1sshpk
2=========
3
4Parse, convert, fingerprint and use SSH keys (both public and private) in pure
5node -- no `ssh-keygen` or other external dependencies.
6
7Supports RSA, DSA, ECDSA (nistp-\*) and ED25519 key types, in PEM (PKCS#1,
8PKCS#8) and OpenSSH formats.
9
10This library has been extracted from
11[`node-http-signature`](https://github.com/joyent/node-http-signature)
12(work by [Mark Cavage](https://github.com/mcavage) and
13[Dave Eddy](https://github.com/bahamas10)) and
14[`node-ssh-fingerprint`](https://github.com/bahamas10/node-ssh-fingerprint)
15(work by Dave Eddy), with additions (including ECDSA support) by
16[Alex Wilson](https://github.com/arekinath).
17
18Install
19-------
20
21```
22npm install sshpk
23```
24
25Examples
26--------
27
28```js
29var sshpk = require('sshpk');
30
31var fs = require('fs');
32
33/* Read in an OpenSSH-format public key */
34var keyPub = fs.readFileSync('id_rsa.pub');
35var key = sshpk.parseKey(keyPub, 'ssh');
36
37/* Get metadata about the key */
38console.log('type => %s', key.type);
39console.log('size => %d bits', key.size);
40console.log('comment => %s', key.comment);
41
42/* Compute key fingerprints, in new OpenSSH (>6.7) format, and old MD5 */
43console.log('fingerprint => %s', key.fingerprint().toString());
44console.log('old-style fingerprint => %s', key.fingerprint('md5').toString());
45```
46
47Example output:
48
49```
50type => rsa
51size => 2048 bits
52comment => foo@foo.com
53fingerprint => SHA256:PYC9kPVC6J873CSIbfp0LwYeczP/W4ffObNCuDJ1u5w
54old-style fingerprint => a0:c8:ad:6c:32:9a:32:fa:59:cc:a9:8c:0a:0d:6e:bd
55```
56
57More examples: converting between formats:
58
59```js
60/* Read in a PEM public key */
61var keyPem = fs.readFileSync('id_rsa.pem');
62var key = sshpk.parseKey(keyPem, 'pem');
63
64/* Convert to PEM PKCS#8 public key format */
65var pemBuf = key.toBuffer('pkcs8');
66
67/* Convert to SSH public key format (and return as a string) */
68var sshKey = key.toString('ssh');
69```
70
71Signing and verifying:
72
73```js
74/* Read in an OpenSSH/PEM *private* key */
75var keyPriv = fs.readFileSync('id_ecdsa');
76var key = sshpk.parsePrivateKey(keyPriv, 'pem');
77
78var data = 'some data';
79
80/* Sign some data with the key */
81var s = key.createSign('sha1');
82s.update(data);
83var signature = s.sign();
84
85/* Now load the public key (could also use just key.toPublic()) */
86var keyPub = fs.readFileSync('id_ecdsa.pub');
87key = sshpk.parseKey(keyPub, 'ssh');
88
89/* Make a crypto.Verifier with this key */
90var v = key.createVerify('sha1');
91v.update(data);
92var valid = v.verify(signature);
93/* => true! */
94```
95
96Matching fingerprints with keys:
97
98```js
99var fp = sshpk.parseFingerprint('SHA256:PYC9kPVC6J873CSIbfp0LwYeczP/W4ffObNCuDJ1u5w');
100
101var keys = [sshpk.parseKey(...), sshpk.parseKey(...), ...];
102
103keys.forEach(function (key) {
104	if (fp.matches(key))
105		console.log('found it!');
106});
107```
108
109Usage
110-----
111
112## Public keys
113
114### `parseKey(data[, format = 'auto'[, options]])`
115
116Parses a key from a given data format and returns a new `Key` object.
117
118Parameters
119
120- `data` -- Either a Buffer or String, containing the key
121- `format` -- String name of format to use, valid options are:
122  - `auto`: choose automatically from all below
123  - `pem`: supports both PKCS#1 and PKCS#8
124  - `ssh`: standard OpenSSH format,
125  - `pkcs1`, `pkcs8`: variants of `pem`
126  - `rfc4253`: raw OpenSSH wire format
127  - `openssh`: new post-OpenSSH 6.5 internal format, produced by
128               `ssh-keygen -o`
129- `options` -- Optional Object, extra options, with keys:
130  - `filename` -- Optional String, name for the key being parsed
131                  (eg. the filename that was opened). Used to generate
132                  Error messages
133  - `passphrase` -- Optional String, encryption passphrase used to decrypt an
134                    encrypted PEM file
135
136### `Key.isKey(obj)`
137
138Returns `true` if the given object is a valid `Key` object created by a version
139of `sshpk` compatible with this one.
140
141Parameters
142
143- `obj` -- Object to identify
144
145### `Key#type`
146
147String, the type of key. Valid options are `rsa`, `dsa`, `ecdsa`.
148
149### `Key#size`
150
151Integer, "size" of the key in bits. For RSA/DSA this is the size of the modulus;
152for ECDSA this is the bit size of the curve in use.
153
154### `Key#comment`
155
156Optional string, a key comment used by some formats (eg the `ssh` format).
157
158### `Key#curve`
159
160Only present if `this.type === 'ecdsa'`, string containing the name of the
161named curve used with this key. Possible values include `nistp256`, `nistp384`
162and `nistp521`.
163
164### `Key#toBuffer([format = 'ssh'])`
165
166Convert the key into a given data format and return the serialized key as
167a Buffer.
168
169Parameters
170
171- `format` -- String name of format to use, for valid options see `parseKey()`
172
173### `Key#toString([format = 'ssh])`
174
175Same as `this.toBuffer(format).toString()`.
176
177### `Key#fingerprint([algorithm = 'sha256'])`
178
179Creates a new `Fingerprint` object representing this Key's fingerprint.
180
181Parameters
182
183- `algorithm` -- String name of hash algorithm to use, valid options are `md5`,
184                 `sha1`, `sha256`, `sha384`, `sha512`
185
186### `Key#createVerify([hashAlgorithm])`
187
188Creates a `crypto.Verifier` specialized to use this Key (and the correct public
189key algorithm to match it). The returned Verifier has the same API as a regular
190one, except that the `verify()` function takes only the target signature as an
191argument.
192
193Parameters
194
195- `hashAlgorithm` -- optional String name of hash algorithm to use, any
196                     supported by OpenSSL are valid, usually including
197                     `sha1`, `sha256`.
198
199`v.verify(signature[, format])` Parameters
200
201- `signature` -- either a Signature object, or a Buffer or String
202- `format` -- optional String, name of format to interpret given String with.
203              Not valid if `signature` is a Signature or Buffer.
204
205### `Key#createDiffieHellman()`
206### `Key#createDH()`
207
208Creates a Diffie-Hellman key exchange object initialized with this key and all
209necessary parameters. This has the same API as a `crypto.DiffieHellman`
210instance, except that functions take `Key` and `PrivateKey` objects as
211arguments, and return them where indicated for.
212
213This is only valid for keys belonging to a cryptosystem that supports DHE
214or a close analogue (i.e. `dsa`, `ecdsa` and `curve25519` keys). An attempt
215to call this function on other keys will yield an `Error`.
216
217## Private keys
218
219### `parsePrivateKey(data[, format = 'auto'[, options]])`
220
221Parses a private key from a given data format and returns a new
222`PrivateKey` object.
223
224Parameters
225
226- `data` -- Either a Buffer or String, containing the key
227- `format` -- String name of format to use, valid options are:
228  - `auto`: choose automatically from all below
229  - `pem`: supports both PKCS#1 and PKCS#8
230  - `ssh`, `openssh`: new post-OpenSSH 6.5 internal format, produced by
231                      `ssh-keygen -o`
232  - `pkcs1`, `pkcs8`: variants of `pem`
233  - `rfc4253`: raw OpenSSH wire format
234- `options` -- Optional Object, extra options, with keys:
235  - `filename` -- Optional String, name for the key being parsed
236                  (eg. the filename that was opened). Used to generate
237                  Error messages
238  - `passphrase` -- Optional String, encryption passphrase used to decrypt an
239                    encrypted PEM file
240
241### `generatePrivateKey(type[, options])`
242
243Generates a new private key of a certain key type, from random data.
244
245Parameters
246
247- `type` -- String, type of key to generate. Currently supported are `'ecdsa'`
248            and `'ed25519'`
249- `options` -- optional Object, with keys:
250  - `curve` -- optional String, for `'ecdsa'` keys, specifies the curve to use.
251               If ECDSA is specified and this option is not given, defaults to
252               using `'nistp256'`.
253
254### `PrivateKey.isPrivateKey(obj)`
255
256Returns `true` if the given object is a valid `PrivateKey` object created by a
257version of `sshpk` compatible with this one.
258
259Parameters
260
261- `obj` -- Object to identify
262
263### `PrivateKey#type`
264
265String, the type of key. Valid options are `rsa`, `dsa`, `ecdsa`.
266
267### `PrivateKey#size`
268
269Integer, "size" of the key in bits. For RSA/DSA this is the size of the modulus;
270for ECDSA this is the bit size of the curve in use.
271
272### `PrivateKey#curve`
273
274Only present if `this.type === 'ecdsa'`, string containing the name of the
275named curve used with this key. Possible values include `nistp256`, `nistp384`
276and `nistp521`.
277
278### `PrivateKey#toBuffer([format = 'pkcs1'])`
279
280Convert the key into a given data format and return the serialized key as
281a Buffer.
282
283Parameters
284
285- `format` -- String name of format to use, valid options are listed under
286              `parsePrivateKey`. Note that ED25519 keys default to `openssh`
287              format instead (as they have no `pkcs1` representation).
288
289### `PrivateKey#toString([format = 'pkcs1'])`
290
291Same as `this.toBuffer(format).toString()`.
292
293### `PrivateKey#toPublic()`
294
295Extract just the public part of this private key, and return it as a `Key`
296object.
297
298### `PrivateKey#fingerprint([algorithm = 'sha256'])`
299
300Same as `this.toPublic().fingerprint()`.
301
302### `PrivateKey#createVerify([hashAlgorithm])`
303
304Same as `this.toPublic().createVerify()`.
305
306### `PrivateKey#createSign([hashAlgorithm])`
307
308Creates a `crypto.Sign` specialized to use this PrivateKey (and the correct
309key algorithm to match it). The returned Signer has the same API as a regular
310one, except that the `sign()` function takes no arguments, and returns a
311`Signature` object.
312
313Parameters
314
315- `hashAlgorithm` -- optional String name of hash algorithm to use, any
316                     supported by OpenSSL are valid, usually including
317                     `sha1`, `sha256`.
318
319`v.sign()` Parameters
320
321- none
322
323### `PrivateKey#derive(newType)`
324
325Derives a related key of type `newType` from this key. Currently this is
326only supported to change between `ed25519` and `curve25519` keys which are
327stored with the same private key (but usually distinct public keys in order
328to avoid degenerate keys that lead to a weak Diffie-Hellman exchange).
329
330Parameters
331
332- `newType` -- String, type of key to derive, either `ed25519` or `curve25519`
333
334## Fingerprints
335
336### `parseFingerprint(fingerprint[, algorithms])`
337
338Pre-parses a fingerprint, creating a `Fingerprint` object that can be used to
339quickly locate a key by using the `Fingerprint#matches` function.
340
341Parameters
342
343- `fingerprint` -- String, the fingerprint value, in any supported format
344- `algorithms` -- Optional list of strings, names of hash algorithms to limit
345                  support to. If `fingerprint` uses a hash algorithm not on
346                  this list, throws `InvalidAlgorithmError`.
347
348### `Fingerprint.isFingerprint(obj)`
349
350Returns `true` if the given object is a valid `Fingerprint` object created by a
351version of `sshpk` compatible with this one.
352
353Parameters
354
355- `obj` -- Object to identify
356
357### `Fingerprint#toString([format])`
358
359Returns a fingerprint as a string, in the given format.
360
361Parameters
362
363- `format` -- Optional String, format to use, valid options are `hex` and
364              `base64`. If this `Fingerprint` uses the `md5` algorithm, the
365              default format is `hex`. Otherwise, the default is `base64`.
366
367### `Fingerprint#matches(key)`
368
369Verifies whether or not this `Fingerprint` matches a given `Key`. This function
370uses double-hashing to avoid leaking timing information. Returns a boolean.
371
372Parameters
373
374- `key` -- a `Key` object, the key to match this fingerprint against
375
376## Signatures
377
378### `parseSignature(signature, algorithm, format)`
379
380Parses a signature in a given format, creating a `Signature` object. Useful
381for converting between the SSH and ASN.1 (PKCS/OpenSSL) signature formats, and
382also returned as output from `PrivateKey#createSign().sign()`.
383
384A Signature object can also be passed to a verifier produced by
385`Key#createVerify()` and it will automatically be converted internally into the
386correct format for verification.
387
388Parameters
389
390- `signature` -- a Buffer (binary) or String (base64), data of the actual
391                 signature in the given format
392- `algorithm` -- a String, name of the algorithm to be used, possible values
393                 are `rsa`, `dsa`, `ecdsa`
394- `format` -- a String, either `asn1` or `ssh`
395
396### `Signature.isSignature(obj)`
397
398Returns `true` if the given object is a valid `Signature` object created by a
399version of `sshpk` compatible with this one.
400
401Parameters
402
403- `obj` -- Object to identify
404
405### `Signature#toBuffer([format = 'asn1'])`
406
407Converts a Signature to the given format and returns it as a Buffer.
408
409Parameters
410
411- `format` -- a String, either `asn1` or `ssh`
412
413### `Signature#toString([format = 'asn1'])`
414
415Same as `this.toBuffer(format).toString('base64')`.
416
417## Certificates
418
419`sshpk` includes basic support for parsing certificates in X.509 (PEM) format
420and the OpenSSH certificate format. This feature is intended to be used mainly
421to access basic metadata about certificates, extract public keys from them, and
422also to generate simple self-signed certificates from an existing key.
423
424Notably, there is no implementation of CA chain-of-trust verification, and only
425very minimal support for key usage restrictions. Please do the security world
426a favour, and DO NOT use this code for certificate verification in the
427traditional X.509 CA chain style.
428
429### `parseCertificate(data, format)`
430
431Parameters
432
433 - `data` -- a Buffer or String
434 - `format` -- a String, format to use, one of `'openssh'`, `'pem'` (X.509 in a
435               PEM wrapper), or `'x509'` (raw DER encoded)
436
437### `createSelfSignedCertificate(subject, privateKey[, options])`
438
439Parameters
440
441 - `subject` -- an Identity, the subject of the certificate
442 - `privateKey` -- a PrivateKey, the key of the subject: will be used both to be
443                   placed in the certificate and also to sign it (since this is
444                   a self-signed certificate)
445 - `options` -- optional Object, with keys:
446   - `lifetime` -- optional Number, lifetime of the certificate from now in
447                   seconds
448   - `validFrom`, `validUntil` -- optional Dates, beginning and end of
449                                  certificate validity period. If given
450                                  `lifetime` will be ignored
451   - `serial` -- optional Buffer, the serial number of the certificate
452   - `purposes` -- optional Array of String, X.509 key usage restrictions
453
454### `createCertificate(subject, key, issuer, issuerKey[, options])`
455
456Parameters
457
458 - `subject` -- an Identity, the subject of the certificate
459 - `key` -- a Key, the public key of the subject
460 - `issuer` -- an Identity, the issuer of the certificate who will sign it
461 - `issuerKey` -- a PrivateKey, the issuer's private key for signing
462 - `options` -- optional Object, with keys:
463   - `lifetime` -- optional Number, lifetime of the certificate from now in
464                   seconds
465   - `validFrom`, `validUntil` -- optional Dates, beginning and end of
466                                  certificate validity period. If given
467                                  `lifetime` will be ignored
468   - `serial` -- optional Buffer, the serial number of the certificate
469   - `purposes` -- optional Array of String, X.509 key usage restrictions
470
471### `Certificate#subjects`
472
473Array of `Identity` instances describing the subject of this certificate.
474
475### `Certificate#issuer`
476
477The `Identity` of the Certificate's issuer (signer).
478
479### `Certificate#subjectKey`
480
481The public key of the subject of the certificate, as a `Key` instance.
482
483### `Certificate#issuerKey`
484
485The public key of the signing issuer of this certificate, as a `Key` instance.
486May be `undefined` if the issuer's key is unknown (e.g. on an X509 certificate).
487
488### `Certificate#serial`
489
490The serial number of the certificate. As this is normally a 64-bit or wider
491integer, it is returned as a Buffer.
492
493### `Certificate#purposes`
494
495Array of Strings indicating the X.509 key usage purposes that this certificate
496is valid for. The possible strings at the moment are:
497
498 * `'signature'` -- key can be used for digital signatures
499 * `'identity'` -- key can be used to attest about the identity of the signer
500                   (X.509 calls this `nonRepudiation`)
501 * `'codeSigning'` -- key can be used to sign executable code
502 * `'keyEncryption'` -- key can be used to encrypt other keys
503 * `'encryption'` -- key can be used to encrypt data (only applies for RSA)
504 * `'keyAgreement'` -- key can be used for key exchange protocols such as
505                       Diffie-Hellman
506 * `'ca'` -- key can be used to sign other certificates (is a Certificate
507             Authority)
508 * `'crl'` -- key can be used to sign Certificate Revocation Lists (CRLs)
509
510### `Certificate#isExpired([when])`
511
512Tests whether the Certificate is currently expired (i.e. the `validFrom` and
513`validUntil` dates specify a range of time that does not include the current
514time).
515
516Parameters
517
518 - `when` -- optional Date, if specified, tests whether the Certificate was or
519             will be expired at the specified time instead of now
520
521Returns a Boolean.
522
523### `Certificate#isSignedByKey(key)`
524
525Tests whether the Certificate was validly signed by the given (public) Key.
526
527Parameters
528
529 - `key` -- a Key instance
530
531Returns a Boolean.
532
533### `Certificate#isSignedBy(certificate)`
534
535Tests whether this Certificate was validly signed by the subject of the given
536certificate. Also tests that the issuer Identity of this Certificate and the
537subject Identity of the other Certificate are equivalent.
538
539Parameters
540
541 - `certificate` -- another Certificate instance
542
543Returns a Boolean.
544
545### `Certificate#fingerprint([hashAlgo])`
546
547Returns the X509-style fingerprint of the entire certificate (as a Fingerprint
548instance). This matches what a web-browser or similar would display as the
549certificate fingerprint and should not be confused with the fingerprint of the
550subject's public key.
551
552Parameters
553
554 - `hashAlgo` -- an optional String, any hash function name
555
556### `Certificate#toBuffer([format])`
557
558Serializes the Certificate to a Buffer and returns it.
559
560Parameters
561
562 - `format` -- an optional String, output format, one of `'openssh'`, `'pem'` or
563               `'x509'`. Defaults to `'x509'`.
564
565Returns a Buffer.
566
567### `Certificate#toString([format])`
568
569 - `format` -- an optional String, output format, one of `'openssh'`, `'pem'` or
570               `'x509'`. Defaults to `'pem'`.
571
572Returns a String.
573
574## Certificate identities
575
576### `identityForHost(hostname)`
577
578Constructs a host-type Identity for a given hostname.
579
580Parameters
581
582 - `hostname` -- the fully qualified DNS name of the host
583
584Returns an Identity instance.
585
586### `identityForUser(uid)`
587
588Constructs a user-type Identity for a given UID.
589
590Parameters
591
592 - `uid` -- a String, user identifier (login name)
593
594Returns an Identity instance.
595
596### `identityForEmail(email)`
597
598Constructs an email-type Identity for a given email address.
599
600Parameters
601
602 - `email` -- a String, email address
603
604Returns an Identity instance.
605
606### `identityFromDN(dn)`
607
608Parses an LDAP-style DN string (e.g. `'CN=foo, C=US'`) and turns it into an
609Identity instance.
610
611Parameters
612
613 - `dn` -- a String
614
615Returns an Identity instance.
616
617### `Identity#toString()`
618
619Returns the identity as an LDAP-style DN string.
620e.g. `'CN=foo, O=bar corp, C=us'`
621
622### `Identity#type`
623
624The type of identity. One of `'host'`, `'user'`, `'email'` or `'unknown'`
625
626### `Identity#hostname`
627### `Identity#uid`
628### `Identity#email`
629
630Set when `type` is `'host'`, `'user'`, or `'email'`, respectively. Strings.
631
632### `Identity#cn`
633
634The value of the first `CN=` in the DN, if any.
635
636Errors
637------
638
639### `InvalidAlgorithmError`
640
641The specified algorithm is not valid, either because it is not supported, or
642because it was not included on a list of allowed algorithms.
643
644Thrown by `Fingerprint.parse`, `Key#fingerprint`.
645
646Properties
647
648- `algorithm` -- the algorithm that could not be validated
649
650### `FingerprintFormatError`
651
652The fingerprint string given could not be parsed as a supported fingerprint
653format, or the specified fingerprint format is invalid.
654
655Thrown by `Fingerprint.parse`, `Fingerprint#toString`.
656
657Properties
658
659- `fingerprint` -- if caused by a fingerprint, the string value given
660- `format` -- if caused by an invalid format specification, the string value given
661
662### `KeyParseError`
663
664The key data given could not be parsed as a valid key.
665
666Properties
667
668- `keyName` -- `filename` that was given to `parseKey`
669- `format` -- the `format` that was trying to parse the key (see `parseKey`)
670- `innerErr` -- the inner Error thrown by the format parser
671
672### `KeyEncryptedError`
673
674The key is encrypted with a symmetric key (ie, it is password protected). The
675parsing operation would succeed if it was given the `passphrase` option.
676
677Properties
678
679- `keyName` -- `filename` that was given to `parseKey`
680- `format` -- the `format` that was trying to parse the key (currently can only
681              be `"pem"`)
682
683### `CertificateParseError`
684
685The certificate data given could not be parsed as a valid certificate.
686
687Properties
688
689- `certName` -- `filename` that was given to `parseCertificate`
690- `format` -- the `format` that was trying to parse the key
691              (see `parseCertificate`)
692- `innerErr` -- the inner Error thrown by the format parser
693
694Friends of sshpk
695----------------
696
697 * [`sshpk-agent`](https://github.com/arekinath/node-sshpk-agent) is a library
698   for speaking the `ssh-agent` protocol from node.js, which uses `sshpk`
699