der.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. var inherits = require('inherits');
  2. var asn1 = require('../../asn1');
  3. var base = asn1.base;
  4. var bignum = asn1.bignum;
  5. // Import DER constants
  6. var der = asn1.constants.der;
  7. function DERDecoder(entity) {
  8. this.enc = 'der';
  9. this.name = entity.name;
  10. this.entity = entity;
  11. // Construct base tree
  12. this.tree = new DERNode();
  13. this.tree._init(entity.body);
  14. };
  15. module.exports = DERDecoder;
  16. DERDecoder.prototype.decode = function decode(data, options) {
  17. if (!(data instanceof base.DecoderBuffer))
  18. data = new base.DecoderBuffer(data, options);
  19. return this.tree._decode(data, options);
  20. };
  21. // Tree methods
  22. function DERNode(parent) {
  23. base.Node.call(this, 'der', parent);
  24. }
  25. inherits(DERNode, base.Node);
  26. DERNode.prototype._peekTag = function peekTag(buffer, tag, any) {
  27. if (buffer.isEmpty())
  28. return false;
  29. var state = buffer.save();
  30. var decodedTag = derDecodeTag(buffer, 'Failed to peek tag: "' + tag + '"');
  31. if (buffer.isError(decodedTag))
  32. return decodedTag;
  33. buffer.restore(state);
  34. return decodedTag.tag === tag || decodedTag.tagStr === tag ||
  35. (decodedTag.tagStr + 'of') === tag || any;
  36. };
  37. DERNode.prototype._decodeTag = function decodeTag(buffer, tag, any) {
  38. var decodedTag = derDecodeTag(buffer,
  39. 'Failed to decode tag of "' + tag + '"');
  40. if (buffer.isError(decodedTag))
  41. return decodedTag;
  42. var len = derDecodeLen(buffer,
  43. decodedTag.primitive,
  44. 'Failed to get length of "' + tag + '"');
  45. // Failure
  46. if (buffer.isError(len))
  47. return len;
  48. if (!any &&
  49. decodedTag.tag !== tag &&
  50. decodedTag.tagStr !== tag &&
  51. decodedTag.tagStr + 'of' !== tag) {
  52. return buffer.error('Failed to match tag: "' + tag + '"');
  53. }
  54. if (decodedTag.primitive || len !== null)
  55. return buffer.skip(len, 'Failed to match body of: "' + tag + '"');
  56. // Indefinite length... find END tag
  57. var state = buffer.save();
  58. var res = this._skipUntilEnd(
  59. buffer,
  60. 'Failed to skip indefinite length body: "' + this.tag + '"');
  61. if (buffer.isError(res))
  62. return res;
  63. len = buffer.offset - state.offset;
  64. buffer.restore(state);
  65. return buffer.skip(len, 'Failed to match body of: "' + tag + '"');
  66. };
  67. DERNode.prototype._skipUntilEnd = function skipUntilEnd(buffer, fail) {
  68. while (true) {
  69. var tag = derDecodeTag(buffer, fail);
  70. if (buffer.isError(tag))
  71. return tag;
  72. var len = derDecodeLen(buffer, tag.primitive, fail);
  73. if (buffer.isError(len))
  74. return len;
  75. var res;
  76. if (tag.primitive || len !== null)
  77. res = buffer.skip(len)
  78. else
  79. res = this._skipUntilEnd(buffer, fail);
  80. // Failure
  81. if (buffer.isError(res))
  82. return res;
  83. if (tag.tagStr === 'end')
  84. break;
  85. }
  86. };
  87. DERNode.prototype._decodeList = function decodeList(buffer, tag, decoder,
  88. options) {
  89. var result = [];
  90. while (!buffer.isEmpty()) {
  91. var possibleEnd = this._peekTag(buffer, 'end');
  92. if (buffer.isError(possibleEnd))
  93. return possibleEnd;
  94. var res = decoder.decode(buffer, 'der', options);
  95. if (buffer.isError(res) && possibleEnd)
  96. break;
  97. result.push(res);
  98. }
  99. return result;
  100. };
  101. DERNode.prototype._decodeStr = function decodeStr(buffer, tag) {
  102. if (tag === 'bitstr') {
  103. var unused = buffer.readUInt8();
  104. if (buffer.isError(unused))
  105. return unused;
  106. return { unused: unused, data: buffer.raw() };
  107. } else if (tag === 'bmpstr') {
  108. var raw = buffer.raw();
  109. if (raw.length % 2 === 1)
  110. return buffer.error('Decoding of string type: bmpstr length mismatch');
  111. var str = '';
  112. for (var i = 0; i < raw.length / 2; i++) {
  113. str += String.fromCharCode(raw.readUInt16BE(i * 2));
  114. }
  115. return str;
  116. } else if (tag === 'numstr') {
  117. var numstr = buffer.raw().toString('ascii');
  118. if (!this._isNumstr(numstr)) {
  119. return buffer.error('Decoding of string type: ' +
  120. 'numstr unsupported characters');
  121. }
  122. return numstr;
  123. } else if (tag === 'octstr') {
  124. return buffer.raw();
  125. } else if (tag === 'objDesc') {
  126. return buffer.raw();
  127. } else if (tag === 'printstr') {
  128. var printstr = buffer.raw().toString('ascii');
  129. if (!this._isPrintstr(printstr)) {
  130. return buffer.error('Decoding of string type: ' +
  131. 'printstr unsupported characters');
  132. }
  133. return printstr;
  134. } else if (/str$/.test(tag)) {
  135. return buffer.raw().toString();
  136. } else {
  137. return buffer.error('Decoding of string type: ' + tag + ' unsupported');
  138. }
  139. };
  140. DERNode.prototype._decodeObjid = function decodeObjid(buffer, values, relative) {
  141. var result;
  142. var identifiers = [];
  143. var ident = 0;
  144. while (!buffer.isEmpty()) {
  145. var subident = buffer.readUInt8();
  146. ident <<= 7;
  147. ident |= subident & 0x7f;
  148. if ((subident & 0x80) === 0) {
  149. identifiers.push(ident);
  150. ident = 0;
  151. }
  152. }
  153. if (subident & 0x80)
  154. identifiers.push(ident);
  155. var first = (identifiers[0] / 40) | 0;
  156. var second = identifiers[0] % 40;
  157. if (relative)
  158. result = identifiers;
  159. else
  160. result = [first, second].concat(identifiers.slice(1));
  161. if (values) {
  162. var tmp = values[result.join(' ')];
  163. if (tmp === undefined)
  164. tmp = values[result.join('.')];
  165. if (tmp !== undefined)
  166. result = tmp;
  167. }
  168. return result;
  169. };
  170. DERNode.prototype._decodeTime = function decodeTime(buffer, tag) {
  171. var str = buffer.raw().toString();
  172. if (tag === 'gentime') {
  173. var year = str.slice(0, 4) | 0;
  174. var mon = str.slice(4, 6) | 0;
  175. var day = str.slice(6, 8) | 0;
  176. var hour = str.slice(8, 10) | 0;
  177. var min = str.slice(10, 12) | 0;
  178. var sec = str.slice(12, 14) | 0;
  179. } else if (tag === 'utctime') {
  180. var year = str.slice(0, 2) | 0;
  181. var mon = str.slice(2, 4) | 0;
  182. var day = str.slice(4, 6) | 0;
  183. var hour = str.slice(6, 8) | 0;
  184. var min = str.slice(8, 10) | 0;
  185. var sec = str.slice(10, 12) | 0;
  186. if (year < 70)
  187. year = 2000 + year;
  188. else
  189. year = 1900 + year;
  190. } else {
  191. return buffer.error('Decoding ' + tag + ' time is not supported yet');
  192. }
  193. return Date.UTC(year, mon - 1, day, hour, min, sec, 0);
  194. };
  195. DERNode.prototype._decodeNull = function decodeNull(buffer) {
  196. return null;
  197. };
  198. DERNode.prototype._decodeBool = function decodeBool(buffer) {
  199. var res = buffer.readUInt8();
  200. if (buffer.isError(res))
  201. return res;
  202. else
  203. return res !== 0;
  204. };
  205. DERNode.prototype._decodeInt = function decodeInt(buffer, values) {
  206. // Bigint, return as it is (assume big endian)
  207. var raw = buffer.raw();
  208. var res = new bignum(raw);
  209. if (values)
  210. res = values[res.toString(10)] || res;
  211. return res;
  212. };
  213. DERNode.prototype._use = function use(entity, obj) {
  214. if (typeof entity === 'function')
  215. entity = entity(obj);
  216. return entity._getDecoder('der').tree;
  217. };
  218. // Utility methods
  219. function derDecodeTag(buf, fail) {
  220. var tag = buf.readUInt8(fail);
  221. if (buf.isError(tag))
  222. return tag;
  223. var cls = der.tagClass[tag >> 6];
  224. var primitive = (tag & 0x20) === 0;
  225. // Multi-octet tag - load
  226. if ((tag & 0x1f) === 0x1f) {
  227. var oct = tag;
  228. tag = 0;
  229. while ((oct & 0x80) === 0x80) {
  230. oct = buf.readUInt8(fail);
  231. if (buf.isError(oct))
  232. return oct;
  233. tag <<= 7;
  234. tag |= oct & 0x7f;
  235. }
  236. } else {
  237. tag &= 0x1f;
  238. }
  239. var tagStr = der.tag[tag];
  240. return {
  241. cls: cls,
  242. primitive: primitive,
  243. tag: tag,
  244. tagStr: tagStr
  245. };
  246. }
  247. function derDecodeLen(buf, primitive, fail) {
  248. var len = buf.readUInt8(fail);
  249. if (buf.isError(len))
  250. return len;
  251. // Indefinite form
  252. if (!primitive && len === 0x80)
  253. return null;
  254. // Definite form
  255. if ((len & 0x80) === 0) {
  256. // Short form
  257. return len;
  258. }
  259. // Long form
  260. var num = len & 0x7f;
  261. if (num > 4)
  262. return buf.error('length octect is too long');
  263. len = 0;
  264. for (var i = 0; i < num; i++) {
  265. len <<= 8;
  266. var j = buf.readUInt8(fail);
  267. if (buf.isError(j))
  268. return j;
  269. len |= j;
  270. }
  271. return len;
  272. }