Initial commit
[yaffs-website] / node_modules / sshpk / lib / formats / pkcs8.js
1 // Copyright 2015 Joyent, Inc.
2
3 module.exports = {
4         read: read,
5         readPkcs8: readPkcs8,
6         write: write,
7         writePkcs8: writePkcs8,
8
9         readECDSACurve: readECDSACurve,
10         writeECDSACurve: writeECDSACurve
11 };
12
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');
20
21 function read(buf, options) {
22         return (pem.read(buf, options, 'pkcs8'));
23 }
24
25 function write(key, options) {
26         return (pem.write(key, options, 'pkcs8'));
27 }
28
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)));
34 }
35
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);
42         }
43
44         der.readSequence();
45         var next = der.offset + der.length;
46
47         var oid = der.readOID();
48         switch (oid) {
49         case '1.2.840.113549.1.1.1':
50                 der._offset = next;
51                 if (type === 'public')
52                         return (readPkcs8RSAPublic(der));
53                 else
54                         return (readPkcs8RSAPrivate(der));
55         case '1.2.840.10040.4.1':
56                 if (type === 'public')
57                         return (readPkcs8DSAPublic(der));
58                 else
59                         return (readPkcs8DSAPrivate(der));
60         case '1.2.840.10045.2.1':
61                 if (type === 'public')
62                         return (readPkcs8ECDSAPublic(der));
63                 else
64                         return (readPkcs8ECDSAPrivate(der));
65         default:
66                 throw (new Error('Unknown key type OID ' + oid));
67         }
68 }
69
70 function readPkcs8RSAPublic(der) {
71         // bit string sequence
72         der.readSequence(asn1.Ber.BitString);
73         der.readByte();
74         der.readSequence();
75
76         // modulus
77         var n = readMPInt(der, 'modulus');
78         var e = readMPInt(der, 'exponent');
79
80         // now, make the key
81         var key = {
82                 type: 'rsa',
83                 source: der.originalInput,
84                 parts: [
85                         { name: 'e', data: e },
86                         { name: 'n', data: n }
87                 ]
88         };
89
90         return (new Key(key));
91 }
92
93 function readPkcs8RSAPrivate(der) {
94         der.readSequence(asn1.Ber.OctetString);
95         der.readSequence();
96
97         var ver = readMPInt(der, 'version');
98         assert.equal(ver[0], 0x0, 'unknown RSA private key version');
99
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');
109
110         // now, make the key
111         var key = {
112                 type: 'rsa',
113                 parts: [
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 }
122                 ]
123         };
124
125         return (new PrivateKey(key));
126 }
127
128 function readPkcs8DSAPublic(der) {
129         der.readSequence();
130
131         var p = readMPInt(der, 'p');
132         var q = readMPInt(der, 'q');
133         var g = readMPInt(der, 'g');
134
135         // bit string sequence
136         der.readSequence(asn1.Ber.BitString);
137         der.readByte();
138
139         var y = readMPInt(der, 'y');
140
141         // now, make the key
142         var key = {
143                 type: 'dsa',
144                 parts: [
145                         { name: 'p', data: p },
146                         { name: 'q', data: q },
147                         { name: 'g', data: g },
148                         { name: 'y', data: y }
149                 ]
150         };
151
152         return (new Key(key));
153 }
154
155 function readPkcs8DSAPrivate(der) {
156         der.readSequence();
157
158         var p = readMPInt(der, 'p');
159         var q = readMPInt(der, 'q');
160         var g = readMPInt(der, 'g');
161
162         der.readSequence(asn1.Ber.OctetString);
163         var x = readMPInt(der, 'x');
164
165         /* The pkcs#8 format does not include the public key */
166         var y = utils.calculateDSAPublic(g, p, x);
167
168         var key = {
169                 type: 'dsa',
170                 parts: [
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 }
176                 ]
177         };
178
179         return (new PrivateKey(key));
180 }
181
182 function readECDSACurve(der) {
183         var curveName, curveNames;
184         var j, c, cd;
185
186         if (der.peek() === asn1.Ber.OID) {
187                 var oid = der.readOID();
188
189                 curveNames = Object.keys(algs.curves);
190                 for (j = 0; j < curveNames.length; ++j) {
191                         c = curveNames[j];
192                         cd = algs.curves[c];
193                         if (cd.pkcs8oid === oid) {
194                                 curveName = c;
195                                 break;
196                         }
197                 }
198
199         } else {
200                 // ECParameters sequence
201                 der.readSequence();
202                 var version = der.readString(asn1.Ber.Integer, true);
203                 assert.strictEqual(version[0], 1, 'ECDSA key not version 1');
204
205                 var curve = {};
206
207                 // FieldID sequence
208                 der.readSequence();
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));
214                 /*
215                  * p always starts with a 1 bit, so count the zeros to get its
216                  * real size.
217                  */
218                 curve.size = p.length * 8 - utils.countZeros(p);
219
220                 // Curve sequence
221                 der.readSequence();
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);
228
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');
233
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 ' +
239                     'required');
240
241                 curveNames = Object.keys(algs.curves);
242                 var ks = Object.keys(curve);
243                 for (j = 0; j < curveNames.length; ++j) {
244                         c = curveNames[j];
245                         cd = algs.curves[c];
246                         var equal = true;
247                         for (var i = 0; i < ks.length; ++i) {
248                                 var k = ks[i];
249                                 if (cd[k] === undefined)
250                                         continue;
251                                 if (typeof (cd[k]) === 'object' &&
252                                     cd[k].equals !== undefined) {
253                                         if (!cd[k].equals(curve[k])) {
254                                                 equal = false;
255                                                 break;
256                                         }
257                                 } else if (Buffer.isBuffer(cd[k])) {
258                                         if (cd[k].toString('binary')
259                                             !== curve[k].toString('binary')) {
260                                                 equal = false;
261                                                 break;
262                                         }
263                                 } else {
264                                         if (cd[k] !== curve[k]) {
265                                                 equal = false;
266                                                 break;
267                                         }
268                                 }
269                         }
270                         if (equal) {
271                                 curveName = c;
272                                 break;
273                         }
274                 }
275         }
276         return (curveName);
277 }
278
279 function readPkcs8ECDSAPrivate(der) {
280         var curveName = readECDSACurve(der);
281         assert.string(curveName, 'a known elliptic curve');
282
283         der.readSequence(asn1.Ber.OctetString);
284         der.readSequence();
285
286         var version = readMPInt(der, 'version');
287         assert.equal(version[0], 1, 'unknown version of ECDSA key');
288
289         var d = der.readString(asn1.Ber.OctetString, true);
290         der.readSequence(0xa1);
291
292         var Q = der.readString(asn1.Ber.BitString, true);
293         Q = utils.ecNormalize(Q);
294
295         var key = {
296                 type: 'ecdsa',
297                 parts: [
298                         { name: 'curve', data: new Buffer(curveName) },
299                         { name: 'Q', data: Q },
300                         { name: 'd', data: d }
301                 ]
302         };
303
304         return (new PrivateKey(key));
305 }
306
307 function readPkcs8ECDSAPublic(der) {
308         var curveName = readECDSACurve(der);
309         assert.string(curveName, 'a known elliptic curve');
310
311         var Q = der.readString(asn1.Ber.BitString, true);
312         Q = utils.ecNormalize(Q);
313
314         var key = {
315                 type: 'ecdsa',
316                 parts: [
317                         { name: 'curve', data: new Buffer(curveName) },
318                         { name: 'Q', data: Q }
319                 ]
320         };
321
322         return (new Key(key));
323 }
324
325 function writePkcs8(der, key) {
326         der.startSequence();
327
328         if (PrivateKey.isPrivateKey(key)) {
329                 var sillyInt = new Buffer(1);
330                 sillyInt[0] = 0x0;
331                 der.writeBuffer(sillyInt, asn1.Ber.Integer);
332         }
333
334         der.startSequence();
335         switch (key.type) {
336         case 'rsa':
337                 der.writeOID('1.2.840.113549.1.1.1');
338                 if (PrivateKey.isPrivateKey(key))
339                         writePkcs8RSAPrivate(key, der);
340                 else
341                         writePkcs8RSAPublic(key, der);
342                 break;
343         case 'dsa':
344                 der.writeOID('1.2.840.10040.4.1');
345                 if (PrivateKey.isPrivateKey(key))
346                         writePkcs8DSAPrivate(key, der);
347                 else
348                         writePkcs8DSAPublic(key, der);
349                 break;
350         case 'ecdsa':
351                 der.writeOID('1.2.840.10045.2.1');
352                 if (PrivateKey.isPrivateKey(key))
353                         writePkcs8ECDSAPrivate(key, der);
354                 else
355                         writePkcs8ECDSAPublic(key, der);
356                 break;
357         default:
358                 throw (new Error('Unsupported key type: ' + key.type));
359         }
360
361         der.endSequence();
362 }
363
364 function writePkcs8RSAPrivate(key, der) {
365         der.writeNull();
366         der.endSequence();
367
368         der.startSequence(asn1.Ber.OctetString);
369         der.startSequence();
370
371         var version = new Buffer(1);
372         version[0] = 0;
373         der.writeBuffer(version, asn1.Ber.Integer);
374
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);
385
386         der.endSequence();
387         der.endSequence();
388 }
389
390 function writePkcs8RSAPublic(key, der) {
391         der.writeNull();
392         der.endSequence();
393
394         der.startSequence(asn1.Ber.BitString);
395         der.writeByte(0x00);
396
397         der.startSequence();
398         der.writeBuffer(key.part.n.data, asn1.Ber.Integer);
399         der.writeBuffer(key.part.e.data, asn1.Ber.Integer);
400         der.endSequence();
401
402         der.endSequence();
403 }
404
405 function writePkcs8DSAPrivate(key, der) {
406         der.startSequence();
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);
410         der.endSequence();
411
412         der.endSequence();
413
414         der.startSequence(asn1.Ber.OctetString);
415         der.writeBuffer(key.part.x.data, asn1.Ber.Integer);
416         der.endSequence();
417 }
418
419 function writePkcs8DSAPublic(key, der) {
420         der.startSequence();
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);
424         der.endSequence();
425         der.endSequence();
426
427         der.startSequence(asn1.Ber.BitString);
428         der.writeByte(0x00);
429         der.writeBuffer(key.part.y.data, asn1.Ber.Integer);
430         der.endSequence();
431 }
432
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);
438
439         } else {
440                 // ECParameters sequence
441                 der.startSequence();
442
443                 var version = new Buffer(1);
444                 version.writeUInt8(1, 0);
445                 der.writeBuffer(version, asn1.Ber.Integer);
446
447                 // FieldID sequence
448                 der.startSequence();
449                 der.writeOID('1.2.840.10045.1.1'); // prime-field
450                 der.writeBuffer(curve.p, asn1.Ber.Integer);
451                 der.endSequence();
452
453                 // Curve sequence
454                 der.startSequence();
455                 var a = curve.p;
456                 if (a[0] === 0x0)
457                         a = a.slice(1);
458                 der.writeBuffer(a, asn1.Ber.OctetString);
459                 der.writeBuffer(curve.b, asn1.Ber.OctetString);
460                 der.writeBuffer(curve.s, asn1.Ber.BitString);
461                 der.endSequence();
462
463                 der.writeBuffer(curve.G, asn1.Ber.OctetString);
464                 der.writeBuffer(curve.n, asn1.Ber.Integer);
465                 var h = curve.h;
466                 if (!h) {
467                         h = new Buffer(1);
468                         h[0] = 1;
469                 }
470                 der.writeBuffer(h, asn1.Ber.Integer);
471
472                 // ECParameters
473                 der.endSequence();
474         }
475 }
476
477 function writePkcs8ECDSAPublic(key, der) {
478         writeECDSACurve(key, der);
479         der.endSequence();
480
481         var Q = utils.ecNormalize(key.part.Q.data, true);
482         der.writeBuffer(Q, asn1.Ber.BitString);
483 }
484
485 function writePkcs8ECDSAPrivate(key, der) {
486         writeECDSACurve(key, der);
487         der.endSequence();
488
489         der.startSequence(asn1.Ber.OctetString);
490         der.startSequence();
491
492         var version = new Buffer(1);
493         version[0] = 1;
494         der.writeBuffer(version, asn1.Ber.Integer);
495
496         der.writeBuffer(key.part.d.data, asn1.Ber.OctetString);
497
498         der.startSequence(0xa1);
499         var Q = utils.ecNormalize(key.part.Q.data, true);
500         der.writeBuffer(Q, asn1.Ber.BitString);
501         der.endSequence();
502
503         der.endSequence();
504         der.endSequence();
505 }