der.js 7.9 KB

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