1 // Copyright 2016 Joyent, Inc.
10 var assert = require('assert-plus');
11 var asn1 = require('asn1');
12 var algs = require('../algs');
13 var utils = require('../utils');
14 var Key = require('../key');
15 var PrivateKey = require('../private-key');
16 var pem = require('./pem');
17 var Identity = require('../identity');
18 var Signature = require('../signature');
19 var Certificate = require('../certificate');
20 var pkcs8 = require('./pkcs8');
23 * This file is based on RFC5280 (X.509).
26 /* Helper to read in a single mpint */
27 function readMPInt(der, nm) {
28 assert.strictEqual(der.peek(), asn1.Ber.Integer,
29 nm + ' is not an Integer');
30 return (utils.mpNormalize(der.readString(asn1.Ber.Integer, true)));
33 function verify(cert, key) {
34 var sig = cert.signatures.x509;
35 assert.object(sig, 'x509 signature');
37 var algParts = sig.algo.split('-');
38 if (algParts[0] !== key.type)
42 if (blob === undefined) {
43 var der = new asn1.BerWriter();
44 writeTBSCert(cert, der);
48 var verifier = key.createVerify(algParts[1]);
50 return (verifier.verify(sig.signature));
54 return (asn1.Ber.Context | asn1.Ber.Constructor | i);
58 return (asn1.Ber.Context | i);
62 'rsa-md5': '1.2.840.113549.1.1.4',
63 'rsa-sha1': '1.2.840.113549.1.1.5',
64 'rsa-sha256': '1.2.840.113549.1.1.11',
65 'rsa-sha384': '1.2.840.113549.1.1.12',
66 'rsa-sha512': '1.2.840.113549.1.1.13',
67 'dsa-sha1': '1.2.840.10040.4.3',
68 'dsa-sha256': '2.16.840.1.101.3.4.3.2',
69 'ecdsa-sha1': '1.2.840.10045.4.1',
70 'ecdsa-sha256': '1.2.840.10045.4.3.2',
71 'ecdsa-sha384': '1.2.840.10045.4.3.3',
72 'ecdsa-sha512': '1.2.840.10045.4.3.4'
74 Object.keys(SIGN_ALGS).forEach(function (k) {
75 SIGN_ALGS[SIGN_ALGS[k]] = k;
77 SIGN_ALGS['1.3.14.3.2.3'] = 'rsa-md5';
78 SIGN_ALGS['1.3.14.3.2.29'] = 'rsa-sha1';
81 'issuerKeyId': '2.5.29.35',
82 'altName': '2.5.29.17',
83 'basicConstraints': '2.5.29.19',
84 'keyUsage': '2.5.29.15',
85 'extKeyUsage': '2.5.29.37'
88 function read(buf, options) {
89 if (typeof (buf) === 'string') {
90 buf = new Buffer(buf, 'binary');
92 assert.buffer(buf, 'buf');
94 var der = new asn1.BerReader(buf);
97 if (Math.abs(der.length - der.remain) > 1) {
98 throw (new Error('DER sequence does not contain whole byte ' +
102 var tbsStart = der.offset;
104 var sigOffset = der.offset + der.length;
105 var tbsEnd = sigOffset;
107 if (der.peek() === Local(0)) {
108 der.readSequence(Local(0));
109 var version = der.readInt();
110 assert.ok(version <= 3,
111 'only x.509 versions up to v3 supported');
115 cert.signatures = {};
116 var sig = (cert.signatures.x509 = {});
119 cert.serial = readMPInt(der, 'serial');
122 var after = der.offset + der.length;
123 var certAlgOid = der.readOID();
124 var certAlg = SIGN_ALGS[certAlgOid];
125 if (certAlg === undefined)
126 throw (new Error('unknown signature algorithm ' + certAlgOid));
129 cert.issuer = Identity.parseAsn1(der);
132 cert.validFrom = readDate(der);
133 cert.validUntil = readDate(der);
135 cert.subjects = [Identity.parseAsn1(der)];
138 after = der.offset + der.length;
139 cert.subjectKey = pkcs8.readPkcs8(undefined, 'public', der);
143 if (der.peek() === Local(1)) {
144 der.readSequence(Local(1));
145 sig.extras.issuerUniqueID =
146 buf.slice(der.offset, der.offset + der.length);
147 der._offset += der.length;
150 /* subjectUniqueID */
151 if (der.peek() === Local(2)) {
152 der.readSequence(Local(2));
153 sig.extras.subjectUniqueID =
154 buf.slice(der.offset, der.offset + der.length);
155 der._offset += der.length;
159 if (der.peek() === Local(3)) {
160 der.readSequence(Local(3));
161 var extEnd = der.offset + der.length;
164 while (der.offset < extEnd)
165 readExtension(cert, buf, der);
167 assert.strictEqual(der.offset, extEnd);
170 assert.strictEqual(der.offset, sigOffset);
173 after = der.offset + der.length;
174 var sigAlgOid = der.readOID();
175 var sigAlg = SIGN_ALGS[sigAlgOid];
176 if (sigAlg === undefined)
177 throw (new Error('unknown signature algorithm ' + sigAlgOid));
180 var sigData = der.readString(asn1.Ber.BitString, true);
181 if (sigData[0] === 0)
182 sigData = sigData.slice(1);
183 var algParts = sigAlg.split('-');
185 sig.signature = Signature.parse(sigData, algParts[0], 'asn1');
186 sig.signature.hashAlgorithm = algParts[1];
188 sig.cache = buf.slice(tbsStart, tbsEnd);
190 return (new Certificate(cert));
193 function readDate(der) {
194 if (der.peek() === asn1.Ber.UTCTime) {
195 return (utcTimeToDate(der.readString(asn1.Ber.UTCTime)));
196 } else if (der.peek() === asn1.Ber.GeneralizedTime) {
197 return (gTimeToDate(der.readString(asn1.Ber.GeneralizedTime)));
199 throw (new Error('Unsupported date format'));
203 /* RFC5280, section 4.2.1.6 (GeneralName type) */
206 RFC822Name: Context(1),
208 X400Address: Local(3),
209 DirectoryName: Local(4),
210 EDIPartyName: Local(5),
212 IPAddress: Context(7),
216 /* RFC5280, section 4.2.1.12 (KeyPurposeId) */
218 'serverAuth': '1.3.6.1.5.5.7.3.1',
219 'clientAuth': '1.3.6.1.5.5.7.3.2',
220 'codeSigning': '1.3.6.1.5.5.7.3.3',
222 /* See https://github.com/joyent/oid-docs/blob/master/root.md */
223 'joyentDocker': '1.3.6.1.4.1.38678.1.4.1',
224 'joyentCmon': '1.3.6.1.4.1.38678.1.4.2'
226 var EXTPURPOSE_REV = {};
227 Object.keys(EXTPURPOSE).forEach(function (k) {
228 EXTPURPOSE_REV[EXTPURPOSE[k]] = k;
232 'signature', 'identity', 'keyEncryption',
233 'encryption', 'keyAgreement', 'ca', 'crl'
236 function readExtension(cert, buf, der) {
238 var after = der.offset + der.length;
239 var extId = der.readOID();
241 var sig = cert.signatures.x509;
242 sig.extras.exts = [];
245 if (der.peek() === asn1.Ber.Boolean)
246 critical = der.readBoolean();
249 case (EXTS.basicConstraints):
250 der.readSequence(asn1.Ber.OctetString);
252 var bcEnd = der.offset + der.length;
254 if (der.peek() === asn1.Ber.Boolean)
255 ca = der.readBoolean();
256 if (cert.purposes === undefined)
259 cert.purposes.push('ca');
260 var bc = { oid: extId, critical: critical };
261 if (der.offset < bcEnd && der.peek() === asn1.Ber.Integer)
262 bc.pathLen = der.readInt();
263 sig.extras.exts.push(bc);
265 case (EXTS.extKeyUsage):
266 der.readSequence(asn1.Ber.OctetString);
268 if (cert.purposes === undefined)
270 var ekEnd = der.offset + der.length;
271 while (der.offset < ekEnd) {
272 var oid = der.readOID();
273 cert.purposes.push(EXTPURPOSE_REV[oid] || oid);
276 * This is a bit of a hack: in the case where we have a cert
277 * that's only allowed to do serverAuth or clientAuth (and not
278 * the other), we want to make sure all our Subjects are of
279 * the right type. But we already parsed our Subjects and
280 * decided if they were hosts or users earlier (since it appears
281 * first in the cert).
283 * So we go through and mutate them into the right kind here if
284 * it doesn't match. This might not be hugely beneficial, as it
285 * seems that single-purpose certs are not often seen in the
288 if (cert.purposes.indexOf('serverAuth') !== -1 &&
289 cert.purposes.indexOf('clientAuth') === -1) {
290 cert.subjects.forEach(function (ide) {
291 if (ide.type !== 'host') {
293 ide.hostname = ide.uid ||
295 ide.components[0].value;
298 } else if (cert.purposes.indexOf('clientAuth') !== -1 &&
299 cert.purposes.indexOf('serverAuth') === -1) {
300 cert.subjects.forEach(function (ide) {
301 if (ide.type !== 'user') {
303 ide.uid = ide.hostname ||
305 ide.components[0].value;
309 sig.extras.exts.push({ oid: extId, critical: critical });
311 case (EXTS.keyUsage):
312 der.readSequence(asn1.Ber.OctetString);
313 var bits = der.readString(asn1.Ber.BitString, true);
314 var setBits = readBitField(bits, KEYUSEBITS);
315 setBits.forEach(function (bit) {
316 if (cert.purposes === undefined)
318 if (cert.purposes.indexOf(bit) === -1)
319 cert.purposes.push(bit);
321 sig.extras.exts.push({ oid: extId, critical: critical,
325 der.readSequence(asn1.Ber.OctetString);
327 var aeEnd = der.offset + der.length;
328 while (der.offset < aeEnd) {
329 switch (der.peek()) {
330 case ALTNAME.OtherName:
331 case ALTNAME.EDIPartyName:
333 der._offset += der.length;
336 der.readOID(ALTNAME.OID);
338 case ALTNAME.RFC822Name:
339 /* RFC822 specifies email addresses */
340 var email = der.readString(ALTNAME.RFC822Name);
341 id = Identity.forEmail(email);
342 if (!cert.subjects[0].equals(id))
343 cert.subjects.push(id);
345 case ALTNAME.DirectoryName:
346 der.readSequence(ALTNAME.DirectoryName);
347 id = Identity.parseAsn1(der);
348 if (!cert.subjects[0].equals(id))
349 cert.subjects.push(id);
351 case ALTNAME.DNSName:
352 var host = der.readString(
354 id = Identity.forHost(host);
355 if (!cert.subjects[0].equals(id))
356 cert.subjects.push(id);
359 der.readString(der.peek());
363 sig.extras.exts.push({ oid: extId, critical: critical });
366 sig.extras.exts.push({
369 data: der.readString(asn1.Ber.OctetString, true)
378 /^([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})?Z$/;
379 function utcTimeToDate(t) {
380 var m = t.match(UTCTIME_RE);
381 assert.ok(m, 'timestamps must be in UTC');
384 var thisYear = d.getUTCFullYear();
385 var century = Math.floor(thisYear / 100) * 100;
387 var year = parseInt(m[1], 10);
388 if (thisYear % 100 < 50 && year >= 60)
389 year += (century - 1);
392 d.setUTCFullYear(year, parseInt(m[2], 10) - 1, parseInt(m[3], 10));
393 d.setUTCHours(parseInt(m[4], 10), parseInt(m[5], 10));
394 if (m[6] && m[6].length > 0)
395 d.setUTCSeconds(parseInt(m[6], 10));
400 /^([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})?Z$/;
401 function gTimeToDate(t) {
402 var m = t.match(GTIME_RE);
406 d.setUTCFullYear(parseInt(m[1], 10), parseInt(m[2], 10) - 1,
408 d.setUTCHours(parseInt(m[4], 10), parseInt(m[5], 10));
409 if (m[6] && m[6].length > 0)
410 d.setUTCSeconds(parseInt(m[6], 10));
414 function zeroPad(n) {
421 function dateToUTCTime(d) {
423 s += zeroPad(d.getUTCFullYear() % 100);
424 s += zeroPad(d.getUTCMonth() + 1);
425 s += zeroPad(d.getUTCDate());
426 s += zeroPad(d.getUTCHours());
427 s += zeroPad(d.getUTCMinutes());
428 s += zeroPad(d.getUTCSeconds());
433 function sign(cert, key) {
434 if (cert.signatures.x509 === undefined)
435 cert.signatures.x509 = {};
436 var sig = cert.signatures.x509;
438 sig.algo = key.type + '-' + key.defaultHashAlgorithm();
439 if (SIGN_ALGS[sig.algo] === undefined)
442 var der = new asn1.BerWriter();
443 writeTBSCert(cert, der);
444 var blob = der.buffer;
447 var signer = key.createSign();
449 cert.signatures.x509.signature = signer.sign();
454 function write(cert, options) {
455 var sig = cert.signatures.x509;
456 assert.object(sig, 'x509 signature');
458 var der = new asn1.BerWriter();
461 der._ensure(sig.cache.length);
462 sig.cache.copy(der._buf, der._offset);
463 der._offset += sig.cache.length;
465 writeTBSCert(cert, der);
469 der.writeOID(SIGN_ALGS[sig.algo]);
470 if (sig.algo.match(/^rsa-/))
474 var sigData = sig.signature.toBuffer('asn1');
475 var data = new Buffer(sigData.length + 1);
477 sigData.copy(data, 1);
478 der.writeBuffer(data, asn1.Ber.BitString);
484 function writeTBSCert(cert, der) {
485 var sig = cert.signatures.x509;
486 assert.object(sig, 'x509 signature');
490 der.startSequence(Local(0));
494 der.writeBuffer(utils.mpNormalize(cert.serial), asn1.Ber.Integer);
497 der.writeOID(SIGN_ALGS[sig.algo]);
500 cert.issuer.toAsn1(der);
503 der.writeString(dateToUTCTime(cert.validFrom), asn1.Ber.UTCTime);
504 der.writeString(dateToUTCTime(cert.validUntil), asn1.Ber.UTCTime);
507 var subject = cert.subjects[0];
508 var altNames = cert.subjects.slice(1);
511 pkcs8.writePkcs8(der, cert.subjectKey);
513 if (sig.extras && sig.extras.issuerUniqueID) {
514 der.writeBuffer(sig.extras.issuerUniqueID, Local(1));
517 if (sig.extras && sig.extras.subjectUniqueID) {
518 der.writeBuffer(sig.extras.subjectUniqueID, Local(2));
521 if (altNames.length > 0 || subject.type === 'host' ||
522 (cert.purposes !== undefined && cert.purposes.length > 0) ||
523 (sig.extras && sig.extras.exts)) {
524 der.startSequence(Local(3));
528 if (cert.purposes !== undefined && cert.purposes.length > 0) {
530 oid: EXTS.basicConstraints,
538 oid: EXTS.extKeyUsage,
542 exts.push({ oid: EXTS.altName });
543 if (sig.extras && sig.extras.exts)
544 exts = sig.extras.exts;
546 for (var i = 0; i < exts.length; ++i) {
548 der.writeOID(exts[i].oid);
550 if (exts[i].critical !== undefined)
551 der.writeBoolean(exts[i].critical);
553 if (exts[i].oid === EXTS.altName) {
554 der.startSequence(asn1.Ber.OctetString);
556 if (subject.type === 'host') {
557 der.writeString(subject.hostname,
560 for (var j = 0; j < altNames.length; ++j) {
561 if (altNames[j].type === 'host') {
563 altNames[j].hostname,
565 } else if (altNames[j].type ===
572 * Encode anything else as a
573 * DN style name for now.
576 ALTNAME.DirectoryName);
577 altNames[j].toAsn1(der);
583 } else if (exts[i].oid === EXTS.basicConstraints) {
584 der.startSequence(asn1.Ber.OctetString);
586 var ca = (cert.purposes.indexOf('ca') !== -1);
587 var pathLen = exts[i].pathLen;
588 der.writeBoolean(ca);
589 if (pathLen !== undefined)
590 der.writeInt(pathLen);
593 } else if (exts[i].oid === EXTS.extKeyUsage) {
594 der.startSequence(asn1.Ber.OctetString);
596 cert.purposes.forEach(function (purpose) {
597 if (purpose === 'ca')
599 if (KEYUSEBITS.indexOf(purpose) !== -1)
602 if (EXTPURPOSE[purpose] !== undefined)
603 oid = EXTPURPOSE[purpose];
608 } else if (exts[i].oid === EXTS.keyUsage) {
609 der.startSequence(asn1.Ber.OctetString);
611 * If we parsed this certificate from a byte
612 * stream (i.e. we didn't generate it in sshpk)
613 * then we'll have a ".bits" property on the
614 * ext with the original raw byte contents.
616 * If we have this, use it here instead of
617 * regenerating it. This guarantees we output
618 * the same data we parsed, so signatures still
621 if (exts[i].bits !== undefined) {
622 der.writeBuffer(exts[i].bits,
625 var bits = writeBitField(cert.purposes,
627 der.writeBuffer(bits,
632 der.writeBuffer(exts[i].data,
633 asn1.Ber.OctetString);
647 * Reads an ASN.1 BER bitfield out of the Buffer produced by doing
648 * `BerReader#readString(asn1.Ber.BitString)`. That function gives us the raw
649 * contents of the BitString tag, which is a count of unused bits followed by
650 * the bits as a right-padded byte string.
652 * `bits` is the Buffer, `bitIndex` should contain an array of string names
653 * for the bits in the string, ordered starting with bit #0 in the ASN.1 spec.
655 * Returns an array of Strings, the names of the bits that were set to 1.
657 function readBitField(bits, bitIndex) {
658 var bitLen = 8 * (bits.length - 1) - bits[0];
660 for (var i = 0; i < bitLen; ++i) {
661 var byteN = 1 + Math.floor(i / 8);
662 var bit = 7 - (i % 8);
664 var bitVal = ((bits[byteN] & mask) !== 0);
665 var name = bitIndex[i];
666 if (bitVal && typeof (name) === 'string') {
667 setBits[name] = true;
670 return (Object.keys(setBits));
674 * `setBits` is an array of strings, containing the names for each bit that
675 * sould be set to 1. `bitIndex` is same as in `readBitField()`.
677 * Returns a Buffer, ready to be written out with `BerWriter#writeString()`.
679 function writeBitField(setBits, bitIndex) {
680 var bitLen = bitIndex.length;
681 var blen = Math.ceil(bitLen / 8);
682 var unused = blen * 8 - bitLen;
683 var bits = new Buffer(1 + blen);
686 for (var i = 0; i < bitLen; ++i) {
687 var byteN = 1 + Math.floor(i / 8);
688 var bit = 7 - (i % 8);
690 var name = bitIndex[i];
691 if (name === undefined)
693 var bitVal = (setBits.indexOf(name) !== -1);