1 // Copyright 2015 Joyent, Inc.
7 writePkcs8: writePkcs8,
9 readECDSACurve: readECDSACurve,
10 writeECDSACurve: writeECDSACurve
13 var assert = require('assert-plus');
14 var asn1 = require('asn1');
15 var algs = require('../algs');
16 var utils = require('../utils');
17 var Key = require('../key');
18 var PrivateKey = require('../private-key');
19 var pem = require('./pem');
21 function read(buf, options) {
22 return (pem.read(buf, options, 'pkcs8'));
25 function write(key, options) {
26 return (pem.write(key, options, 'pkcs8'));
29 /* Helper to read in a single mpint */
30 function readMPInt(der, nm) {
31 assert.strictEqual(der.peek(), asn1.Ber.Integer,
32 nm + ' is not an Integer');
33 return (utils.mpNormalize(der.readString(asn1.Ber.Integer, true)));
36 function readPkcs8(alg, type, der) {
37 /* Private keys in pkcs#8 format have a weird extra int */
38 if (der.peek() === asn1.Ber.Integer) {
39 assert.strictEqual(type, 'private',
40 'unexpected Integer at start of public key');
41 der.readString(asn1.Ber.Integer, true);
45 var next = der.offset + der.length;
47 var oid = der.readOID();
49 case '1.2.840.113549.1.1.1':
51 if (type === 'public')
52 return (readPkcs8RSAPublic(der));
54 return (readPkcs8RSAPrivate(der));
55 case '1.2.840.10040.4.1':
56 if (type === 'public')
57 return (readPkcs8DSAPublic(der));
59 return (readPkcs8DSAPrivate(der));
60 case '1.2.840.10045.2.1':
61 if (type === 'public')
62 return (readPkcs8ECDSAPublic(der));
64 return (readPkcs8ECDSAPrivate(der));
66 throw (new Error('Unknown key type OID ' + oid));
70 function readPkcs8RSAPublic(der) {
71 // bit string sequence
72 der.readSequence(asn1.Ber.BitString);
77 var n = readMPInt(der, 'modulus');
78 var e = readMPInt(der, 'exponent');
83 source: der.originalInput,
85 { name: 'e', data: e },
86 { name: 'n', data: n }
90 return (new Key(key));
93 function readPkcs8RSAPrivate(der) {
94 der.readSequence(asn1.Ber.OctetString);
97 var ver = readMPInt(der, 'version');
98 assert.equal(ver[0], 0x0, 'unknown RSA private key version');
100 // modulus then public exponent
101 var n = readMPInt(der, 'modulus');
102 var e = readMPInt(der, 'public exponent');
103 var d = readMPInt(der, 'private exponent');
104 var p = readMPInt(der, 'prime1');
105 var q = readMPInt(der, 'prime2');
106 var dmodp = readMPInt(der, 'exponent1');
107 var dmodq = readMPInt(der, 'exponent2');
108 var iqmp = readMPInt(der, 'iqmp');
114 { name: 'n', data: n },
115 { name: 'e', data: e },
116 { name: 'd', data: d },
117 { name: 'iqmp', data: iqmp },
118 { name: 'p', data: p },
119 { name: 'q', data: q },
120 { name: 'dmodp', data: dmodp },
121 { name: 'dmodq', data: dmodq }
125 return (new PrivateKey(key));
128 function readPkcs8DSAPublic(der) {
131 var p = readMPInt(der, 'p');
132 var q = readMPInt(der, 'q');
133 var g = readMPInt(der, 'g');
135 // bit string sequence
136 der.readSequence(asn1.Ber.BitString);
139 var y = readMPInt(der, 'y');
145 { name: 'p', data: p },
146 { name: 'q', data: q },
147 { name: 'g', data: g },
148 { name: 'y', data: y }
152 return (new Key(key));
155 function readPkcs8DSAPrivate(der) {
158 var p = readMPInt(der, 'p');
159 var q = readMPInt(der, 'q');
160 var g = readMPInt(der, 'g');
162 der.readSequence(asn1.Ber.OctetString);
163 var x = readMPInt(der, 'x');
165 /* The pkcs#8 format does not include the public key */
166 var y = utils.calculateDSAPublic(g, p, x);
171 { name: 'p', data: p },
172 { name: 'q', data: q },
173 { name: 'g', data: g },
174 { name: 'y', data: y },
175 { name: 'x', data: x }
179 return (new PrivateKey(key));
182 function readECDSACurve(der) {
183 var curveName, curveNames;
186 if (der.peek() === asn1.Ber.OID) {
187 var oid = der.readOID();
189 curveNames = Object.keys(algs.curves);
190 for (j = 0; j < curveNames.length; ++j) {
193 if (cd.pkcs8oid === oid) {
200 // ECParameters sequence
202 var version = der.readString(asn1.Ber.Integer, true);
203 assert.strictEqual(version[0], 1, 'ECDSA key not version 1');
209 var fieldTypeOid = der.readOID();
210 assert.strictEqual(fieldTypeOid, '1.2.840.10045.1.1',
211 'ECDSA key is not from a prime-field');
212 var p = curve.p = utils.mpNormalize(
213 der.readString(asn1.Ber.Integer, true));
215 * p always starts with a 1 bit, so count the zeros to get its
218 curve.size = p.length * 8 - utils.countZeros(p);
222 curve.a = utils.mpNormalize(
223 der.readString(asn1.Ber.OctetString, true));
224 curve.b = utils.mpNormalize(
225 der.readString(asn1.Ber.OctetString, true));
226 if (der.peek() === asn1.Ber.BitString)
227 curve.s = der.readString(asn1.Ber.BitString, true);
229 // Combined Gx and Gy
230 curve.G = der.readString(asn1.Ber.OctetString, true);
231 assert.strictEqual(curve.G[0], 0x4,
232 'uncompressed G is required');
234 curve.n = utils.mpNormalize(
235 der.readString(asn1.Ber.Integer, true));
236 curve.h = utils.mpNormalize(
237 der.readString(asn1.Ber.Integer, true));
238 assert.strictEqual(curve.h[0], 0x1, 'a cofactor=1 curve is ' +
241 curveNames = Object.keys(algs.curves);
242 var ks = Object.keys(curve);
243 for (j = 0; j < curveNames.length; ++j) {
247 for (var i = 0; i < ks.length; ++i) {
249 if (cd[k] === undefined)
251 if (typeof (cd[k]) === 'object' &&
252 cd[k].equals !== undefined) {
253 if (!cd[k].equals(curve[k])) {
257 } else if (Buffer.isBuffer(cd[k])) {
258 if (cd[k].toString('binary')
259 !== curve[k].toString('binary')) {
264 if (cd[k] !== curve[k]) {
279 function readPkcs8ECDSAPrivate(der) {
280 var curveName = readECDSACurve(der);
281 assert.string(curveName, 'a known elliptic curve');
283 der.readSequence(asn1.Ber.OctetString);
286 var version = readMPInt(der, 'version');
287 assert.equal(version[0], 1, 'unknown version of ECDSA key');
289 var d = der.readString(asn1.Ber.OctetString, true);
290 der.readSequence(0xa1);
292 var Q = der.readString(asn1.Ber.BitString, true);
293 Q = utils.ecNormalize(Q);
298 { name: 'curve', data: new Buffer(curveName) },
299 { name: 'Q', data: Q },
300 { name: 'd', data: d }
304 return (new PrivateKey(key));
307 function readPkcs8ECDSAPublic(der) {
308 var curveName = readECDSACurve(der);
309 assert.string(curveName, 'a known elliptic curve');
311 var Q = der.readString(asn1.Ber.BitString, true);
312 Q = utils.ecNormalize(Q);
317 { name: 'curve', data: new Buffer(curveName) },
318 { name: 'Q', data: Q }
322 return (new Key(key));
325 function writePkcs8(der, key) {
328 if (PrivateKey.isPrivateKey(key)) {
329 var sillyInt = new Buffer(1);
331 der.writeBuffer(sillyInt, asn1.Ber.Integer);
337 der.writeOID('1.2.840.113549.1.1.1');
338 if (PrivateKey.isPrivateKey(key))
339 writePkcs8RSAPrivate(key, der);
341 writePkcs8RSAPublic(key, der);
344 der.writeOID('1.2.840.10040.4.1');
345 if (PrivateKey.isPrivateKey(key))
346 writePkcs8DSAPrivate(key, der);
348 writePkcs8DSAPublic(key, der);
351 der.writeOID('1.2.840.10045.2.1');
352 if (PrivateKey.isPrivateKey(key))
353 writePkcs8ECDSAPrivate(key, der);
355 writePkcs8ECDSAPublic(key, der);
358 throw (new Error('Unsupported key type: ' + key.type));
364 function writePkcs8RSAPrivate(key, der) {
368 der.startSequence(asn1.Ber.OctetString);
371 var version = new Buffer(1);
373 der.writeBuffer(version, asn1.Ber.Integer);
375 der.writeBuffer(key.part.n.data, asn1.Ber.Integer);
376 der.writeBuffer(key.part.e.data, asn1.Ber.Integer);
377 der.writeBuffer(key.part.d.data, asn1.Ber.Integer);
378 der.writeBuffer(key.part.p.data, asn1.Ber.Integer);
379 der.writeBuffer(key.part.q.data, asn1.Ber.Integer);
380 if (!key.part.dmodp || !key.part.dmodq)
381 utils.addRSAMissing(key);
382 der.writeBuffer(key.part.dmodp.data, asn1.Ber.Integer);
383 der.writeBuffer(key.part.dmodq.data, asn1.Ber.Integer);
384 der.writeBuffer(key.part.iqmp.data, asn1.Ber.Integer);
390 function writePkcs8RSAPublic(key, der) {
394 der.startSequence(asn1.Ber.BitString);
398 der.writeBuffer(key.part.n.data, asn1.Ber.Integer);
399 der.writeBuffer(key.part.e.data, asn1.Ber.Integer);
405 function writePkcs8DSAPrivate(key, der) {
407 der.writeBuffer(key.part.p.data, asn1.Ber.Integer);
408 der.writeBuffer(key.part.q.data, asn1.Ber.Integer);
409 der.writeBuffer(key.part.g.data, asn1.Ber.Integer);
414 der.startSequence(asn1.Ber.OctetString);
415 der.writeBuffer(key.part.x.data, asn1.Ber.Integer);
419 function writePkcs8DSAPublic(key, der) {
421 der.writeBuffer(key.part.p.data, asn1.Ber.Integer);
422 der.writeBuffer(key.part.q.data, asn1.Ber.Integer);
423 der.writeBuffer(key.part.g.data, asn1.Ber.Integer);
427 der.startSequence(asn1.Ber.BitString);
429 der.writeBuffer(key.part.y.data, asn1.Ber.Integer);
433 function writeECDSACurve(key, der) {
434 var curve = algs.curves[key.curve];
435 if (curve.pkcs8oid) {
436 /* This one has a name in pkcs#8, so just write the oid */
437 der.writeOID(curve.pkcs8oid);
440 // ECParameters sequence
443 var version = new Buffer(1);
444 version.writeUInt8(1, 0);
445 der.writeBuffer(version, asn1.Ber.Integer);
449 der.writeOID('1.2.840.10045.1.1'); // prime-field
450 der.writeBuffer(curve.p, asn1.Ber.Integer);
458 der.writeBuffer(a, asn1.Ber.OctetString);
459 der.writeBuffer(curve.b, asn1.Ber.OctetString);
460 der.writeBuffer(curve.s, asn1.Ber.BitString);
463 der.writeBuffer(curve.G, asn1.Ber.OctetString);
464 der.writeBuffer(curve.n, asn1.Ber.Integer);
470 der.writeBuffer(h, asn1.Ber.Integer);
477 function writePkcs8ECDSAPublic(key, der) {
478 writeECDSACurve(key, der);
481 var Q = utils.ecNormalize(key.part.Q.data, true);
482 der.writeBuffer(Q, asn1.Ber.BitString);
485 function writePkcs8ECDSAPrivate(key, der) {
486 writeECDSACurve(key, der);
489 der.startSequence(asn1.Ber.OctetString);
492 var version = new Buffer(1);
494 der.writeBuffer(version, asn1.Ber.Integer);
496 der.writeBuffer(key.part.d.data, asn1.Ber.OctetString);
498 der.startSequence(0xa1);
499 var Q = utils.ecNormalize(key.part.Q.data, true);
500 der.writeBuffer(Q, asn1.Ber.BitString);