x509.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. // Copyright 2017 Joyent, Inc.
  2. module.exports = {
  3. read: read,
  4. verify: verify,
  5. sign: sign,
  6. signAsync: signAsync,
  7. write: write
  8. };
  9. var assert = require('assert-plus');
  10. var asn1 = require('asn1');
  11. var algs = require('../algs');
  12. var utils = require('../utils');
  13. var Key = require('../key');
  14. var PrivateKey = require('../private-key');
  15. var pem = require('./pem');
  16. var Identity = require('../identity');
  17. var Signature = require('../signature');
  18. var Certificate = require('../certificate');
  19. var pkcs8 = require('./pkcs8');
  20. /*
  21. * This file is based on RFC5280 (X.509).
  22. */
  23. /* Helper to read in a single mpint */
  24. function readMPInt(der, nm) {
  25. assert.strictEqual(der.peek(), asn1.Ber.Integer,
  26. nm + ' is not an Integer');
  27. return (utils.mpNormalize(der.readString(asn1.Ber.Integer, true)));
  28. }
  29. function verify(cert, key) {
  30. var sig = cert.signatures.x509;
  31. assert.object(sig, 'x509 signature');
  32. var algParts = sig.algo.split('-');
  33. if (algParts[0] !== key.type)
  34. return (false);
  35. var blob = sig.cache;
  36. if (blob === undefined) {
  37. var der = new asn1.BerWriter();
  38. writeTBSCert(cert, der);
  39. blob = der.buffer;
  40. }
  41. var verifier = key.createVerify(algParts[1]);
  42. verifier.write(blob);
  43. return (verifier.verify(sig.signature));
  44. }
  45. function Local(i) {
  46. return (asn1.Ber.Context | asn1.Ber.Constructor | i);
  47. }
  48. function Context(i) {
  49. return (asn1.Ber.Context | i);
  50. }
  51. var SIGN_ALGS = {
  52. 'rsa-md5': '1.2.840.113549.1.1.4',
  53. 'rsa-sha1': '1.2.840.113549.1.1.5',
  54. 'rsa-sha256': '1.2.840.113549.1.1.11',
  55. 'rsa-sha384': '1.2.840.113549.1.1.12',
  56. 'rsa-sha512': '1.2.840.113549.1.1.13',
  57. 'dsa-sha1': '1.2.840.10040.4.3',
  58. 'dsa-sha256': '2.16.840.1.101.3.4.3.2',
  59. 'ecdsa-sha1': '1.2.840.10045.4.1',
  60. 'ecdsa-sha256': '1.2.840.10045.4.3.2',
  61. 'ecdsa-sha384': '1.2.840.10045.4.3.3',
  62. 'ecdsa-sha512': '1.2.840.10045.4.3.4'
  63. };
  64. Object.keys(SIGN_ALGS).forEach(function (k) {
  65. SIGN_ALGS[SIGN_ALGS[k]] = k;
  66. });
  67. SIGN_ALGS['1.3.14.3.2.3'] = 'rsa-md5';
  68. SIGN_ALGS['1.3.14.3.2.29'] = 'rsa-sha1';
  69. var EXTS = {
  70. 'issuerKeyId': '2.5.29.35',
  71. 'altName': '2.5.29.17',
  72. 'basicConstraints': '2.5.29.19',
  73. 'keyUsage': '2.5.29.15',
  74. 'extKeyUsage': '2.5.29.37'
  75. };
  76. function read(buf, options) {
  77. if (typeof (buf) === 'string') {
  78. buf = new Buffer(buf, 'binary');
  79. }
  80. assert.buffer(buf, 'buf');
  81. var der = new asn1.BerReader(buf);
  82. der.readSequence();
  83. if (Math.abs(der.length - der.remain) > 1) {
  84. throw (new Error('DER sequence does not contain whole byte ' +
  85. 'stream'));
  86. }
  87. var tbsStart = der.offset;
  88. der.readSequence();
  89. var sigOffset = der.offset + der.length;
  90. var tbsEnd = sigOffset;
  91. if (der.peek() === Local(0)) {
  92. der.readSequence(Local(0));
  93. var version = der.readInt();
  94. assert.ok(version <= 3,
  95. 'only x.509 versions up to v3 supported');
  96. }
  97. var cert = {};
  98. cert.signatures = {};
  99. var sig = (cert.signatures.x509 = {});
  100. sig.extras = {};
  101. cert.serial = readMPInt(der, 'serial');
  102. der.readSequence();
  103. var after = der.offset + der.length;
  104. var certAlgOid = der.readOID();
  105. var certAlg = SIGN_ALGS[certAlgOid];
  106. if (certAlg === undefined)
  107. throw (new Error('unknown signature algorithm ' + certAlgOid));
  108. der._offset = after;
  109. cert.issuer = Identity.parseAsn1(der);
  110. der.readSequence();
  111. cert.validFrom = readDate(der);
  112. cert.validUntil = readDate(der);
  113. cert.subjects = [Identity.parseAsn1(der)];
  114. der.readSequence();
  115. after = der.offset + der.length;
  116. cert.subjectKey = pkcs8.readPkcs8(undefined, 'public', der);
  117. der._offset = after;
  118. /* issuerUniqueID */
  119. if (der.peek() === Local(1)) {
  120. der.readSequence(Local(1));
  121. sig.extras.issuerUniqueID =
  122. buf.slice(der.offset, der.offset + der.length);
  123. der._offset += der.length;
  124. }
  125. /* subjectUniqueID */
  126. if (der.peek() === Local(2)) {
  127. der.readSequence(Local(2));
  128. sig.extras.subjectUniqueID =
  129. buf.slice(der.offset, der.offset + der.length);
  130. der._offset += der.length;
  131. }
  132. /* extensions */
  133. if (der.peek() === Local(3)) {
  134. der.readSequence(Local(3));
  135. var extEnd = der.offset + der.length;
  136. der.readSequence();
  137. while (der.offset < extEnd)
  138. readExtension(cert, buf, der);
  139. assert.strictEqual(der.offset, extEnd);
  140. }
  141. assert.strictEqual(der.offset, sigOffset);
  142. der.readSequence();
  143. after = der.offset + der.length;
  144. var sigAlgOid = der.readOID();
  145. var sigAlg = SIGN_ALGS[sigAlgOid];
  146. if (sigAlg === undefined)
  147. throw (new Error('unknown signature algorithm ' + sigAlgOid));
  148. der._offset = after;
  149. var sigData = der.readString(asn1.Ber.BitString, true);
  150. if (sigData[0] === 0)
  151. sigData = sigData.slice(1);
  152. var algParts = sigAlg.split('-');
  153. sig.signature = Signature.parse(sigData, algParts[0], 'asn1');
  154. sig.signature.hashAlgorithm = algParts[1];
  155. sig.algo = sigAlg;
  156. sig.cache = buf.slice(tbsStart, tbsEnd);
  157. return (new Certificate(cert));
  158. }
  159. function readDate(der) {
  160. if (der.peek() === asn1.Ber.UTCTime) {
  161. return (utcTimeToDate(der.readString(asn1.Ber.UTCTime)));
  162. } else if (der.peek() === asn1.Ber.GeneralizedTime) {
  163. return (gTimeToDate(der.readString(asn1.Ber.GeneralizedTime)));
  164. } else {
  165. throw (new Error('Unsupported date format'));
  166. }
  167. }
  168. /* RFC5280, section 4.2.1.6 (GeneralName type) */
  169. var ALTNAME = {
  170. OtherName: Local(0),
  171. RFC822Name: Context(1),
  172. DNSName: Context(2),
  173. X400Address: Local(3),
  174. DirectoryName: Local(4),
  175. EDIPartyName: Local(5),
  176. URI: Context(6),
  177. IPAddress: Context(7),
  178. OID: Context(8)
  179. };
  180. /* RFC5280, section 4.2.1.12 (KeyPurposeId) */
  181. var EXTPURPOSE = {
  182. 'serverAuth': '1.3.6.1.5.5.7.3.1',
  183. 'clientAuth': '1.3.6.1.5.5.7.3.2',
  184. 'codeSigning': '1.3.6.1.5.5.7.3.3',
  185. /* See https://github.com/joyent/oid-docs/blob/master/root.md */
  186. 'joyentDocker': '1.3.6.1.4.1.38678.1.4.1',
  187. 'joyentCmon': '1.3.6.1.4.1.38678.1.4.2'
  188. };
  189. var EXTPURPOSE_REV = {};
  190. Object.keys(EXTPURPOSE).forEach(function (k) {
  191. EXTPURPOSE_REV[EXTPURPOSE[k]] = k;
  192. });
  193. var KEYUSEBITS = [
  194. 'signature', 'identity', 'keyEncryption',
  195. 'encryption', 'keyAgreement', 'ca', 'crl'
  196. ];
  197. function readExtension(cert, buf, der) {
  198. der.readSequence();
  199. var after = der.offset + der.length;
  200. var extId = der.readOID();
  201. var id;
  202. var sig = cert.signatures.x509;
  203. sig.extras.exts = [];
  204. var critical;
  205. if (der.peek() === asn1.Ber.Boolean)
  206. critical = der.readBoolean();
  207. switch (extId) {
  208. case (EXTS.basicConstraints):
  209. der.readSequence(asn1.Ber.OctetString);
  210. der.readSequence();
  211. var bcEnd = der.offset + der.length;
  212. var ca = false;
  213. if (der.peek() === asn1.Ber.Boolean)
  214. ca = der.readBoolean();
  215. if (cert.purposes === undefined)
  216. cert.purposes = [];
  217. if (ca === true)
  218. cert.purposes.push('ca');
  219. var bc = { oid: extId, critical: critical };
  220. if (der.offset < bcEnd && der.peek() === asn1.Ber.Integer)
  221. bc.pathLen = der.readInt();
  222. sig.extras.exts.push(bc);
  223. break;
  224. case (EXTS.extKeyUsage):
  225. der.readSequence(asn1.Ber.OctetString);
  226. der.readSequence();
  227. if (cert.purposes === undefined)
  228. cert.purposes = [];
  229. var ekEnd = der.offset + der.length;
  230. while (der.offset < ekEnd) {
  231. var oid = der.readOID();
  232. cert.purposes.push(EXTPURPOSE_REV[oid] || oid);
  233. }
  234. /*
  235. * This is a bit of a hack: in the case where we have a cert
  236. * that's only allowed to do serverAuth or clientAuth (and not
  237. * the other), we want to make sure all our Subjects are of
  238. * the right type. But we already parsed our Subjects and
  239. * decided if they were hosts or users earlier (since it appears
  240. * first in the cert).
  241. *
  242. * So we go through and mutate them into the right kind here if
  243. * it doesn't match. This might not be hugely beneficial, as it
  244. * seems that single-purpose certs are not often seen in the
  245. * wild.
  246. */
  247. if (cert.purposes.indexOf('serverAuth') !== -1 &&
  248. cert.purposes.indexOf('clientAuth') === -1) {
  249. cert.subjects.forEach(function (ide) {
  250. if (ide.type !== 'host') {
  251. ide.type = 'host';
  252. ide.hostname = ide.uid ||
  253. ide.email ||
  254. ide.components[0].value;
  255. }
  256. });
  257. } else if (cert.purposes.indexOf('clientAuth') !== -1 &&
  258. cert.purposes.indexOf('serverAuth') === -1) {
  259. cert.subjects.forEach(function (ide) {
  260. if (ide.type !== 'user') {
  261. ide.type = 'user';
  262. ide.uid = ide.hostname ||
  263. ide.email ||
  264. ide.components[0].value;
  265. }
  266. });
  267. }
  268. sig.extras.exts.push({ oid: extId, critical: critical });
  269. break;
  270. case (EXTS.keyUsage):
  271. der.readSequence(asn1.Ber.OctetString);
  272. var bits = der.readString(asn1.Ber.BitString, true);
  273. var setBits = readBitField(bits, KEYUSEBITS);
  274. setBits.forEach(function (bit) {
  275. if (cert.purposes === undefined)
  276. cert.purposes = [];
  277. if (cert.purposes.indexOf(bit) === -1)
  278. cert.purposes.push(bit);
  279. });
  280. sig.extras.exts.push({ oid: extId, critical: critical,
  281. bits: bits });
  282. break;
  283. case (EXTS.altName):
  284. der.readSequence(asn1.Ber.OctetString);
  285. der.readSequence();
  286. var aeEnd = der.offset + der.length;
  287. while (der.offset < aeEnd) {
  288. switch (der.peek()) {
  289. case ALTNAME.OtherName:
  290. case ALTNAME.EDIPartyName:
  291. der.readSequence();
  292. der._offset += der.length;
  293. break;
  294. case ALTNAME.OID:
  295. der.readOID(ALTNAME.OID);
  296. break;
  297. case ALTNAME.RFC822Name:
  298. /* RFC822 specifies email addresses */
  299. var email = der.readString(ALTNAME.RFC822Name);
  300. id = Identity.forEmail(email);
  301. if (!cert.subjects[0].equals(id))
  302. cert.subjects.push(id);
  303. break;
  304. case ALTNAME.DirectoryName:
  305. der.readSequence(ALTNAME.DirectoryName);
  306. id = Identity.parseAsn1(der);
  307. if (!cert.subjects[0].equals(id))
  308. cert.subjects.push(id);
  309. break;
  310. case ALTNAME.DNSName:
  311. var host = der.readString(
  312. ALTNAME.DNSName);
  313. id = Identity.forHost(host);
  314. if (!cert.subjects[0].equals(id))
  315. cert.subjects.push(id);
  316. break;
  317. default:
  318. der.readString(der.peek());
  319. break;
  320. }
  321. }
  322. sig.extras.exts.push({ oid: extId, critical: critical });
  323. break;
  324. default:
  325. sig.extras.exts.push({
  326. oid: extId,
  327. critical: critical,
  328. data: der.readString(asn1.Ber.OctetString, true)
  329. });
  330. break;
  331. }
  332. der._offset = after;
  333. }
  334. var UTCTIME_RE =
  335. /^([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})?Z$/;
  336. function utcTimeToDate(t) {
  337. var m = t.match(UTCTIME_RE);
  338. assert.ok(m, 'timestamps must be in UTC');
  339. var d = new Date();
  340. var thisYear = d.getUTCFullYear();
  341. var century = Math.floor(thisYear / 100) * 100;
  342. var year = parseInt(m[1], 10);
  343. if (thisYear % 100 < 50 && year >= 60)
  344. year += (century - 1);
  345. else
  346. year += century;
  347. d.setUTCFullYear(year, parseInt(m[2], 10) - 1, parseInt(m[3], 10));
  348. d.setUTCHours(parseInt(m[4], 10), parseInt(m[5], 10));
  349. if (m[6] && m[6].length > 0)
  350. d.setUTCSeconds(parseInt(m[6], 10));
  351. return (d);
  352. }
  353. var GTIME_RE =
  354. /^([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})?Z$/;
  355. function gTimeToDate(t) {
  356. var m = t.match(GTIME_RE);
  357. assert.ok(m);
  358. var d = new Date();
  359. d.setUTCFullYear(parseInt(m[1], 10), parseInt(m[2], 10) - 1,
  360. parseInt(m[3], 10));
  361. d.setUTCHours(parseInt(m[4], 10), parseInt(m[5], 10));
  362. if (m[6] && m[6].length > 0)
  363. d.setUTCSeconds(parseInt(m[6], 10));
  364. return (d);
  365. }
  366. function zeroPad(n) {
  367. var s = '' + n;
  368. while (s.length < 2)
  369. s = '0' + s;
  370. return (s);
  371. }
  372. function dateToUTCTime(d) {
  373. var s = '';
  374. s += zeroPad(d.getUTCFullYear() % 100);
  375. s += zeroPad(d.getUTCMonth() + 1);
  376. s += zeroPad(d.getUTCDate());
  377. s += zeroPad(d.getUTCHours());
  378. s += zeroPad(d.getUTCMinutes());
  379. s += zeroPad(d.getUTCSeconds());
  380. s += 'Z';
  381. return (s);
  382. }
  383. function sign(cert, key) {
  384. if (cert.signatures.x509 === undefined)
  385. cert.signatures.x509 = {};
  386. var sig = cert.signatures.x509;
  387. sig.algo = key.type + '-' + key.defaultHashAlgorithm();
  388. if (SIGN_ALGS[sig.algo] === undefined)
  389. return (false);
  390. var der = new asn1.BerWriter();
  391. writeTBSCert(cert, der);
  392. var blob = der.buffer;
  393. sig.cache = blob;
  394. var signer = key.createSign();
  395. signer.write(blob);
  396. cert.signatures.x509.signature = signer.sign();
  397. return (true);
  398. }
  399. function signAsync(cert, signer, done) {
  400. if (cert.signatures.x509 === undefined)
  401. cert.signatures.x509 = {};
  402. var sig = cert.signatures.x509;
  403. var der = new asn1.BerWriter();
  404. writeTBSCert(cert, der);
  405. var blob = der.buffer;
  406. sig.cache = blob;
  407. signer(blob, function (err, signature) {
  408. if (err) {
  409. done(err);
  410. return;
  411. }
  412. sig.algo = signature.type + '-' + signature.hashAlgorithm;
  413. if (SIGN_ALGS[sig.algo] === undefined) {
  414. done(new Error('Invalid signing algorithm "' +
  415. sig.algo + '"'));
  416. return;
  417. }
  418. sig.signature = signature;
  419. done();
  420. });
  421. }
  422. function write(cert, options) {
  423. var sig = cert.signatures.x509;
  424. assert.object(sig, 'x509 signature');
  425. var der = new asn1.BerWriter();
  426. der.startSequence();
  427. if (sig.cache) {
  428. der._ensure(sig.cache.length);
  429. sig.cache.copy(der._buf, der._offset);
  430. der._offset += sig.cache.length;
  431. } else {
  432. writeTBSCert(cert, der);
  433. }
  434. der.startSequence();
  435. der.writeOID(SIGN_ALGS[sig.algo]);
  436. if (sig.algo.match(/^rsa-/))
  437. der.writeNull();
  438. der.endSequence();
  439. var sigData = sig.signature.toBuffer('asn1');
  440. var data = new Buffer(sigData.length + 1);
  441. data[0] = 0;
  442. sigData.copy(data, 1);
  443. der.writeBuffer(data, asn1.Ber.BitString);
  444. der.endSequence();
  445. return (der.buffer);
  446. }
  447. function writeTBSCert(cert, der) {
  448. var sig = cert.signatures.x509;
  449. assert.object(sig, 'x509 signature');
  450. der.startSequence();
  451. der.startSequence(Local(0));
  452. der.writeInt(2);
  453. der.endSequence();
  454. der.writeBuffer(utils.mpNormalize(cert.serial), asn1.Ber.Integer);
  455. der.startSequence();
  456. der.writeOID(SIGN_ALGS[sig.algo]);
  457. der.endSequence();
  458. cert.issuer.toAsn1(der);
  459. der.startSequence();
  460. der.writeString(dateToUTCTime(cert.validFrom), asn1.Ber.UTCTime);
  461. der.writeString(dateToUTCTime(cert.validUntil), asn1.Ber.UTCTime);
  462. der.endSequence();
  463. var subject = cert.subjects[0];
  464. var altNames = cert.subjects.slice(1);
  465. subject.toAsn1(der);
  466. pkcs8.writePkcs8(der, cert.subjectKey);
  467. if (sig.extras && sig.extras.issuerUniqueID) {
  468. der.writeBuffer(sig.extras.issuerUniqueID, Local(1));
  469. }
  470. if (sig.extras && sig.extras.subjectUniqueID) {
  471. der.writeBuffer(sig.extras.subjectUniqueID, Local(2));
  472. }
  473. if (altNames.length > 0 || subject.type === 'host' ||
  474. (cert.purposes !== undefined && cert.purposes.length > 0) ||
  475. (sig.extras && sig.extras.exts)) {
  476. der.startSequence(Local(3));
  477. der.startSequence();
  478. var exts = [];
  479. if (cert.purposes !== undefined && cert.purposes.length > 0) {
  480. exts.push({
  481. oid: EXTS.basicConstraints,
  482. critical: true
  483. });
  484. exts.push({
  485. oid: EXTS.keyUsage,
  486. critical: true
  487. });
  488. exts.push({
  489. oid: EXTS.extKeyUsage,
  490. critical: true
  491. });
  492. }
  493. exts.push({ oid: EXTS.altName });
  494. if (sig.extras && sig.extras.exts)
  495. exts = sig.extras.exts;
  496. for (var i = 0; i < exts.length; ++i) {
  497. der.startSequence();
  498. der.writeOID(exts[i].oid);
  499. if (exts[i].critical !== undefined)
  500. der.writeBoolean(exts[i].critical);
  501. if (exts[i].oid === EXTS.altName) {
  502. der.startSequence(asn1.Ber.OctetString);
  503. der.startSequence();
  504. if (subject.type === 'host') {
  505. der.writeString(subject.hostname,
  506. Context(2));
  507. }
  508. for (var j = 0; j < altNames.length; ++j) {
  509. if (altNames[j].type === 'host') {
  510. der.writeString(
  511. altNames[j].hostname,
  512. ALTNAME.DNSName);
  513. } else if (altNames[j].type ===
  514. 'email') {
  515. der.writeString(
  516. altNames[j].email,
  517. ALTNAME.RFC822Name);
  518. } else {
  519. /*
  520. * Encode anything else as a
  521. * DN style name for now.
  522. */
  523. der.startSequence(
  524. ALTNAME.DirectoryName);
  525. altNames[j].toAsn1(der);
  526. der.endSequence();
  527. }
  528. }
  529. der.endSequence();
  530. der.endSequence();
  531. } else if (exts[i].oid === EXTS.basicConstraints) {
  532. der.startSequence(asn1.Ber.OctetString);
  533. der.startSequence();
  534. var ca = (cert.purposes.indexOf('ca') !== -1);
  535. var pathLen = exts[i].pathLen;
  536. der.writeBoolean(ca);
  537. if (pathLen !== undefined)
  538. der.writeInt(pathLen);
  539. der.endSequence();
  540. der.endSequence();
  541. } else if (exts[i].oid === EXTS.extKeyUsage) {
  542. der.startSequence(asn1.Ber.OctetString);
  543. der.startSequence();
  544. cert.purposes.forEach(function (purpose) {
  545. if (purpose === 'ca')
  546. return;
  547. if (KEYUSEBITS.indexOf(purpose) !== -1)
  548. return;
  549. var oid = purpose;
  550. if (EXTPURPOSE[purpose] !== undefined)
  551. oid = EXTPURPOSE[purpose];
  552. der.writeOID(oid);
  553. });
  554. der.endSequence();
  555. der.endSequence();
  556. } else if (exts[i].oid === EXTS.keyUsage) {
  557. der.startSequence(asn1.Ber.OctetString);
  558. /*
  559. * If we parsed this certificate from a byte
  560. * stream (i.e. we didn't generate it in sshpk)
  561. * then we'll have a ".bits" property on the
  562. * ext with the original raw byte contents.
  563. *
  564. * If we have this, use it here instead of
  565. * regenerating it. This guarantees we output
  566. * the same data we parsed, so signatures still
  567. * validate.
  568. */
  569. if (exts[i].bits !== undefined) {
  570. der.writeBuffer(exts[i].bits,
  571. asn1.Ber.BitString);
  572. } else {
  573. var bits = writeBitField(cert.purposes,
  574. KEYUSEBITS);
  575. der.writeBuffer(bits,
  576. asn1.Ber.BitString);
  577. }
  578. der.endSequence();
  579. } else {
  580. der.writeBuffer(exts[i].data,
  581. asn1.Ber.OctetString);
  582. }
  583. der.endSequence();
  584. }
  585. der.endSequence();
  586. der.endSequence();
  587. }
  588. der.endSequence();
  589. }
  590. /*
  591. * Reads an ASN.1 BER bitfield out of the Buffer produced by doing
  592. * `BerReader#readString(asn1.Ber.BitString)`. That function gives us the raw
  593. * contents of the BitString tag, which is a count of unused bits followed by
  594. * the bits as a right-padded byte string.
  595. *
  596. * `bits` is the Buffer, `bitIndex` should contain an array of string names
  597. * for the bits in the string, ordered starting with bit #0 in the ASN.1 spec.
  598. *
  599. * Returns an array of Strings, the names of the bits that were set to 1.
  600. */
  601. function readBitField(bits, bitIndex) {
  602. var bitLen = 8 * (bits.length - 1) - bits[0];
  603. var setBits = {};
  604. for (var i = 0; i < bitLen; ++i) {
  605. var byteN = 1 + Math.floor(i / 8);
  606. var bit = 7 - (i % 8);
  607. var mask = 1 << bit;
  608. var bitVal = ((bits[byteN] & mask) !== 0);
  609. var name = bitIndex[i];
  610. if (bitVal && typeof (name) === 'string') {
  611. setBits[name] = true;
  612. }
  613. }
  614. return (Object.keys(setBits));
  615. }
  616. /*
  617. * `setBits` is an array of strings, containing the names for each bit that
  618. * sould be set to 1. `bitIndex` is same as in `readBitField()`.
  619. *
  620. * Returns a Buffer, ready to be written out with `BerWriter#writeString()`.
  621. */
  622. function writeBitField(setBits, bitIndex) {
  623. var bitLen = bitIndex.length;
  624. var blen = Math.ceil(bitLen / 8);
  625. var unused = blen * 8 - bitLen;
  626. var bits = new Buffer(1 + blen);
  627. bits.fill(0);
  628. bits[0] = unused;
  629. for (var i = 0; i < bitLen; ++i) {
  630. var byteN = 1 + Math.floor(i / 8);
  631. var bit = 7 - (i % 8);
  632. var mask = 1 << bit;
  633. var name = bitIndex[i];
  634. if (name === undefined)
  635. continue;
  636. var bitVal = (setBits.indexOf(name) !== -1);
  637. if (bitVal) {
  638. bits[byteN] |= mask;
  639. }
  640. }
  641. return (bits);
  642. }