| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 | var inherits = require('inherits');var asn1 = require('../../asn1');var base = asn1.base;var bignum = asn1.bignum;// Import DER constantsvar der = asn1.constants.der;function DERDecoder(entity) {  this.enc = 'der';  this.name = entity.name;  this.entity = entity;  // Construct base tree  this.tree = new DERNode();  this.tree._init(entity.body);};module.exports = DERDecoder;DERDecoder.prototype.decode = function decode(data, options) {  if (!(data instanceof base.DecoderBuffer))    data = new base.DecoderBuffer(data, options);  return this.tree._decode(data, options);};// Tree methodsfunction DERNode(parent) {  base.Node.call(this, 'der', parent);}inherits(DERNode, base.Node);DERNode.prototype._peekTag = function peekTag(buffer, tag, any) {  if (buffer.isEmpty())    return false;  var state = buffer.save();  var decodedTag = derDecodeTag(buffer, 'Failed to peek tag: "' + tag + '"');  if (buffer.isError(decodedTag))    return decodedTag;  buffer.restore(state);  return decodedTag.tag === tag || decodedTag.tagStr === tag ||    (decodedTag.tagStr + 'of') === tag || any;};DERNode.prototype._decodeTag = function decodeTag(buffer, tag, any) {  var decodedTag = derDecodeTag(buffer,                                'Failed to decode tag of "' + tag + '"');  if (buffer.isError(decodedTag))    return decodedTag;  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, 'Failed to match body of: "' + tag + '"');  // Indefinite length... find END tag  var state = buffer.save();  var res = this._skipUntilEnd(      buffer,      'Failed to skip indefinite length body: "' + this.tag + '"');  if (buffer.isError(res))    return res;  len = buffer.offset - state.offset;  buffer.restore(state);  return buffer.skip(len, 'Failed to match body of: "' + tag + '"');};DERNode.prototype._skipUntilEnd = function skipUntilEnd(buffer, fail) {  while (true) {    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)      res = buffer.skip(len)    else      res = this._skipUntilEnd(buffer, fail);    // Failure    if (buffer.isError(res))      return res;    if (tag.tagStr === 'end')      break;  }};DERNode.prototype._decodeList = function decodeList(buffer, tag, decoder,                                                    options) {  var result = [];  while (!buffer.isEmpty()) {    var possibleEnd = this._peekTag(buffer, 'end');    if (buffer.isError(possibleEnd))      return possibleEnd;    var res = decoder.decode(buffer, 'der', options);    if (buffer.isError(res) && possibleEnd)      break;    result.push(res);  }  return result;};DERNode.prototype._decodeStr = function decodeStr(buffer, tag) {  if (tag === 'bitstr') {    var unused = buffer.readUInt8();    if (buffer.isError(unused))      return unused;    return { unused: unused, data: buffer.raw() };  } else if (tag === 'bmpstr') {    var raw = buffer.raw();    if (raw.length % 2 === 1)      return buffer.error('Decoding of string type: bmpstr length mismatch');    var str = '';    for (var i = 0; i < raw.length / 2; i++) {      str += String.fromCharCode(raw.readUInt16BE(i * 2));    }    return str;  } else if (tag === 'numstr') {    var numstr = buffer.raw().toString('ascii');    if (!this._isNumstr(numstr)) {      return buffer.error('Decoding of string type: ' +                          'numstr unsupported characters');    }    return numstr;  } else if (tag === 'octstr') {    return buffer.raw();  } else if (tag === 'objDesc') {    return buffer.raw();  } else if (tag === 'printstr') {    var printstr = buffer.raw().toString('ascii');    if (!this._isPrintstr(printstr)) {      return buffer.error('Decoding of string type: ' +                          'printstr unsupported characters');    }    return printstr;  } else if (/str$/.test(tag)) {    return buffer.raw().toString();  } else {    return buffer.error('Decoding of string type: ' + tag + ' unsupported');  }};DERNode.prototype._decodeObjid = function decodeObjid(buffer, values, relative) {  var result;  var identifiers = [];  var ident = 0;  while (!buffer.isEmpty()) {    var subident = buffer.readUInt8();    ident <<= 7;    ident |= subident & 0x7f;    if ((subident & 0x80) === 0) {      identifiers.push(ident);      ident = 0;    }  }  if (subident & 0x80)    identifiers.push(ident);  var first = (identifiers[0] / 40) | 0;  var second = identifiers[0] % 40;  if (relative)    result = identifiers;  else    result = [first, second].concat(identifiers.slice(1));  if (values) {    var tmp = values[result.join(' ')];    if (tmp === undefined)      tmp = values[result.join('.')];    if (tmp !== undefined)      result = tmp;  }  return result;};DERNode.prototype._decodeTime = function decodeTime(buffer, tag) {  var str = buffer.raw().toString();  if (tag === 'gentime') {    var year = str.slice(0, 4) | 0;    var mon = str.slice(4, 6) | 0;    var day = str.slice(6, 8) | 0;    var hour = str.slice(8, 10) | 0;    var min = str.slice(10, 12) | 0;    var sec = str.slice(12, 14) | 0;  } else if (tag === 'utctime') {    var year = str.slice(0, 2) | 0;    var mon = str.slice(2, 4) | 0;    var day = str.slice(4, 6) | 0;    var hour = str.slice(6, 8) | 0;    var min = str.slice(8, 10) | 0;    var sec = str.slice(10, 12) | 0;    if (year < 70)      year = 2000 + year;    else      year = 1900 + year;  } else {    return buffer.error('Decoding ' + tag + ' time is not supported yet');  }  return Date.UTC(year, mon - 1, day, hour, min, sec, 0);};DERNode.prototype._decodeNull = function decodeNull(buffer) {  return null;};DERNode.prototype._decodeBool = function decodeBool(buffer) {  var res = buffer.readUInt8();  if (buffer.isError(res))    return res;  else    return res !== 0;};DERNode.prototype._decodeInt = function decodeInt(buffer, values) {  // Bigint, return as it is (assume big endian)  var raw = buffer.raw();  var res = new bignum(raw);  if (values)    res = values[res.toString(10)] || res;  return res;};DERNode.prototype._use = function use(entity, obj) {  if (typeof entity === 'function')    entity = entity(obj);  return entity._getDecoder('der').tree;};// Utility methodsfunction derDecodeTag(buf, fail) {  var tag = buf.readUInt8(fail);  if (buf.isError(tag))    return tag;  var cls = der.tagClass[tag >> 6];  var primitive = (tag & 0x20) === 0;  // Multi-octet tag - load  if ((tag & 0x1f) === 0x1f) {    var oct = tag;    tag = 0;    while ((oct & 0x80) === 0x80) {      oct = buf.readUInt8(fail);      if (buf.isError(oct))        return oct;      tag <<= 7;      tag |= oct & 0x7f;    }  } else {    tag &= 0x1f;  }  var tagStr = der.tag[tag];  return {    cls: cls,    primitive: primitive,    tag: tag,    tagStr: tagStr  };}function derDecodeLen(buf, primitive, fail) {  var len = buf.readUInt8(fail);  if (buf.isError(len))    return len;  // Indefinite form  if (!primitive && len === 0x80)    return null;  // Definite form  if ((len & 0x80) === 0) {    // Short form    return len;  }  // Long form  var num = len & 0x7f;  if (num > 4)    return buf.error('length octect is too long');  len = 0;  for (var i = 0; i < num; i++) {    len <<= 8;    var j = buf.readUInt8(fail);    if (buf.isError(j))      return j;    len |= j;  }  return len;}
 |