• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2015 Joyent, Inc.
2
3module.exports = {
4	read: read,
5	readPkcs8: readPkcs8,
6	write: write,
7	writePkcs8: writePkcs8,
8
9	readECDSACurve: readECDSACurve,
10	writeECDSACurve: writeECDSACurve
11};
12
13var assert = require('assert-plus');
14var asn1 = require('asn1');
15var Buffer = require('safer-buffer').Buffer;
16var algs = require('../algs');
17var utils = require('../utils');
18var Key = require('../key');
19var PrivateKey = require('../private-key');
20var pem = require('./pem');
21
22function read(buf, options) {
23	return (pem.read(buf, options, 'pkcs8'));
24}
25
26function write(key, options) {
27	return (pem.write(key, options, 'pkcs8'));
28}
29
30/* Helper to read in a single mpint */
31function readMPInt(der, nm) {
32	assert.strictEqual(der.peek(), asn1.Ber.Integer,
33	    nm + ' is not an Integer');
34	return (utils.mpNormalize(der.readString(asn1.Ber.Integer, true)));
35}
36
37function readPkcs8(alg, type, der) {
38	/* Private keys in pkcs#8 format have a weird extra int */
39	if (der.peek() === asn1.Ber.Integer) {
40		assert.strictEqual(type, 'private',
41		    'unexpected Integer at start of public key');
42		der.readString(asn1.Ber.Integer, true);
43	}
44
45	der.readSequence();
46	var next = der.offset + der.length;
47
48	var oid = der.readOID();
49	switch (oid) {
50	case '1.2.840.113549.1.1.1':
51		der._offset = next;
52		if (type === 'public')
53			return (readPkcs8RSAPublic(der));
54		else
55			return (readPkcs8RSAPrivate(der));
56	case '1.2.840.10040.4.1':
57		if (type === 'public')
58			return (readPkcs8DSAPublic(der));
59		else
60			return (readPkcs8DSAPrivate(der));
61	case '1.2.840.10045.2.1':
62		if (type === 'public')
63			return (readPkcs8ECDSAPublic(der));
64		else
65			return (readPkcs8ECDSAPrivate(der));
66	case '1.3.101.112':
67		if (type === 'public') {
68			return (readPkcs8EdDSAPublic(der));
69		} else {
70			return (readPkcs8EdDSAPrivate(der));
71		}
72	case '1.3.101.110':
73		if (type === 'public') {
74			return (readPkcs8X25519Public(der));
75		} else {
76			return (readPkcs8X25519Private(der));
77		}
78	default:
79		throw (new Error('Unknown key type OID ' + oid));
80	}
81}
82
83function readPkcs8RSAPublic(der) {
84	// bit string sequence
85	der.readSequence(asn1.Ber.BitString);
86	der.readByte();
87	der.readSequence();
88
89	// modulus
90	var n = readMPInt(der, 'modulus');
91	var e = readMPInt(der, 'exponent');
92
93	// now, make the key
94	var key = {
95		type: 'rsa',
96		source: der.originalInput,
97		parts: [
98			{ name: 'e', data: e },
99			{ name: 'n', data: n }
100		]
101	};
102
103	return (new Key(key));
104}
105
106function readPkcs8RSAPrivate(der) {
107	der.readSequence(asn1.Ber.OctetString);
108	der.readSequence();
109
110	var ver = readMPInt(der, 'version');
111	assert.equal(ver[0], 0x0, 'unknown RSA private key version');
112
113	// modulus then public exponent
114	var n = readMPInt(der, 'modulus');
115	var e = readMPInt(der, 'public exponent');
116	var d = readMPInt(der, 'private exponent');
117	var p = readMPInt(der, 'prime1');
118	var q = readMPInt(der, 'prime2');
119	var dmodp = readMPInt(der, 'exponent1');
120	var dmodq = readMPInt(der, 'exponent2');
121	var iqmp = readMPInt(der, 'iqmp');
122
123	// now, make the key
124	var key = {
125		type: 'rsa',
126		parts: [
127			{ name: 'n', data: n },
128			{ name: 'e', data: e },
129			{ name: 'd', data: d },
130			{ name: 'iqmp', data: iqmp },
131			{ name: 'p', data: p },
132			{ name: 'q', data: q },
133			{ name: 'dmodp', data: dmodp },
134			{ name: 'dmodq', data: dmodq }
135		]
136	};
137
138	return (new PrivateKey(key));
139}
140
141function readPkcs8DSAPublic(der) {
142	der.readSequence();
143
144	var p = readMPInt(der, 'p');
145	var q = readMPInt(der, 'q');
146	var g = readMPInt(der, 'g');
147
148	// bit string sequence
149	der.readSequence(asn1.Ber.BitString);
150	der.readByte();
151
152	var y = readMPInt(der, 'y');
153
154	// now, make the key
155	var key = {
156		type: 'dsa',
157		parts: [
158			{ name: 'p', data: p },
159			{ name: 'q', data: q },
160			{ name: 'g', data: g },
161			{ name: 'y', data: y }
162		]
163	};
164
165	return (new Key(key));
166}
167
168function readPkcs8DSAPrivate(der) {
169	der.readSequence();
170
171	var p = readMPInt(der, 'p');
172	var q = readMPInt(der, 'q');
173	var g = readMPInt(der, 'g');
174
175	der.readSequence(asn1.Ber.OctetString);
176	var x = readMPInt(der, 'x');
177
178	/* The pkcs#8 format does not include the public key */
179	var y = utils.calculateDSAPublic(g, p, x);
180
181	var key = {
182		type: 'dsa',
183		parts: [
184			{ name: 'p', data: p },
185			{ name: 'q', data: q },
186			{ name: 'g', data: g },
187			{ name: 'y', data: y },
188			{ name: 'x', data: x }
189		]
190	};
191
192	return (new PrivateKey(key));
193}
194
195function readECDSACurve(der) {
196	var curveName, curveNames;
197	var j, c, cd;
198
199	if (der.peek() === asn1.Ber.OID) {
200		var oid = der.readOID();
201
202		curveNames = Object.keys(algs.curves);
203		for (j = 0; j < curveNames.length; ++j) {
204			c = curveNames[j];
205			cd = algs.curves[c];
206			if (cd.pkcs8oid === oid) {
207				curveName = c;
208				break;
209			}
210		}
211
212	} else {
213		// ECParameters sequence
214		der.readSequence();
215		var version = der.readString(asn1.Ber.Integer, true);
216		assert.strictEqual(version[0], 1, 'ECDSA key not version 1');
217
218		var curve = {};
219
220		// FieldID sequence
221		der.readSequence();
222		var fieldTypeOid = der.readOID();
223		assert.strictEqual(fieldTypeOid, '1.2.840.10045.1.1',
224		    'ECDSA key is not from a prime-field');
225		var p = curve.p = utils.mpNormalize(
226		    der.readString(asn1.Ber.Integer, true));
227		/*
228		 * p always starts with a 1 bit, so count the zeros to get its
229		 * real size.
230		 */
231		curve.size = p.length * 8 - utils.countZeros(p);
232
233		// Curve sequence
234		der.readSequence();
235		curve.a = utils.mpNormalize(
236		    der.readString(asn1.Ber.OctetString, true));
237		curve.b = utils.mpNormalize(
238		    der.readString(asn1.Ber.OctetString, true));
239		if (der.peek() === asn1.Ber.BitString)
240			curve.s = der.readString(asn1.Ber.BitString, true);
241
242		// Combined Gx and Gy
243		curve.G = der.readString(asn1.Ber.OctetString, true);
244		assert.strictEqual(curve.G[0], 0x4,
245		    'uncompressed G is required');
246
247		curve.n = utils.mpNormalize(
248		    der.readString(asn1.Ber.Integer, true));
249		curve.h = utils.mpNormalize(
250		    der.readString(asn1.Ber.Integer, true));
251		assert.strictEqual(curve.h[0], 0x1, 'a cofactor=1 curve is ' +
252		    'required');
253
254		curveNames = Object.keys(algs.curves);
255		var ks = Object.keys(curve);
256		for (j = 0; j < curveNames.length; ++j) {
257			c = curveNames[j];
258			cd = algs.curves[c];
259			var equal = true;
260			for (var i = 0; i < ks.length; ++i) {
261				var k = ks[i];
262				if (cd[k] === undefined)
263					continue;
264				if (typeof (cd[k]) === 'object' &&
265				    cd[k].equals !== undefined) {
266					if (!cd[k].equals(curve[k])) {
267						equal = false;
268						break;
269					}
270				} else if (Buffer.isBuffer(cd[k])) {
271					if (cd[k].toString('binary')
272					    !== curve[k].toString('binary')) {
273						equal = false;
274						break;
275					}
276				} else {
277					if (cd[k] !== curve[k]) {
278						equal = false;
279						break;
280					}
281				}
282			}
283			if (equal) {
284				curveName = c;
285				break;
286			}
287		}
288	}
289	return (curveName);
290}
291
292function readPkcs8ECDSAPrivate(der) {
293	var curveName = readECDSACurve(der);
294	assert.string(curveName, 'a known elliptic curve');
295
296	der.readSequence(asn1.Ber.OctetString);
297	der.readSequence();
298
299	var version = readMPInt(der, 'version');
300	assert.equal(version[0], 1, 'unknown version of ECDSA key');
301
302	var d = der.readString(asn1.Ber.OctetString, true);
303	der.readSequence(0xa1);
304
305	var Q = der.readString(asn1.Ber.BitString, true);
306	Q = utils.ecNormalize(Q);
307
308	var key = {
309		type: 'ecdsa',
310		parts: [
311			{ name: 'curve', data: Buffer.from(curveName) },
312			{ name: 'Q', data: Q },
313			{ name: 'd', data: d }
314		]
315	};
316
317	return (new PrivateKey(key));
318}
319
320function readPkcs8ECDSAPublic(der) {
321	var curveName = readECDSACurve(der);
322	assert.string(curveName, 'a known elliptic curve');
323
324	var Q = der.readString(asn1.Ber.BitString, true);
325	Q = utils.ecNormalize(Q);
326
327	var key = {
328		type: 'ecdsa',
329		parts: [
330			{ name: 'curve', data: Buffer.from(curveName) },
331			{ name: 'Q', data: Q }
332		]
333	};
334
335	return (new Key(key));
336}
337
338function readPkcs8EdDSAPublic(der) {
339	if (der.peek() === 0x00)
340		der.readByte();
341
342	var A = utils.readBitString(der);
343
344	var key = {
345		type: 'ed25519',
346		parts: [
347			{ name: 'A', data: utils.zeroPadToLength(A, 32) }
348		]
349	};
350
351	return (new Key(key));
352}
353
354function readPkcs8X25519Public(der) {
355	var A = utils.readBitString(der);
356
357	var key = {
358		type: 'curve25519',
359		parts: [
360			{ name: 'A', data: utils.zeroPadToLength(A, 32) }
361		]
362	};
363
364	return (new Key(key));
365}
366
367function readPkcs8EdDSAPrivate(der) {
368	if (der.peek() === 0x00)
369		der.readByte();
370
371	der.readSequence(asn1.Ber.OctetString);
372	var k = der.readString(asn1.Ber.OctetString, true);
373	k = utils.zeroPadToLength(k, 32);
374
375	var A;
376	if (der.peek() === asn1.Ber.BitString) {
377		A = utils.readBitString(der);
378		A = utils.zeroPadToLength(A, 32);
379	} else {
380		A = utils.calculateED25519Public(k);
381	}
382
383	var key = {
384		type: 'ed25519',
385		parts: [
386			{ name: 'A', data: utils.zeroPadToLength(A, 32) },
387			{ name: 'k', data: utils.zeroPadToLength(k, 32) }
388		]
389	};
390
391	return (new PrivateKey(key));
392}
393
394function readPkcs8X25519Private(der) {
395	if (der.peek() === 0x00)
396		der.readByte();
397
398	der.readSequence(asn1.Ber.OctetString);
399	var k = der.readString(asn1.Ber.OctetString, true);
400	k = utils.zeroPadToLength(k, 32);
401
402	var A = utils.calculateX25519Public(k);
403
404	var key = {
405		type: 'curve25519',
406		parts: [
407			{ name: 'A', data: utils.zeroPadToLength(A, 32) },
408			{ name: 'k', data: utils.zeroPadToLength(k, 32) }
409		]
410	};
411
412	return (new PrivateKey(key));
413}
414
415function writePkcs8(der, key) {
416	der.startSequence();
417
418	if (PrivateKey.isPrivateKey(key)) {
419		var sillyInt = Buffer.from([0]);
420		der.writeBuffer(sillyInt, asn1.Ber.Integer);
421	}
422
423	der.startSequence();
424	switch (key.type) {
425	case 'rsa':
426		der.writeOID('1.2.840.113549.1.1.1');
427		if (PrivateKey.isPrivateKey(key))
428			writePkcs8RSAPrivate(key, der);
429		else
430			writePkcs8RSAPublic(key, der);
431		break;
432	case 'dsa':
433		der.writeOID('1.2.840.10040.4.1');
434		if (PrivateKey.isPrivateKey(key))
435			writePkcs8DSAPrivate(key, der);
436		else
437			writePkcs8DSAPublic(key, der);
438		break;
439	case 'ecdsa':
440		der.writeOID('1.2.840.10045.2.1');
441		if (PrivateKey.isPrivateKey(key))
442			writePkcs8ECDSAPrivate(key, der);
443		else
444			writePkcs8ECDSAPublic(key, der);
445		break;
446	case 'ed25519':
447		der.writeOID('1.3.101.112');
448		if (PrivateKey.isPrivateKey(key))
449			throw (new Error('Ed25519 private keys in pkcs8 ' +
450			    'format are not supported'));
451		writePkcs8EdDSAPublic(key, der);
452		break;
453	default:
454		throw (new Error('Unsupported key type: ' + key.type));
455	}
456
457	der.endSequence();
458}
459
460function writePkcs8RSAPrivate(key, der) {
461	der.writeNull();
462	der.endSequence();
463
464	der.startSequence(asn1.Ber.OctetString);
465	der.startSequence();
466
467	var version = Buffer.from([0]);
468	der.writeBuffer(version, asn1.Ber.Integer);
469
470	der.writeBuffer(key.part.n.data, asn1.Ber.Integer);
471	der.writeBuffer(key.part.e.data, asn1.Ber.Integer);
472	der.writeBuffer(key.part.d.data, asn1.Ber.Integer);
473	der.writeBuffer(key.part.p.data, asn1.Ber.Integer);
474	der.writeBuffer(key.part.q.data, asn1.Ber.Integer);
475	if (!key.part.dmodp || !key.part.dmodq)
476		utils.addRSAMissing(key);
477	der.writeBuffer(key.part.dmodp.data, asn1.Ber.Integer);
478	der.writeBuffer(key.part.dmodq.data, asn1.Ber.Integer);
479	der.writeBuffer(key.part.iqmp.data, asn1.Ber.Integer);
480
481	der.endSequence();
482	der.endSequence();
483}
484
485function writePkcs8RSAPublic(key, der) {
486	der.writeNull();
487	der.endSequence();
488
489	der.startSequence(asn1.Ber.BitString);
490	der.writeByte(0x00);
491
492	der.startSequence();
493	der.writeBuffer(key.part.n.data, asn1.Ber.Integer);
494	der.writeBuffer(key.part.e.data, asn1.Ber.Integer);
495	der.endSequence();
496
497	der.endSequence();
498}
499
500function writePkcs8DSAPrivate(key, der) {
501	der.startSequence();
502	der.writeBuffer(key.part.p.data, asn1.Ber.Integer);
503	der.writeBuffer(key.part.q.data, asn1.Ber.Integer);
504	der.writeBuffer(key.part.g.data, asn1.Ber.Integer);
505	der.endSequence();
506
507	der.endSequence();
508
509	der.startSequence(asn1.Ber.OctetString);
510	der.writeBuffer(key.part.x.data, asn1.Ber.Integer);
511	der.endSequence();
512}
513
514function writePkcs8DSAPublic(key, der) {
515	der.startSequence();
516	der.writeBuffer(key.part.p.data, asn1.Ber.Integer);
517	der.writeBuffer(key.part.q.data, asn1.Ber.Integer);
518	der.writeBuffer(key.part.g.data, asn1.Ber.Integer);
519	der.endSequence();
520	der.endSequence();
521
522	der.startSequence(asn1.Ber.BitString);
523	der.writeByte(0x00);
524	der.writeBuffer(key.part.y.data, asn1.Ber.Integer);
525	der.endSequence();
526}
527
528function writeECDSACurve(key, der) {
529	var curve = algs.curves[key.curve];
530	if (curve.pkcs8oid) {
531		/* This one has a name in pkcs#8, so just write the oid */
532		der.writeOID(curve.pkcs8oid);
533
534	} else {
535		// ECParameters sequence
536		der.startSequence();
537
538		var version = Buffer.from([1]);
539		der.writeBuffer(version, asn1.Ber.Integer);
540
541		// FieldID sequence
542		der.startSequence();
543		der.writeOID('1.2.840.10045.1.1'); // prime-field
544		der.writeBuffer(curve.p, asn1.Ber.Integer);
545		der.endSequence();
546
547		// Curve sequence
548		der.startSequence();
549		var a = curve.p;
550		if (a[0] === 0x0)
551			a = a.slice(1);
552		der.writeBuffer(a, asn1.Ber.OctetString);
553		der.writeBuffer(curve.b, asn1.Ber.OctetString);
554		der.writeBuffer(curve.s, asn1.Ber.BitString);
555		der.endSequence();
556
557		der.writeBuffer(curve.G, asn1.Ber.OctetString);
558		der.writeBuffer(curve.n, asn1.Ber.Integer);
559		var h = curve.h;
560		if (!h) {
561			h = Buffer.from([1]);
562		}
563		der.writeBuffer(h, asn1.Ber.Integer);
564
565		// ECParameters
566		der.endSequence();
567	}
568}
569
570function writePkcs8ECDSAPublic(key, der) {
571	writeECDSACurve(key, der);
572	der.endSequence();
573
574	var Q = utils.ecNormalize(key.part.Q.data, true);
575	der.writeBuffer(Q, asn1.Ber.BitString);
576}
577
578function writePkcs8ECDSAPrivate(key, der) {
579	writeECDSACurve(key, der);
580	der.endSequence();
581
582	der.startSequence(asn1.Ber.OctetString);
583	der.startSequence();
584
585	var version = Buffer.from([1]);
586	der.writeBuffer(version, asn1.Ber.Integer);
587
588	der.writeBuffer(key.part.d.data, asn1.Ber.OctetString);
589
590	der.startSequence(0xa1);
591	var Q = utils.ecNormalize(key.part.Q.data, true);
592	der.writeBuffer(Q, asn1.Ber.BitString);
593	der.endSequence();
594
595	der.endSequence();
596	der.endSequence();
597}
598
599function writePkcs8EdDSAPublic(key, der) {
600	der.endSequence();
601
602	utils.writeBitString(der, key.part.A.data);
603}
604
605function writePkcs8EdDSAPrivate(key, der) {
606	der.endSequence();
607
608	var k = utils.mpNormalize(key.part.k.data, true);
609	der.startSequence(asn1.Ber.OctetString);
610	der.writeBuffer(k, asn1.Ber.OctetString);
611	der.endSequence();
612}
613