Comparing version 0.1.5 to 0.2.0
@@ -31,14 +31,14 @@ var asn1 = require('../asn1'); | ||
Entity.prototype.decode = function decode(data, enc) { | ||
Entity.prototype.decode = function decode(data, enc, options) { | ||
// Lazily create decoder | ||
if (!this.decoders.hasOwnProperty(enc)) | ||
this.decoders[enc] = this._createNamed(asn1.decoders[enc]); | ||
return this.decoders[enc].decode(data); | ||
return this.decoders[enc].decode(data, options); | ||
}; | ||
Entity.prototype.encode = function encode(data, enc, /* internal */ path) { | ||
Entity.prototype.encode = function encode(data, enc, /* internal */ reporter) { | ||
// Lazily create encoder | ||
if (!this.encoders.hasOwnProperty(enc)) | ||
this.encoders[enc] = this._createNamed(asn1.encoders[enc]); | ||
return this.encoders[enc].encode(data, path); | ||
return this.encoders[enc].encode(data, reporter); | ||
}; |
var assert = require('assert'); | ||
var util = require('util'); | ||
var Reporter = require('../base').Reporter; | ||
var Buffer = require('buffer').Buffer; | ||
function DecoderBuffer(base) { | ||
assert(Buffer.isBuffer(base)); | ||
function DecoderBuffer(base, options) { | ||
Reporter.call(this, options); | ||
if (!Buffer.isBuffer(base)) { | ||
this.error('Input not Buffer'); | ||
return; | ||
} | ||
@@ -11,2 +17,3 @@ this.base = base; | ||
} | ||
util.inherits(DecoderBuffer, Reporter); | ||
exports.DecoderBuffer = DecoderBuffer; | ||
@@ -33,10 +40,18 @@ | ||
DecoderBuffer.prototype.readUInt8 = function readUInt8() { | ||
assert(this.offset + 1 <= this.length); | ||
return this.base.readUInt8(this.offset++, true); | ||
DecoderBuffer.prototype.readUInt8 = function readUInt8(fail) { | ||
if (this.offset + 1 <= this.length) | ||
return this.base.readUInt8(this.offset++, true); | ||
else | ||
return this.error(fail || 'DecoderBuffer overrun'); | ||
} | ||
DecoderBuffer.prototype.skip = function skip(bytes) { | ||
assert(this.offset + bytes <= this.length); | ||
DecoderBuffer.prototype.skip = function skip(bytes, fail) { | ||
if (!(this.offset + bytes <= this.length)) | ||
return this.error(fail || 'DecoderBuffer overrun'); | ||
var res = new DecoderBuffer(this.base); | ||
// Share reporter state | ||
res._reporterState = this._reporterState; | ||
res.offset = this.offset; | ||
@@ -52,3 +67,3 @@ res.length = this.offset + bytes; | ||
function EncoderBuffer(value) { | ||
function EncoderBuffer(value, reporter) { | ||
if (Array.isArray(value)) { | ||
@@ -63,3 +78,4 @@ this.length = 0; | ||
} else if (typeof value === 'number') { | ||
assert(0 <= value && value <= 0xff, 'non-byte EncoderBuffer value'); | ||
if (!(0 <= value && value <= 0xff)) | ||
return reporter.error('non-byte EncoderBuffer value'); | ||
this.value = value; | ||
@@ -74,3 +90,3 @@ this.length = 1; | ||
} else { | ||
assert(0, 'Unsupported type: ' + typeof value); | ||
return reporter.error('Unsupporter type: ' + typeof value); | ||
} | ||
@@ -77,0 +93,0 @@ } |
var base = exports; | ||
base.EncoderError = require('./error').EncoderError; | ||
base.Reporter = require('./reporter').Reporter; | ||
base.DecoderBuffer = require('./buffer').DecoderBuffer; | ||
base.EncoderBuffer = require('./buffer').EncoderBuffer; | ||
base.Node = require('./node'); |
var assert = require('assert'); | ||
var Reporter = require('../base').Reporter; | ||
var EncoderBuffer = require('../base').EncoderBuffer; | ||
var EncoderError = require('../base').EncoderError; | ||
@@ -240,3 +240,3 @@ // Supported tags | ||
Node.prototype._decode = function decode(input, obj) { | ||
Node.prototype._decode = function decode(input) { | ||
var state = this._baseState; | ||
@@ -246,3 +246,3 @@ | ||
if (state.parent === null) | ||
return state.children[0]._decode(input); | ||
return input.wrapResult(state.children[0]._decode(input)); | ||
@@ -252,2 +252,6 @@ var result = state['default']; | ||
var prevKey; | ||
if (state.key !== null) | ||
prevKey = input.enterKey(state.key); | ||
// Check if tag is there | ||
@@ -261,18 +265,23 @@ if (state.optional) { | ||
); | ||
if (input.isError(present)) | ||
return present; | ||
} | ||
// Push object on stack | ||
if (state.obj && present) { | ||
var prevObj = obj; | ||
obj = {}; | ||
} | ||
var prevObj; | ||
if (state.obj && present) | ||
prevObj = input.enterObject(); | ||
if (present) { | ||
// Unwrap explicit values | ||
if (state.explicit !== null) | ||
input = this._decodeTag(input, state.explicit); | ||
if (state.explicit !== null) { | ||
var explicit = this._decodeTag(input, state.explicit); | ||
if (input.isError(explicit)) | ||
return explicit; | ||
input = explicit; | ||
} | ||
// Unwrap implicit and normal values | ||
if (state.use === null && !state.any && state.choice === null) { | ||
input = this._decodeTag( | ||
var body = this._decodeTag( | ||
input, | ||
@@ -282,2 +291,5 @@ state.implicit !== null ? state.implicit : state.tag, | ||
); | ||
if (input.isError(body)) | ||
return body; | ||
input = body; | ||
} | ||
@@ -291,9 +303,15 @@ | ||
else | ||
result = this._decodeChoice(input, obj); | ||
result = this._decodeChoice(input); | ||
if (input.isError(result)) | ||
return result; | ||
// Decode children | ||
if (!state.any && state.choice === null && state.children !== null) { | ||
state.children.forEach(function decodeChildren(child) { | ||
child._decode(input, obj); | ||
var fail = state.children.some(function decodeChildren(child) { | ||
// NOTE: We are ignoring errors here, to let parser continue with other | ||
// parts of encoded data | ||
child._decode(input); | ||
}); | ||
if (fail) | ||
return err; | ||
} | ||
@@ -303,10 +321,8 @@ } | ||
// Pop object | ||
if (state.obj && present) { | ||
result = obj; | ||
obj = prevObj; | ||
} | ||
if (state.obj && present) | ||
result = input.leaveObject(prevObj); | ||
// Set key | ||
if (state.key !== null) | ||
obj[state.key] = result; | ||
input.leaveKey(prevKey, state.key, result); | ||
@@ -340,3 +356,3 @@ return result; | ||
else | ||
assert(false, 'unknown tag: ' + tag); | ||
return input.error('unknown tag: ' + tag); | ||
@@ -346,3 +362,3 @@ return null; | ||
Node.prototype._decodeChoice = function decodeChoice(input, obj) { | ||
Node.prototype._decodeChoice = function decodeChoice(input) { | ||
var state = this._baseState; | ||
@@ -356,3 +372,7 @@ var result = null; | ||
try { | ||
result = { type: key, value: node._decode(input, obj) }; | ||
var value = node._decode(input); | ||
if (input.isError(value)) | ||
return false; | ||
result = { type: key, value: value }; | ||
match = true; | ||
@@ -366,3 +386,5 @@ } catch (e) { | ||
assert(match, 'Choice not matched'); | ||
if (!match) | ||
return input.error('Choice not matched'); | ||
return result; | ||
@@ -375,3 +397,7 @@ }; | ||
Node.prototype._encode = function encode(data, path) { | ||
Node.prototype._createEncoderBuffer = function createEncoderBuffer(data) { | ||
return new EncoderBuffer(data, this.reporter); | ||
}; | ||
Node.prototype._encode = function encode(data, reporter) { | ||
var state = this._baseState; | ||
@@ -381,3 +407,3 @@ | ||
if (state.parent === null) | ||
return state.children[0]._encode(data, path || ''); | ||
return state.children[0]._encode(data, reporter || new Reporter()); | ||
@@ -387,2 +413,5 @@ var result = null; | ||
// Set reporter to share it with a child class | ||
this.reporter = reporter; | ||
// Check if data is there | ||
@@ -396,2 +425,5 @@ if (state.optional && data === undefined) { | ||
// For error reporting | ||
var prevKey; | ||
// Encode children first | ||
@@ -402,18 +434,16 @@ var content = null; | ||
// Anything that was given is translated to buffer | ||
result = new EncoderBuffer(data); | ||
result = this._createEncoderBuffer(data); | ||
} else if (state.children) { | ||
content = state.children.map(function(child) { | ||
assert(child._baseState.key !== null, 'Child should have a key'); | ||
if (child._baseState.key === null) | ||
return reporter.error('Child should have a key'); | ||
var prevKey = reporter.enterKey(child._baseState.key); | ||
// Maintain path for error reporting purposes | ||
var newpath = path ? path + '.' + child._baseState.key : | ||
child._baseState.key; | ||
try { | ||
return child._encode(data[child._baseState.key], newpath); | ||
} catch (e) { | ||
if (e instanceof EncoderError) | ||
throw e; | ||
else | ||
throw new EncoderError(newpath, e); | ||
} | ||
if (typeof data !== 'object') | ||
return reporter.error('Child expected, but input is not object'); | ||
var res = child._encode(data[child._baseState.key], reporter); | ||
reporter.leaveKey(prevKey); | ||
return res; | ||
}, this).filter(function(child) { | ||
@@ -423,14 +453,18 @@ return child; | ||
content = new EncoderBuffer(content); | ||
content = this._createEncoderBuffer(content); | ||
} else { | ||
if (state.choice === null) { | ||
if (state.tag === 'seqof' || state.tag === 'setof') { | ||
assert(state.args && state.args.length === 1); | ||
assert(Array.isArray(data), 'seqof/setof, but data is not Array'); | ||
// TODO(indutny): this should be thrown on DSL level | ||
if (!(state.args && state.args.length === 1)) | ||
return reporter.error('Too many args for : ' + state.tag); | ||
content = new EncoderBuffer(data.map(function(item) { | ||
return this._use(state.args[0], item, path); | ||
if (!Array.isArray(data)) | ||
return reporter.error('seqof/setof, but data is not Array'); | ||
content = this._createEncoderBuffer(data.map(function(item) { | ||
return this._use(state.args[0], item); | ||
}, this)); | ||
} else if (state.use !== null) { | ||
result = this._use(state.use, data, path); | ||
result = this._use(state.use, data); | ||
} else { | ||
@@ -441,3 +475,3 @@ content = this._encodePrimitive(state.tag, data); | ||
} else { | ||
result = this._encodeChoice(data); | ||
result = this._encodeChoice(data, reporter); | ||
} | ||
@@ -451,6 +485,8 @@ } | ||
if (tag === null) | ||
assert(state.use !== null, 'Tag could be ommited only for .use()'); | ||
else | ||
if (tag === null) { | ||
if (state.use === null) | ||
reporter.error('Tag could be ommited only for .use()'); | ||
} else { | ||
result = this._encodeComposite(tag, primitive, content); | ||
} | ||
} | ||
@@ -465,7 +501,7 @@ | ||
Node.prototype._encodeChoice = function encodeChoice(data) { | ||
Node.prototype._encodeChoice = function encodeChoice(data, reporter) { | ||
var state = this._baseState; | ||
var node = state.choice[data.type]; | ||
return node._encode(data.value); | ||
return node._encode(data.value, reporter); | ||
}; | ||
@@ -472,0 +508,0 @@ |
@@ -1,2 +0,1 @@ | ||
var assert = require('assert'); | ||
var util = require('util'); | ||
@@ -21,7 +20,7 @@ | ||
DERDecoder.prototype.decode = function decode(data) { | ||
DERDecoder.prototype.decode = function decode(data, options) { | ||
if (!(data instanceof base.DecoderBuffer)) | ||
data = new base.DecoderBuffer(data); | ||
data = new base.DecoderBuffer(data, options); | ||
return this.tree._decode(data); | ||
return this.tree._decode(data, options); | ||
}; | ||
@@ -41,3 +40,6 @@ | ||
var state = buffer.save(); | ||
var decodedTag = derDecodeTag(buffer); | ||
var decodedTag = derDecodeTag(buffer, 'Failed to peek tag: "' + tag + '"'); | ||
if (buffer.isError(decodedTag)) | ||
return decodedTag; | ||
buffer.restore(state); | ||
@@ -49,31 +51,55 @@ | ||
DERNode.prototype._decodeTag = function decodeTag(buffer, tag, any) { | ||
var decodedTag = derDecodeTag(buffer); | ||
var len = derDecodeLen(buffer, decodedTag.primitive); | ||
var decodedTag = derDecodeTag(buffer, | ||
'Failed to decode tag of "' + tag + '"'); | ||
if (buffer.isError(decodedTag)) | ||
return decodedTag; | ||
if (!any) { | ||
assert(decodedTag.tag === tag || | ||
decodedTag.tagStr === tag || | ||
decodedTag.tagStr + 'of' === tag, | ||
'Failed to match tag: ' + tag); | ||
var len = derDecodeLen(buffer, | ||
decodedTag.primitive, | ||
'Failed to get length of "' + tag + '"'); | ||
// Failure | ||
if (buffer.isError(len)) | ||
return len; | ||
if (!any && | ||
decodedTag.tag !== tag && | ||
decodedTag.tagStr !== tag && | ||
decodedTag.tagStr + 'of' !== tag) { | ||
return buffer.error('Failed to match tag: "' + tag + '"'); | ||
} | ||
if (decodedTag.primitive || len !== null) | ||
return buffer.skip(len); | ||
return buffer.skip(len, 'Failed to match body of: "' + tag + '"'); | ||
// Indefinite length... find END tag | ||
var state = buffer.save(); | ||
this._skipUntilEnd(buffer); | ||
var res = this._skipUntilEnd( | ||
buffer, | ||
'Failed to skip indefinite length body: "' + this.tag + '"'); | ||
if (buffer.isError(res)) | ||
return res; | ||
return buffer.restore(state); | ||
}; | ||
DERNode.prototype._skipUntilEnd = function skipUntilEnd(buffer) { | ||
DERNode.prototype._skipUntilEnd = function skipUntilEnd(buffer, fail) { | ||
while (true) { | ||
var tag = derDecodeTag(buffer); | ||
var len = derDecodeLen(buffer, tag.primitive); | ||
var tag = derDecodeTag(buffer, fail); | ||
if (buffer.isError(tag)) | ||
return tag; | ||
var len = derDecodeLen(buffer, tag.primitive, fail); | ||
if (buffer.isError(len)) | ||
return len; | ||
var res; | ||
if (tag.primitive || len !== null) | ||
buffer.skip(len) | ||
res = buffer.skip(len) | ||
else | ||
this._skipUntilEnd(buffer); | ||
res = this._skipUntilEnd(buffer, fail); | ||
// Failure | ||
if (buffer.isError(res)) | ||
return res; | ||
if (tag.tagStr === 'end') | ||
@@ -87,9 +113,10 @@ break; | ||
while (!buffer.isEmpty()) { | ||
try { | ||
var possibleEnd = this._peekTag(buffer, 'end'); | ||
result.push(decoder.decode(buffer, 'der')); | ||
} catch (e) { | ||
if (possibleEnd) | ||
break; | ||
} | ||
var possibleEnd = this._peekTag(buffer, 'end'); | ||
if (buffer.isError(possibleEnd)) | ||
return possibleEnd; | ||
var res = decoder.decode(buffer, 'der'); | ||
if (buffer.isError(res) && possibleEnd) | ||
break; | ||
result.push(res); | ||
} | ||
@@ -105,3 +132,3 @@ return result; | ||
else | ||
assert(0, 'Decoding of string type: ' + tag + ' unsupported'); | ||
return this.error('Decoding of string type: ' + tag + ' unsupported'); | ||
}; | ||
@@ -159,3 +186,3 @@ | ||
} else { | ||
assert(0, 'Decoding ' + tag + ' time is not supported yet'); | ||
return this.error('Decoding ' + tag + ' time is not supported yet'); | ||
} | ||
@@ -171,3 +198,7 @@ | ||
DERNode.prototype._decodeBool = function decodeBool(buffer) { | ||
return buffer.readUInt8() !== 0; | ||
var res = buffer.readUInt8(); | ||
if (buffer.isError(res)) | ||
return res; | ||
else | ||
return res !== 0; | ||
}; | ||
@@ -179,7 +210,10 @@ | ||
res <<= 8; | ||
res |= buffer.readUInt8(); | ||
var i = buffer.readUInt8(); | ||
if (buffer.isError(i)) | ||
return i; | ||
res |= i; | ||
} | ||
if (values) | ||
res = values[res]; | ||
res = values[res] || res; | ||
return res; | ||
@@ -194,4 +228,6 @@ }; | ||
function derDecodeTag(buf) { | ||
var tag = buf.readUInt8(); | ||
function derDecodeTag(buf, fail) { | ||
var tag = buf.readUInt8(fail); | ||
if (buf.isError(tag)) | ||
return tag; | ||
@@ -206,3 +242,6 @@ var cls = der.tagClass[tag >> 6]; | ||
while ((oct & 0x80) === 0x80) { | ||
oct = buf.readUInt8(); | ||
oct = buf.readUInt8(fail); | ||
if (buf.isError(oct)) | ||
return oct; | ||
tag <<= 7; | ||
@@ -224,4 +263,6 @@ tag |= oct & 0x7f; | ||
function derDecodeLen(buf, primitive) { | ||
var len = buf.readUInt8(); | ||
function derDecodeLen(buf, primitive, fail) { | ||
var len = buf.readUInt8(fail); | ||
if (buf.isError(len)) | ||
return len; | ||
@@ -240,7 +281,12 @@ // Indefinite form | ||
var num = len & 0x7f; | ||
assert(num < 4, 'length octect is too long'); | ||
if (num >= 4) | ||
return buf.error('length octect is too long'); | ||
len = 0; | ||
for (var i = 0; i < num; i++) { | ||
len <<= 8; | ||
len |= buf.readUInt8(); | ||
var j = buf.readUInt8(fail); | ||
if (buf.isError(j)) | ||
return j; | ||
len |= j; | ||
} | ||
@@ -247,0 +293,0 @@ |
@@ -1,2 +0,1 @@ | ||
var assert = require('assert'); | ||
var util = require('util'); | ||
@@ -22,4 +21,4 @@ var Buffer = require('buffer').Buffer; | ||
DEREncoder.prototype.encode = function encode(data, path) { | ||
return this.tree._encode(data, path).join(); | ||
DEREncoder.prototype.encode = function encode(data, reporter) { | ||
return this.tree._encode(data, reporter).join(); | ||
}; | ||
@@ -37,3 +36,3 @@ | ||
content) { | ||
var encodedTag = encodeTag(tag, primitive); | ||
var encodedTag = encodeTag(tag, primitive, this.reporter); | ||
@@ -45,3 +44,3 @@ // Short form | ||
header[1] = content.length; | ||
return new base.EncoderBuffer([ header, content ]); | ||
return this._createEncoderBuffer([ header, content ]); | ||
} | ||
@@ -62,3 +61,3 @@ | ||
return new base.EncoderBuffer([ header, content ]); | ||
return this._createEncoderBuffer([ header, content ]); | ||
}; | ||
@@ -68,7 +67,7 @@ | ||
if (tag === 'octstr') | ||
return new base.EncoderBuffer(str); | ||
return this._createEncoderBuffer(str); | ||
else if (tag === 'bitstr') | ||
return new base.EncoderBuffer([ str.unused | 0, str.data ]); | ||
else | ||
assert(0, 'Encoding of string type: ' + tag + ' unsupported'); | ||
return this._createEncoderBuffer([ str.unused | 0, str.data ]); | ||
return this.reporter.error('Encoding of string type: ' + tag + | ||
' unsupported'); | ||
}; | ||
@@ -78,4 +77,6 @@ | ||
if (typeof id === 'string') { | ||
assert(values, 'string objid given, but no values map found'); | ||
assert(values.hasOwnProperty(id), 'objid not found in values map'); | ||
if (!values) | ||
return this.reporter.error('string objid given, but no values map found'); | ||
if (!values.hasOwnProperty(id)) | ||
return this.reporter.error('objid not found in values map'); | ||
id = values[id].split(/\s+/g); | ||
@@ -86,7 +87,10 @@ for (var i = 0; i < id.length; i++) | ||
assert(Array.isArray(id), | ||
'objid() should be either array or string, got: ' + | ||
JSON.stringify(id)); | ||
if (!Array.isArray(id)) { | ||
return this.reporter.error('objid() should be either array or string, ' + | ||
'got: ' + JSON.stringify(id)); | ||
} | ||
if (!relative) { | ||
assert(id[1] < 40, 'Second objid identifier OOB'); | ||
if (id[1] >= 40) | ||
return this.reporter.error('Second objid identifier OOB'); | ||
id.splice(0, 2, id[0] * 40 + id[1]); | ||
@@ -112,3 +116,3 @@ } | ||
return new base.EncoderBuffer(objid); | ||
return this._createEncoderBuffer(objid); | ||
}; | ||
@@ -148,3 +152,3 @@ | ||
} else { | ||
assert(0, 'Encoding ' + tag + ' time is not supported yet'); | ||
this.reporter.error('Encoding ' + tag + ' time is not supported yet'); | ||
} | ||
@@ -156,3 +160,3 @@ | ||
DERNode.prototype._encodeNull = function encodeNull() { | ||
return new base.EncoderBuffer(''); | ||
return this._createEncoderBuffer(''); | ||
}; | ||
@@ -162,5 +166,8 @@ | ||
if (typeof num === 'string') { | ||
assert(values, 'String int or enum given, but no values map'); | ||
assert(values.hasOwnProperty(num), | ||
'Values map doesn\'t contain: ' + JSON.stringify(num)); | ||
if (!values) | ||
return this.reporter.error('String int or enum given, but no values map'); | ||
if (!values.hasOwnProperty(num)) { | ||
return this.reporter.error('Values map doesn\'t contain: ' + | ||
JSON.stringify(num)); | ||
} | ||
num = values[num]; | ||
@@ -170,3 +177,3 @@ } | ||
if (num < 0x100) | ||
return new base.EncoderBuffer(num); | ||
return this._createEncoderBuffer(num); | ||
@@ -183,11 +190,11 @@ var size = 1; | ||
return new base.EncoderBuffer(out); | ||
return this._createEncoderBuffer(out); | ||
}; | ||
DERNode.prototype._encodeBool = function encodeBool(value) { | ||
return new base.EncoderBuffer(value ? 0xff : 0); | ||
return this._createEncoderBuffer(value ? 0xff : 0); | ||
}; | ||
DERNode.prototype._use = function use(encoder, data, path) { | ||
return encoder.encode(data, 'der', path); | ||
DERNode.prototype._use = function use(encoder, data) { | ||
return encoder.encode(data, 'der', this.reporter); | ||
}; | ||
@@ -197,3 +204,3 @@ | ||
function encodeTag(tag, primitive, cls) { | ||
function encodeTag(tag, primitive, cls, reporter) { | ||
var res; | ||
@@ -211,5 +218,6 @@ | ||
else | ||
throw new Error('Unknown tag: ' + tag); | ||
return reporter.error('Unknown tag: ' + tag); | ||
assert(res < 0x1f, 'Multi-octet tag encoding unsupported'); | ||
if (res >= 0x1f) | ||
return reporter.error('Multi-octet tag encoding unsupported'); | ||
@@ -216,0 +224,0 @@ if (!primitive) |
{ | ||
"name": "asn1.js", | ||
"version": "0.1.5", | ||
"version": "0.2.0", | ||
"description": "ASN.1 encoder and decoder", | ||
@@ -5,0 +5,0 @@ "main": "lib/asn1.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
56084
1672