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