Template Upload
This commit is contained in:
9
node_modules/sshpk/.npmignore
generated
vendored
Normal file
9
node_modules/sshpk/.npmignore
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
.gitmodules
|
||||
deps
|
||||
docs
|
||||
Makefile
|
||||
node_modules
|
||||
test
|
||||
tools
|
||||
coverage
|
||||
man/src
|
11
node_modules/sshpk/.travis.yml
generated
vendored
Normal file
11
node_modules/sshpk/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "5.10"
|
||||
- "4.4"
|
||||
- "4.1"
|
||||
- "0.12"
|
||||
- "0.10"
|
||||
before_install:
|
||||
- "make check"
|
||||
after_success:
|
||||
- '[ "${TRAVIS_NODE_VERSION}" = "4.4" ] && make codecovio'
|
18
node_modules/sshpk/LICENSE
generated
vendored
Normal file
18
node_modules/sshpk/LICENSE
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
Copyright Joyent, Inc. All rights reserved.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
698
node_modules/sshpk/README.md
generated
vendored
Normal file
698
node_modules/sshpk/README.md
generated
vendored
Normal file
@ -0,0 +1,698 @@
|
||||
sshpk
|
||||
=========
|
||||
|
||||
Parse, convert, fingerprint and use SSH keys (both public and private) in pure
|
||||
node -- no `ssh-keygen` or other external dependencies.
|
||||
|
||||
Supports RSA, DSA, ECDSA (nistp-\*) and ED25519 key types, in PEM (PKCS#1,
|
||||
PKCS#8) and OpenSSH formats.
|
||||
|
||||
This library has been extracted from
|
||||
[`node-http-signature`](https://github.com/joyent/node-http-signature)
|
||||
(work by [Mark Cavage](https://github.com/mcavage) and
|
||||
[Dave Eddy](https://github.com/bahamas10)) and
|
||||
[`node-ssh-fingerprint`](https://github.com/bahamas10/node-ssh-fingerprint)
|
||||
(work by Dave Eddy), with additions (including ECDSA support) by
|
||||
[Alex Wilson](https://github.com/arekinath).
|
||||
|
||||
Install
|
||||
-------
|
||||
|
||||
```
|
||||
npm install sshpk
|
||||
```
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
```js
|
||||
var sshpk = require('sshpk');
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
/* Read in an OpenSSH-format public key */
|
||||
var keyPub = fs.readFileSync('id_rsa.pub');
|
||||
var key = sshpk.parseKey(keyPub, 'ssh');
|
||||
|
||||
/* Get metadata about the key */
|
||||
console.log('type => %s', key.type);
|
||||
console.log('size => %d bits', key.size);
|
||||
console.log('comment => %s', key.comment);
|
||||
|
||||
/* Compute key fingerprints, in new OpenSSH (>6.7) format, and old MD5 */
|
||||
console.log('fingerprint => %s', key.fingerprint().toString());
|
||||
console.log('old-style fingerprint => %s', key.fingerprint('md5').toString());
|
||||
```
|
||||
|
||||
Example output:
|
||||
|
||||
```
|
||||
type => rsa
|
||||
size => 2048 bits
|
||||
comment => foo@foo.com
|
||||
fingerprint => SHA256:PYC9kPVC6J873CSIbfp0LwYeczP/W4ffObNCuDJ1u5w
|
||||
old-style fingerprint => a0:c8:ad:6c:32:9a:32:fa:59:cc:a9:8c:0a:0d:6e:bd
|
||||
```
|
||||
|
||||
More examples: converting between formats:
|
||||
|
||||
```js
|
||||
/* Read in a PEM public key */
|
||||
var keyPem = fs.readFileSync('id_rsa.pem');
|
||||
var key = sshpk.parseKey(keyPem, 'pem');
|
||||
|
||||
/* Convert to PEM PKCS#8 public key format */
|
||||
var pemBuf = key.toBuffer('pkcs8');
|
||||
|
||||
/* Convert to SSH public key format (and return as a string) */
|
||||
var sshKey = key.toString('ssh');
|
||||
```
|
||||
|
||||
Signing and verifying:
|
||||
|
||||
```js
|
||||
/* Read in an OpenSSH/PEM *private* key */
|
||||
var keyPriv = fs.readFileSync('id_ecdsa');
|
||||
var key = sshpk.parsePrivateKey(keyPriv, 'pem');
|
||||
|
||||
var data = 'some data';
|
||||
|
||||
/* Sign some data with the key */
|
||||
var s = key.createSign('sha1');
|
||||
s.update(data);
|
||||
var signature = s.sign();
|
||||
|
||||
/* Now load the public key (could also use just key.toPublic()) */
|
||||
var keyPub = fs.readFileSync('id_ecdsa.pub');
|
||||
key = sshpk.parseKey(keyPub, 'ssh');
|
||||
|
||||
/* Make a crypto.Verifier with this key */
|
||||
var v = key.createVerify('sha1');
|
||||
v.update(data);
|
||||
var valid = v.verify(signature);
|
||||
/* => true! */
|
||||
```
|
||||
|
||||
Matching fingerprints with keys:
|
||||
|
||||
```js
|
||||
var fp = sshpk.parseFingerprint('SHA256:PYC9kPVC6J873CSIbfp0LwYeczP/W4ffObNCuDJ1u5w');
|
||||
|
||||
var keys = [sshpk.parseKey(...), sshpk.parseKey(...), ...];
|
||||
|
||||
keys.forEach(function (key) {
|
||||
if (fp.matches(key))
|
||||
console.log('found it!');
|
||||
});
|
||||
```
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
## Public keys
|
||||
|
||||
### `parseKey(data[, format = 'auto'[, options]])`
|
||||
|
||||
Parses a key from a given data format and returns a new `Key` object.
|
||||
|
||||
Parameters
|
||||
|
||||
- `data` -- Either a Buffer or String, containing the key
|
||||
- `format` -- String name of format to use, valid options are:
|
||||
- `auto`: choose automatically from all below
|
||||
- `pem`: supports both PKCS#1 and PKCS#8
|
||||
- `ssh`: standard OpenSSH format,
|
||||
- `pkcs1`, `pkcs8`: variants of `pem`
|
||||
- `rfc4253`: raw OpenSSH wire format
|
||||
- `openssh`: new post-OpenSSH 6.5 internal format, produced by
|
||||
`ssh-keygen -o`
|
||||
- `options` -- Optional Object, extra options, with keys:
|
||||
- `filename` -- Optional String, name for the key being parsed
|
||||
(eg. the filename that was opened). Used to generate
|
||||
Error messages
|
||||
- `passphrase` -- Optional String, encryption passphrase used to decrypt an
|
||||
encrypted PEM file
|
||||
|
||||
### `Key.isKey(obj)`
|
||||
|
||||
Returns `true` if the given object is a valid `Key` object created by a version
|
||||
of `sshpk` compatible with this one.
|
||||
|
||||
Parameters
|
||||
|
||||
- `obj` -- Object to identify
|
||||
|
||||
### `Key#type`
|
||||
|
||||
String, the type of key. Valid options are `rsa`, `dsa`, `ecdsa`.
|
||||
|
||||
### `Key#size`
|
||||
|
||||
Integer, "size" of the key in bits. For RSA/DSA this is the size of the modulus;
|
||||
for ECDSA this is the bit size of the curve in use.
|
||||
|
||||
### `Key#comment`
|
||||
|
||||
Optional string, a key comment used by some formats (eg the `ssh` format).
|
||||
|
||||
### `Key#curve`
|
||||
|
||||
Only present if `this.type === 'ecdsa'`, string containing the name of the
|
||||
named curve used with this key. Possible values include `nistp256`, `nistp384`
|
||||
and `nistp521`.
|
||||
|
||||
### `Key#toBuffer([format = 'ssh'])`
|
||||
|
||||
Convert the key into a given data format and return the serialized key as
|
||||
a Buffer.
|
||||
|
||||
Parameters
|
||||
|
||||
- `format` -- String name of format to use, for valid options see `parseKey()`
|
||||
|
||||
### `Key#toString([format = 'ssh])`
|
||||
|
||||
Same as `this.toBuffer(format).toString()`.
|
||||
|
||||
### `Key#fingerprint([algorithm = 'sha256'])`
|
||||
|
||||
Creates a new `Fingerprint` object representing this Key's fingerprint.
|
||||
|
||||
Parameters
|
||||
|
||||
- `algorithm` -- String name of hash algorithm to use, valid options are `md5`,
|
||||
`sha1`, `sha256`, `sha384`, `sha512`
|
||||
|
||||
### `Key#createVerify([hashAlgorithm])`
|
||||
|
||||
Creates a `crypto.Verifier` specialized to use this Key (and the correct public
|
||||
key algorithm to match it). The returned Verifier has the same API as a regular
|
||||
one, except that the `verify()` function takes only the target signature as an
|
||||
argument.
|
||||
|
||||
Parameters
|
||||
|
||||
- `hashAlgorithm` -- optional String name of hash algorithm to use, any
|
||||
supported by OpenSSL are valid, usually including
|
||||
`sha1`, `sha256`.
|
||||
|
||||
`v.verify(signature[, format])` Parameters
|
||||
|
||||
- `signature` -- either a Signature object, or a Buffer or String
|
||||
- `format` -- optional String, name of format to interpret given String with.
|
||||
Not valid if `signature` is a Signature or Buffer.
|
||||
|
||||
### `Key#createDiffieHellman()`
|
||||
### `Key#createDH()`
|
||||
|
||||
Creates a Diffie-Hellman key exchange object initialized with this key and all
|
||||
necessary parameters. This has the same API as a `crypto.DiffieHellman`
|
||||
instance, except that functions take `Key` and `PrivateKey` objects as
|
||||
arguments, and return them where indicated for.
|
||||
|
||||
This is only valid for keys belonging to a cryptosystem that supports DHE
|
||||
or a close analogue (i.e. `dsa`, `ecdsa` and `curve25519` keys). An attempt
|
||||
to call this function on other keys will yield an `Error`.
|
||||
|
||||
## Private keys
|
||||
|
||||
### `parsePrivateKey(data[, format = 'auto'[, options]])`
|
||||
|
||||
Parses a private key from a given data format and returns a new
|
||||
`PrivateKey` object.
|
||||
|
||||
Parameters
|
||||
|
||||
- `data` -- Either a Buffer or String, containing the key
|
||||
- `format` -- String name of format to use, valid options are:
|
||||
- `auto`: choose automatically from all below
|
||||
- `pem`: supports both PKCS#1 and PKCS#8
|
||||
- `ssh`, `openssh`: new post-OpenSSH 6.5 internal format, produced by
|
||||
`ssh-keygen -o`
|
||||
- `pkcs1`, `pkcs8`: variants of `pem`
|
||||
- `rfc4253`: raw OpenSSH wire format
|
||||
- `options` -- Optional Object, extra options, with keys:
|
||||
- `filename` -- Optional String, name for the key being parsed
|
||||
(eg. the filename that was opened). Used to generate
|
||||
Error messages
|
||||
- `passphrase` -- Optional String, encryption passphrase used to decrypt an
|
||||
encrypted PEM file
|
||||
|
||||
### `generatePrivateKey(type[, options])`
|
||||
|
||||
Generates a new private key of a certain key type, from random data.
|
||||
|
||||
Parameters
|
||||
|
||||
- `type` -- String, type of key to generate. Currently supported are `'ecdsa'`
|
||||
and `'ed25519'`
|
||||
- `options` -- optional Object, with keys:
|
||||
- `curve` -- optional String, for `'ecdsa'` keys, specifies the curve to use.
|
||||
If ECDSA is specified and this option is not given, defaults to
|
||||
using `'nistp256'`.
|
||||
|
||||
### `PrivateKey.isPrivateKey(obj)`
|
||||
|
||||
Returns `true` if the given object is a valid `PrivateKey` object created by a
|
||||
version of `sshpk` compatible with this one.
|
||||
|
||||
Parameters
|
||||
|
||||
- `obj` -- Object to identify
|
||||
|
||||
### `PrivateKey#type`
|
||||
|
||||
String, the type of key. Valid options are `rsa`, `dsa`, `ecdsa`.
|
||||
|
||||
### `PrivateKey#size`
|
||||
|
||||
Integer, "size" of the key in bits. For RSA/DSA this is the size of the modulus;
|
||||
for ECDSA this is the bit size of the curve in use.
|
||||
|
||||
### `PrivateKey#curve`
|
||||
|
||||
Only present if `this.type === 'ecdsa'`, string containing the name of the
|
||||
named curve used with this key. Possible values include `nistp256`, `nistp384`
|
||||
and `nistp521`.
|
||||
|
||||
### `PrivateKey#toBuffer([format = 'pkcs1'])`
|
||||
|
||||
Convert the key into a given data format and return the serialized key as
|
||||
a Buffer.
|
||||
|
||||
Parameters
|
||||
|
||||
- `format` -- String name of format to use, valid options are listed under
|
||||
`parsePrivateKey`. Note that ED25519 keys default to `openssh`
|
||||
format instead (as they have no `pkcs1` representation).
|
||||
|
||||
### `PrivateKey#toString([format = 'pkcs1'])`
|
||||
|
||||
Same as `this.toBuffer(format).toString()`.
|
||||
|
||||
### `PrivateKey#toPublic()`
|
||||
|
||||
Extract just the public part of this private key, and return it as a `Key`
|
||||
object.
|
||||
|
||||
### `PrivateKey#fingerprint([algorithm = 'sha256'])`
|
||||
|
||||
Same as `this.toPublic().fingerprint()`.
|
||||
|
||||
### `PrivateKey#createVerify([hashAlgorithm])`
|
||||
|
||||
Same as `this.toPublic().createVerify()`.
|
||||
|
||||
### `PrivateKey#createSign([hashAlgorithm])`
|
||||
|
||||
Creates a `crypto.Sign` specialized to use this PrivateKey (and the correct
|
||||
key algorithm to match it). The returned Signer has the same API as a regular
|
||||
one, except that the `sign()` function takes no arguments, and returns a
|
||||
`Signature` object.
|
||||
|
||||
Parameters
|
||||
|
||||
- `hashAlgorithm` -- optional String name of hash algorithm to use, any
|
||||
supported by OpenSSL are valid, usually including
|
||||
`sha1`, `sha256`.
|
||||
|
||||
`v.sign()` Parameters
|
||||
|
||||
- none
|
||||
|
||||
### `PrivateKey#derive(newType)`
|
||||
|
||||
Derives a related key of type `newType` from this key. Currently this is
|
||||
only supported to change between `ed25519` and `curve25519` keys which are
|
||||
stored with the same private key (but usually distinct public keys in order
|
||||
to avoid degenerate keys that lead to a weak Diffie-Hellman exchange).
|
||||
|
||||
Parameters
|
||||
|
||||
- `newType` -- String, type of key to derive, either `ed25519` or `curve25519`
|
||||
|
||||
## Fingerprints
|
||||
|
||||
### `parseFingerprint(fingerprint[, algorithms])`
|
||||
|
||||
Pre-parses a fingerprint, creating a `Fingerprint` object that can be used to
|
||||
quickly locate a key by using the `Fingerprint#matches` function.
|
||||
|
||||
Parameters
|
||||
|
||||
- `fingerprint` -- String, the fingerprint value, in any supported format
|
||||
- `algorithms` -- Optional list of strings, names of hash algorithms to limit
|
||||
support to. If `fingerprint` uses a hash algorithm not on
|
||||
this list, throws `InvalidAlgorithmError`.
|
||||
|
||||
### `Fingerprint.isFingerprint(obj)`
|
||||
|
||||
Returns `true` if the given object is a valid `Fingerprint` object created by a
|
||||
version of `sshpk` compatible with this one.
|
||||
|
||||
Parameters
|
||||
|
||||
- `obj` -- Object to identify
|
||||
|
||||
### `Fingerprint#toString([format])`
|
||||
|
||||
Returns a fingerprint as a string, in the given format.
|
||||
|
||||
Parameters
|
||||
|
||||
- `format` -- Optional String, format to use, valid options are `hex` and
|
||||
`base64`. If this `Fingerprint` uses the `md5` algorithm, the
|
||||
default format is `hex`. Otherwise, the default is `base64`.
|
||||
|
||||
### `Fingerprint#matches(key)`
|
||||
|
||||
Verifies whether or not this `Fingerprint` matches a given `Key`. This function
|
||||
uses double-hashing to avoid leaking timing information. Returns a boolean.
|
||||
|
||||
Parameters
|
||||
|
||||
- `key` -- a `Key` object, the key to match this fingerprint against
|
||||
|
||||
## Signatures
|
||||
|
||||
### `parseSignature(signature, algorithm, format)`
|
||||
|
||||
Parses a signature in a given format, creating a `Signature` object. Useful
|
||||
for converting between the SSH and ASN.1 (PKCS/OpenSSL) signature formats, and
|
||||
also returned as output from `PrivateKey#createSign().sign()`.
|
||||
|
||||
A Signature object can also be passed to a verifier produced by
|
||||
`Key#createVerify()` and it will automatically be converted internally into the
|
||||
correct format for verification.
|
||||
|
||||
Parameters
|
||||
|
||||
- `signature` -- a Buffer (binary) or String (base64), data of the actual
|
||||
signature in the given format
|
||||
- `algorithm` -- a String, name of the algorithm to be used, possible values
|
||||
are `rsa`, `dsa`, `ecdsa`
|
||||
- `format` -- a String, either `asn1` or `ssh`
|
||||
|
||||
### `Signature.isSignature(obj)`
|
||||
|
||||
Returns `true` if the given object is a valid `Signature` object created by a
|
||||
version of `sshpk` compatible with this one.
|
||||
|
||||
Parameters
|
||||
|
||||
- `obj` -- Object to identify
|
||||
|
||||
### `Signature#toBuffer([format = 'asn1'])`
|
||||
|
||||
Converts a Signature to the given format and returns it as a Buffer.
|
||||
|
||||
Parameters
|
||||
|
||||
- `format` -- a String, either `asn1` or `ssh`
|
||||
|
||||
### `Signature#toString([format = 'asn1'])`
|
||||
|
||||
Same as `this.toBuffer(format).toString('base64')`.
|
||||
|
||||
## Certificates
|
||||
|
||||
`sshpk` includes basic support for parsing certificates in X.509 (PEM) format
|
||||
and the OpenSSH certificate format. This feature is intended to be used mainly
|
||||
to access basic metadata about certificates, extract public keys from them, and
|
||||
also to generate simple self-signed certificates from an existing key.
|
||||
|
||||
Notably, there is no implementation of CA chain-of-trust verification, and only
|
||||
very minimal support for key usage restrictions. Please do the security world
|
||||
a favour, and DO NOT use this code for certificate verification in the
|
||||
traditional X.509 CA chain style.
|
||||
|
||||
### `parseCertificate(data, format)`
|
||||
|
||||
Parameters
|
||||
|
||||
- `data` -- a Buffer or String
|
||||
- `format` -- a String, format to use, one of `'openssh'`, `'pem'` (X.509 in a
|
||||
PEM wrapper), or `'x509'` (raw DER encoded)
|
||||
|
||||
### `createSelfSignedCertificate(subject, privateKey[, options])`
|
||||
|
||||
Parameters
|
||||
|
||||
- `subject` -- an Identity, the subject of the certificate
|
||||
- `privateKey` -- a PrivateKey, the key of the subject: will be used both to be
|
||||
placed in the certificate and also to sign it (since this is
|
||||
a self-signed certificate)
|
||||
- `options` -- optional Object, with keys:
|
||||
- `lifetime` -- optional Number, lifetime of the certificate from now in
|
||||
seconds
|
||||
- `validFrom`, `validUntil` -- optional Dates, beginning and end of
|
||||
certificate validity period. If given
|
||||
`lifetime` will be ignored
|
||||
- `serial` -- optional Buffer, the serial number of the certificate
|
||||
- `purposes` -- optional Array of String, X.509 key usage restrictions
|
||||
|
||||
### `createCertificate(subject, key, issuer, issuerKey[, options])`
|
||||
|
||||
Parameters
|
||||
|
||||
- `subject` -- an Identity, the subject of the certificate
|
||||
- `key` -- a Key, the public key of the subject
|
||||
- `issuer` -- an Identity, the issuer of the certificate who will sign it
|
||||
- `issuerKey` -- a PrivateKey, the issuer's private key for signing
|
||||
- `options` -- optional Object, with keys:
|
||||
- `lifetime` -- optional Number, lifetime of the certificate from now in
|
||||
seconds
|
||||
- `validFrom`, `validUntil` -- optional Dates, beginning and end of
|
||||
certificate validity period. If given
|
||||
`lifetime` will be ignored
|
||||
- `serial` -- optional Buffer, the serial number of the certificate
|
||||
- `purposes` -- optional Array of String, X.509 key usage restrictions
|
||||
|
||||
### `Certificate#subjects`
|
||||
|
||||
Array of `Identity` instances describing the subject of this certificate.
|
||||
|
||||
### `Certificate#issuer`
|
||||
|
||||
The `Identity` of the Certificate's issuer (signer).
|
||||
|
||||
### `Certificate#subjectKey`
|
||||
|
||||
The public key of the subject of the certificate, as a `Key` instance.
|
||||
|
||||
### `Certificate#issuerKey`
|
||||
|
||||
The public key of the signing issuer of this certificate, as a `Key` instance.
|
||||
May be `undefined` if the issuer's key is unknown (e.g. on an X509 certificate).
|
||||
|
||||
### `Certificate#serial`
|
||||
|
||||
The serial number of the certificate. As this is normally a 64-bit or wider
|
||||
integer, it is returned as a Buffer.
|
||||
|
||||
### `Certificate#purposes`
|
||||
|
||||
Array of Strings indicating the X.509 key usage purposes that this certificate
|
||||
is valid for. The possible strings at the moment are:
|
||||
|
||||
* `'signature'` -- key can be used for digital signatures
|
||||
* `'identity'` -- key can be used to attest about the identity of the signer
|
||||
(X.509 calls this `nonRepudiation`)
|
||||
* `'codeSigning'` -- key can be used to sign executable code
|
||||
* `'keyEncryption'` -- key can be used to encrypt other keys
|
||||
* `'encryption'` -- key can be used to encrypt data (only applies for RSA)
|
||||
* `'keyAgreement'` -- key can be used for key exchange protocols such as
|
||||
Diffie-Hellman
|
||||
* `'ca'` -- key can be used to sign other certificates (is a Certificate
|
||||
Authority)
|
||||
* `'crl'` -- key can be used to sign Certificate Revocation Lists (CRLs)
|
||||
|
||||
### `Certificate#isExpired([when])`
|
||||
|
||||
Tests whether the Certificate is currently expired (i.e. the `validFrom` and
|
||||
`validUntil` dates specify a range of time that does not include the current
|
||||
time).
|
||||
|
||||
Parameters
|
||||
|
||||
- `when` -- optional Date, if specified, tests whether the Certificate was or
|
||||
will be expired at the specified time instead of now
|
||||
|
||||
Returns a Boolean.
|
||||
|
||||
### `Certificate#isSignedByKey(key)`
|
||||
|
||||
Tests whether the Certificate was validly signed by the given (public) Key.
|
||||
|
||||
Parameters
|
||||
|
||||
- `key` -- a Key instance
|
||||
|
||||
Returns a Boolean.
|
||||
|
||||
### `Certificate#isSignedBy(certificate)`
|
||||
|
||||
Tests whether this Certificate was validly signed by the subject of the given
|
||||
certificate. Also tests that the issuer Identity of this Certificate and the
|
||||
subject Identity of the other Certificate are equivalent.
|
||||
|
||||
Parameters
|
||||
|
||||
- `certificate` -- another Certificate instance
|
||||
|
||||
Returns a Boolean.
|
||||
|
||||
### `Certificate#fingerprint([hashAlgo])`
|
||||
|
||||
Returns the X509-style fingerprint of the entire certificate (as a Fingerprint
|
||||
instance). This matches what a web-browser or similar would display as the
|
||||
certificate fingerprint and should not be confused with the fingerprint of the
|
||||
subject's public key.
|
||||
|
||||
Parameters
|
||||
|
||||
- `hashAlgo` -- an optional String, any hash function name
|
||||
|
||||
### `Certificate#toBuffer([format])`
|
||||
|
||||
Serializes the Certificate to a Buffer and returns it.
|
||||
|
||||
Parameters
|
||||
|
||||
- `format` -- an optional String, output format, one of `'openssh'`, `'pem'` or
|
||||
`'x509'`. Defaults to `'x509'`.
|
||||
|
||||
Returns a Buffer.
|
||||
|
||||
### `Certificate#toString([format])`
|
||||
|
||||
- `format` -- an optional String, output format, one of `'openssh'`, `'pem'` or
|
||||
`'x509'`. Defaults to `'pem'`.
|
||||
|
||||
Returns a String.
|
||||
|
||||
## Certificate identities
|
||||
|
||||
### `identityForHost(hostname)`
|
||||
|
||||
Constructs a host-type Identity for a given hostname.
|
||||
|
||||
Parameters
|
||||
|
||||
- `hostname` -- the fully qualified DNS name of the host
|
||||
|
||||
Returns an Identity instance.
|
||||
|
||||
### `identityForUser(uid)`
|
||||
|
||||
Constructs a user-type Identity for a given UID.
|
||||
|
||||
Parameters
|
||||
|
||||
- `uid` -- a String, user identifier (login name)
|
||||
|
||||
Returns an Identity instance.
|
||||
|
||||
### `identityForEmail(email)`
|
||||
|
||||
Constructs an email-type Identity for a given email address.
|
||||
|
||||
Parameters
|
||||
|
||||
- `email` -- a String, email address
|
||||
|
||||
Returns an Identity instance.
|
||||
|
||||
### `identityFromDN(dn)`
|
||||
|
||||
Parses an LDAP-style DN string (e.g. `'CN=foo, C=US'`) and turns it into an
|
||||
Identity instance.
|
||||
|
||||
Parameters
|
||||
|
||||
- `dn` -- a String
|
||||
|
||||
Returns an Identity instance.
|
||||
|
||||
### `Identity#toString()`
|
||||
|
||||
Returns the identity as an LDAP-style DN string.
|
||||
e.g. `'CN=foo, O=bar corp, C=us'`
|
||||
|
||||
### `Identity#type`
|
||||
|
||||
The type of identity. One of `'host'`, `'user'`, `'email'` or `'unknown'`
|
||||
|
||||
### `Identity#hostname`
|
||||
### `Identity#uid`
|
||||
### `Identity#email`
|
||||
|
||||
Set when `type` is `'host'`, `'user'`, or `'email'`, respectively. Strings.
|
||||
|
||||
### `Identity#cn`
|
||||
|
||||
The value of the first `CN=` in the DN, if any.
|
||||
|
||||
Errors
|
||||
------
|
||||
|
||||
### `InvalidAlgorithmError`
|
||||
|
||||
The specified algorithm is not valid, either because it is not supported, or
|
||||
because it was not included on a list of allowed algorithms.
|
||||
|
||||
Thrown by `Fingerprint.parse`, `Key#fingerprint`.
|
||||
|
||||
Properties
|
||||
|
||||
- `algorithm` -- the algorithm that could not be validated
|
||||
|
||||
### `FingerprintFormatError`
|
||||
|
||||
The fingerprint string given could not be parsed as a supported fingerprint
|
||||
format, or the specified fingerprint format is invalid.
|
||||
|
||||
Thrown by `Fingerprint.parse`, `Fingerprint#toString`.
|
||||
|
||||
Properties
|
||||
|
||||
- `fingerprint` -- if caused by a fingerprint, the string value given
|
||||
- `format` -- if caused by an invalid format specification, the string value given
|
||||
|
||||
### `KeyParseError`
|
||||
|
||||
The key data given could not be parsed as a valid key.
|
||||
|
||||
Properties
|
||||
|
||||
- `keyName` -- `filename` that was given to `parseKey`
|
||||
- `format` -- the `format` that was trying to parse the key (see `parseKey`)
|
||||
- `innerErr` -- the inner Error thrown by the format parser
|
||||
|
||||
### `KeyEncryptedError`
|
||||
|
||||
The key is encrypted with a symmetric key (ie, it is password protected). The
|
||||
parsing operation would succeed if it was given the `passphrase` option.
|
||||
|
||||
Properties
|
||||
|
||||
- `keyName` -- `filename` that was given to `parseKey`
|
||||
- `format` -- the `format` that was trying to parse the key (currently can only
|
||||
be `"pem"`)
|
||||
|
||||
### `CertificateParseError`
|
||||
|
||||
The certificate data given could not be parsed as a valid certificate.
|
||||
|
||||
Properties
|
||||
|
||||
- `certName` -- `filename` that was given to `parseCertificate`
|
||||
- `format` -- the `format` that was trying to parse the key
|
||||
(see `parseCertificate`)
|
||||
- `innerErr` -- the inner Error thrown by the format parser
|
||||
|
||||
Friends of sshpk
|
||||
----------------
|
||||
|
||||
* [`sshpk-agent`](https://github.com/arekinath/node-sshpk-agent) is a library
|
||||
for speaking the `ssh-agent` protocol from node.js, which uses `sshpk`
|
201
node_modules/sshpk/bin/sshpk-conv
generated
vendored
Normal file
201
node_modules/sshpk/bin/sshpk-conv
generated
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
#!/usr/bin/env node
|
||||
// -*- mode: js -*-
|
||||
// vim: set filetype=javascript :
|
||||
// Copyright 2015 Joyent, Inc. All rights reserved.
|
||||
|
||||
var dashdash = require('dashdash');
|
||||
var sshpk = require('../lib/index');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var tty = require('tty');
|
||||
var readline = require('readline');
|
||||
var getPassword = require('getpass').getPass;
|
||||
|
||||
var options = [
|
||||
{
|
||||
names: ['outformat', 't'],
|
||||
type: 'string',
|
||||
help: 'Output format'
|
||||
},
|
||||
{
|
||||
names: ['informat', 'T'],
|
||||
type: 'string',
|
||||
help: 'Input format'
|
||||
},
|
||||
{
|
||||
names: ['file', 'f'],
|
||||
type: 'string',
|
||||
help: 'Input file name (default stdin)'
|
||||
},
|
||||
{
|
||||
names: ['out', 'o'],
|
||||
type: 'string',
|
||||
help: 'Output file name (default stdout)'
|
||||
},
|
||||
{
|
||||
names: ['private', 'p'],
|
||||
type: 'bool',
|
||||
help: 'Produce a private key as output'
|
||||
},
|
||||
{
|
||||
names: ['derive', 'd'],
|
||||
type: 'string',
|
||||
help: 'Output a new key derived from this one, with given algo'
|
||||
},
|
||||
{
|
||||
names: ['identify', 'i'],
|
||||
type: 'bool',
|
||||
help: 'Print key metadata instead of converting'
|
||||
},
|
||||
{
|
||||
names: ['comment', 'c'],
|
||||
type: 'string',
|
||||
help: 'Set key comment, if output format supports'
|
||||
},
|
||||
{
|
||||
names: ['help', 'h'],
|
||||
type: 'bool',
|
||||
help: 'Shows this help text'
|
||||
}
|
||||
];
|
||||
|
||||
if (require.main === module) {
|
||||
var parser = dashdash.createParser({
|
||||
options: options
|
||||
});
|
||||
|
||||
try {
|
||||
var opts = parser.parse(process.argv);
|
||||
} catch (e) {
|
||||
console.error('sshpk-conv: error: %s', e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (opts.help || opts._args.length > 1) {
|
||||
var help = parser.help({}).trimRight();
|
||||
console.error('sshpk-conv: converts between SSH key formats\n');
|
||||
console.error(help);
|
||||
console.error('\navailable formats:');
|
||||
console.error(' - pem, pkcs1 eg id_rsa');
|
||||
console.error(' - ssh eg id_rsa.pub');
|
||||
console.error(' - pkcs8 format you want for openssl');
|
||||
console.error(' - openssh like output of ssh-keygen -o');
|
||||
console.error(' - rfc4253 raw OpenSSH wire format');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Key derivation can only be done on private keys, so use of the -d
|
||||
* option necessarily implies -p.
|
||||
*/
|
||||
if (opts.derive)
|
||||
opts.private = true;
|
||||
|
||||
var inFile = process.stdin;
|
||||
var inFileName = 'stdin';
|
||||
|
||||
var inFilePath;
|
||||
if (opts.file) {
|
||||
inFilePath = opts.file;
|
||||
} else if (opts._args.length === 1) {
|
||||
inFilePath = opts._args[0];
|
||||
}
|
||||
|
||||
if (inFilePath)
|
||||
inFileName = path.basename(inFilePath);
|
||||
|
||||
try {
|
||||
if (inFilePath) {
|
||||
fs.accessSync(inFilePath, fs.R_OK);
|
||||
inFile = fs.createReadStream(inFilePath);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('sshpk-conv: error opening input file' +
|
||||
': ' + e.name + ': ' + e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var outFile = process.stdout;
|
||||
|
||||
try {
|
||||
if (opts.out && !opts.identify) {
|
||||
fs.accessSync(path.dirname(opts.out), fs.W_OK);
|
||||
outFile = fs.createWriteStream(opts.out);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('sshpk-conv: error opening output file' +
|
||||
': ' + e.name + ': ' + e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var bufs = [];
|
||||
inFile.on('readable', function () {
|
||||
var data;
|
||||
while ((data = inFile.read()))
|
||||
bufs.push(data);
|
||||
});
|
||||
var parseOpts = {};
|
||||
parseOpts.filename = inFileName;
|
||||
inFile.on('end', function processKey() {
|
||||
var buf = Buffer.concat(bufs);
|
||||
var fmt = 'auto';
|
||||
if (opts.informat)
|
||||
fmt = opts.informat;
|
||||
var f = sshpk.parseKey;
|
||||
if (opts.private)
|
||||
f = sshpk.parsePrivateKey;
|
||||
try {
|
||||
var key = f(buf, fmt, parseOpts);
|
||||
} catch (e) {
|
||||
if (e.name === 'KeyEncryptedError') {
|
||||
getPassword(function (err, pw) {
|
||||
if (err) {
|
||||
console.log('sshpk-conv: ' +
|
||||
err.name + ': ' +
|
||||
err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
parseOpts.passphrase = pw;
|
||||
processKey();
|
||||
});
|
||||
return;
|
||||
}
|
||||
console.error('sshpk-conv: ' +
|
||||
e.name + ': ' + e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (opts.derive)
|
||||
key = key.derive(opts.derive);
|
||||
|
||||
if (opts.comment)
|
||||
key.comment = opts.comment;
|
||||
|
||||
if (!opts.identify) {
|
||||
fmt = undefined;
|
||||
if (opts.outformat)
|
||||
fmt = opts.outformat;
|
||||
outFile.write(key.toBuffer(fmt));
|
||||
if (fmt === 'ssh' ||
|
||||
(!opts.private && fmt === undefined))
|
||||
outFile.write('\n');
|
||||
outFile.once('drain', function () {
|
||||
process.exit(0);
|
||||
});
|
||||
} else {
|
||||
var kind = 'public';
|
||||
if (sshpk.PrivateKey.isPrivateKey(key))
|
||||
kind = 'private';
|
||||
console.log('%s: a %d bit %s %s key', inFileName,
|
||||
key.size, key.type.toUpperCase(), kind);
|
||||
if (key.type === 'ecdsa')
|
||||
console.log('ECDSA curve: %s', key.curve);
|
||||
if (key.comment)
|
||||
console.log('Comment: %s', key.comment);
|
||||
console.log('Fingerprint:');
|
||||
console.log(' ' + key.fingerprint().toString());
|
||||
console.log(' ' + key.fingerprint('md5').toString());
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
}
|
191
node_modules/sshpk/bin/sshpk-sign
generated
vendored
Normal file
191
node_modules/sshpk/bin/sshpk-sign
generated
vendored
Normal file
@ -0,0 +1,191 @@
|
||||
#!/usr/bin/env node
|
||||
// -*- mode: js -*-
|
||||
// vim: set filetype=javascript :
|
||||
// Copyright 2015 Joyent, Inc. All rights reserved.
|
||||
|
||||
var dashdash = require('dashdash');
|
||||
var sshpk = require('../lib/index');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var getPassword = require('getpass').getPass;
|
||||
|
||||
var options = [
|
||||
{
|
||||
names: ['hash', 'H'],
|
||||
type: 'string',
|
||||
help: 'Hash algorithm (sha1, sha256, sha384, sha512)'
|
||||
},
|
||||
{
|
||||
names: ['verbose', 'v'],
|
||||
type: 'bool',
|
||||
help: 'Display verbose info about key and hash used'
|
||||
},
|
||||
{
|
||||
names: ['identity', 'i'],
|
||||
type: 'string',
|
||||
help: 'Path to key to use'
|
||||
},
|
||||
{
|
||||
names: ['file', 'f'],
|
||||
type: 'string',
|
||||
help: 'Input filename'
|
||||
},
|
||||
{
|
||||
names: ['out', 'o'],
|
||||
type: 'string',
|
||||
help: 'Output filename'
|
||||
},
|
||||
{
|
||||
names: ['format', 't'],
|
||||
type: 'string',
|
||||
help: 'Signature format (asn1, ssh, raw)'
|
||||
},
|
||||
{
|
||||
names: ['binary', 'b'],
|
||||
type: 'bool',
|
||||
help: 'Output raw binary instead of base64'
|
||||
},
|
||||
{
|
||||
names: ['help', 'h'],
|
||||
type: 'bool',
|
||||
help: 'Shows this help text'
|
||||
}
|
||||
];
|
||||
|
||||
var parseOpts = {};
|
||||
|
||||
if (require.main === module) {
|
||||
var parser = dashdash.createParser({
|
||||
options: options
|
||||
});
|
||||
|
||||
try {
|
||||
var opts = parser.parse(process.argv);
|
||||
} catch (e) {
|
||||
console.error('sshpk-sign: error: %s', e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (opts.help || opts._args.length > 1) {
|
||||
var help = parser.help({}).trimRight();
|
||||
console.error('sshpk-sign: sign data using an SSH key\n');
|
||||
console.error(help);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!opts.identity) {
|
||||
var help = parser.help({}).trimRight();
|
||||
console.error('sshpk-sign: the -i or --identity option ' +
|
||||
'is required\n');
|
||||
console.error(help);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var keyData = fs.readFileSync(opts.identity);
|
||||
parseOpts.filename = opts.identity;
|
||||
|
||||
run();
|
||||
}
|
||||
|
||||
function run() {
|
||||
var key;
|
||||
try {
|
||||
key = sshpk.parsePrivateKey(keyData, 'auto', parseOpts);
|
||||
} catch (e) {
|
||||
if (e.name === 'KeyEncryptedError') {
|
||||
getPassword(function (err, pw) {
|
||||
parseOpts.passphrase = pw;
|
||||
run();
|
||||
});
|
||||
return;
|
||||
}
|
||||
console.error('sshpk-sign: error loading private key "' +
|
||||
opts.identity + '": ' + e.name + ': ' + e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var hash = opts.hash || key.defaultHashAlgorithm();
|
||||
|
||||
var signer;
|
||||
try {
|
||||
signer = key.createSign(hash);
|
||||
} catch (e) {
|
||||
console.error('sshpk-sign: error creating signer: ' +
|
||||
e.name + ': ' + e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (opts.verbose) {
|
||||
console.error('sshpk-sign: using %s-%s with a %d bit key',
|
||||
key.type, hash, key.size);
|
||||
}
|
||||
|
||||
var inFile = process.stdin;
|
||||
var inFileName = 'stdin';
|
||||
|
||||
var inFilePath;
|
||||
if (opts.file) {
|
||||
inFilePath = opts.file;
|
||||
} else if (opts._args.length === 1) {
|
||||
inFilePath = opts._args[0];
|
||||
}
|
||||
|
||||
if (inFilePath)
|
||||
inFileName = path.basename(inFilePath);
|
||||
|
||||
try {
|
||||
if (inFilePath) {
|
||||
fs.accessSync(inFilePath, fs.R_OK);
|
||||
inFile = fs.createReadStream(inFilePath);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('sshpk-sign: error opening input file' +
|
||||
': ' + e.name + ': ' + e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var outFile = process.stdout;
|
||||
|
||||
try {
|
||||
if (opts.out && !opts.identify) {
|
||||
fs.accessSync(path.dirname(opts.out), fs.W_OK);
|
||||
outFile = fs.createWriteStream(opts.out);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('sshpk-sign: error opening output file' +
|
||||
': ' + e.name + ': ' + e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
inFile.pipe(signer);
|
||||
inFile.on('end', function () {
|
||||
var sig;
|
||||
try {
|
||||
sig = signer.sign();
|
||||
} catch (e) {
|
||||
console.error('sshpk-sign: error signing data: ' +
|
||||
e.name + ': ' + e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var fmt = opts.format || 'asn1';
|
||||
var output;
|
||||
try {
|
||||
output = sig.toBuffer(fmt);
|
||||
if (!opts.binary)
|
||||
output = output.toString('base64');
|
||||
} catch (e) {
|
||||
console.error('sshpk-sign: error converting signature' +
|
||||
' to ' + fmt + ' format: ' + e.name + ': ' +
|
||||
e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
outFile.write(output);
|
||||
if (!opts.binary)
|
||||
outFile.write('\n');
|
||||
outFile.once('drain', function () {
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
}
|
166
node_modules/sshpk/bin/sshpk-verify
generated
vendored
Normal file
166
node_modules/sshpk/bin/sshpk-verify
generated
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env node
|
||||
// -*- mode: js -*-
|
||||
// vim: set filetype=javascript :
|
||||
// Copyright 2015 Joyent, Inc. All rights reserved.
|
||||
|
||||
var dashdash = require('dashdash');
|
||||
var sshpk = require('../lib/index');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
var options = [
|
||||
{
|
||||
names: ['hash', 'H'],
|
||||
type: 'string',
|
||||
help: 'Hash algorithm (sha1, sha256, sha384, sha512)'
|
||||
},
|
||||
{
|
||||
names: ['verbose', 'v'],
|
||||
type: 'bool',
|
||||
help: 'Display verbose info about key and hash used'
|
||||
},
|
||||
{
|
||||
names: ['identity', 'i'],
|
||||
type: 'string',
|
||||
help: 'Path to (public) key to use'
|
||||
},
|
||||
{
|
||||
names: ['file', 'f'],
|
||||
type: 'string',
|
||||
help: 'Input filename'
|
||||
},
|
||||
{
|
||||
names: ['format', 't'],
|
||||
type: 'string',
|
||||
help: 'Signature format (asn1, ssh, raw)'
|
||||
},
|
||||
{
|
||||
names: ['signature', 's'],
|
||||
type: 'string',
|
||||
help: 'base64-encoded signature data'
|
||||
},
|
||||
{
|
||||
names: ['help', 'h'],
|
||||
type: 'bool',
|
||||
help: 'Shows this help text'
|
||||
}
|
||||
];
|
||||
|
||||
if (require.main === module) {
|
||||
var parser = dashdash.createParser({
|
||||
options: options
|
||||
});
|
||||
|
||||
try {
|
||||
var opts = parser.parse(process.argv);
|
||||
} catch (e) {
|
||||
console.error('sshpk-verify: error: %s', e.message);
|
||||
process.exit(3);
|
||||
}
|
||||
|
||||
if (opts.help || opts._args.length > 1) {
|
||||
var help = parser.help({}).trimRight();
|
||||
console.error('sshpk-verify: sign data using an SSH key\n');
|
||||
console.error(help);
|
||||
process.exit(3);
|
||||
}
|
||||
|
||||
if (!opts.identity) {
|
||||
var help = parser.help({}).trimRight();
|
||||
console.error('sshpk-verify: the -i or --identity option ' +
|
||||
'is required\n');
|
||||
console.error(help);
|
||||
process.exit(3);
|
||||
}
|
||||
|
||||
if (!opts.signature) {
|
||||
var help = parser.help({}).trimRight();
|
||||
console.error('sshpk-verify: the -s or --signature option ' +
|
||||
'is required\n');
|
||||
console.error(help);
|
||||
process.exit(3);
|
||||
}
|
||||
|
||||
var keyData = fs.readFileSync(opts.identity);
|
||||
|
||||
var key;
|
||||
try {
|
||||
key = sshpk.parseKey(keyData);
|
||||
} catch (e) {
|
||||
console.error('sshpk-verify: error loading key "' +
|
||||
opts.identity + '": ' + e.name + ': ' + e.message);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
var fmt = opts.format || 'asn1';
|
||||
var sigData = new Buffer(opts.signature, 'base64');
|
||||
|
||||
var sig;
|
||||
try {
|
||||
sig = sshpk.parseSignature(sigData, key.type, fmt);
|
||||
} catch (e) {
|
||||
console.error('sshpk-verify: error parsing signature: ' +
|
||||
e.name + ': ' + e.message);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
var hash = opts.hash || key.defaultHashAlgorithm();
|
||||
|
||||
var verifier;
|
||||
try {
|
||||
verifier = key.createVerify(hash);
|
||||
} catch (e) {
|
||||
console.error('sshpk-verify: error creating verifier: ' +
|
||||
e.name + ': ' + e.message);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
if (opts.verbose) {
|
||||
console.error('sshpk-verify: using %s-%s with a %d bit key',
|
||||
key.type, hash, key.size);
|
||||
}
|
||||
|
||||
var inFile = process.stdin;
|
||||
var inFileName = 'stdin';
|
||||
|
||||
var inFilePath;
|
||||
if (opts.file) {
|
||||
inFilePath = opts.file;
|
||||
} else if (opts._args.length === 1) {
|
||||
inFilePath = opts._args[0];
|
||||
}
|
||||
|
||||
if (inFilePath)
|
||||
inFileName = path.basename(inFilePath);
|
||||
|
||||
try {
|
||||
if (inFilePath) {
|
||||
fs.accessSync(inFilePath, fs.R_OK);
|
||||
inFile = fs.createReadStream(inFilePath);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('sshpk-verify: error opening input file' +
|
||||
': ' + e.name + ': ' + e.message);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
inFile.pipe(verifier);
|
||||
inFile.on('end', function () {
|
||||
var ret;
|
||||
try {
|
||||
ret = verifier.verify(sig);
|
||||
} catch (e) {
|
||||
console.error('sshpk-verify: error verifying data: ' +
|
||||
e.name + ': ' + e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
console.error('OK');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.error('NOT OK');
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
168
node_modules/sshpk/lib/algs.js
generated
vendored
Normal file
168
node_modules/sshpk/lib/algs.js
generated
vendored
Normal file
@ -0,0 +1,168 @@
|
||||
// Copyright 2015 Joyent, Inc.
|
||||
|
||||
var algInfo = {
|
||||
'dsa': {
|
||||
parts: ['p', 'q', 'g', 'y'],
|
||||
sizePart: 'p'
|
||||
},
|
||||
'rsa': {
|
||||
parts: ['e', 'n'],
|
||||
sizePart: 'n'
|
||||
},
|
||||
'ecdsa': {
|
||||
parts: ['curve', 'Q'],
|
||||
sizePart: 'Q'
|
||||
},
|
||||
'ed25519': {
|
||||
parts: ['R'],
|
||||
normalize: false,
|
||||
sizePart: 'R'
|
||||
}
|
||||
};
|
||||
algInfo['curve25519'] = algInfo['ed25519'];
|
||||
|
||||
var algPrivInfo = {
|
||||
'dsa': {
|
||||
parts: ['p', 'q', 'g', 'y', 'x']
|
||||
},
|
||||
'rsa': {
|
||||
parts: ['n', 'e', 'd', 'iqmp', 'p', 'q']
|
||||
},
|
||||
'ecdsa': {
|
||||
parts: ['curve', 'Q', 'd']
|
||||
},
|
||||
'ed25519': {
|
||||
parts: ['R', 'r'],
|
||||
normalize: false
|
||||
}
|
||||
};
|
||||
algPrivInfo['curve25519'] = algPrivInfo['ed25519'];
|
||||
|
||||
var hashAlgs = {
|
||||
'md5': true,
|
||||
'sha1': true,
|
||||
'sha256': true,
|
||||
'sha384': true,
|
||||
'sha512': true
|
||||
};
|
||||
|
||||
/*
|
||||
* Taken from
|
||||
* http://csrc.nist.gov/groups/ST/toolkit/documents/dss/NISTReCur.pdf
|
||||
*/
|
||||
var curves = {
|
||||
'nistp256': {
|
||||
size: 256,
|
||||
pkcs8oid: '1.2.840.10045.3.1.7',
|
||||
p: new Buffer(('00' +
|
||||
'ffffffff 00000001 00000000 00000000' +
|
||||
'00000000 ffffffff ffffffff ffffffff').
|
||||
replace(/ /g, ''), 'hex'),
|
||||
a: new Buffer(('00' +
|
||||
'FFFFFFFF 00000001 00000000 00000000' +
|
||||
'00000000 FFFFFFFF FFFFFFFF FFFFFFFC').
|
||||
replace(/ /g, ''), 'hex'),
|
||||
b: new Buffer((
|
||||
'5ac635d8 aa3a93e7 b3ebbd55 769886bc' +
|
||||
'651d06b0 cc53b0f6 3bce3c3e 27d2604b').
|
||||
replace(/ /g, ''), 'hex'),
|
||||
s: new Buffer(('00' +
|
||||
'c49d3608 86e70493 6a6678e1 139d26b7' +
|
||||
'819f7e90').
|
||||
replace(/ /g, ''), 'hex'),
|
||||
n: new Buffer(('00' +
|
||||
'ffffffff 00000000 ffffffff ffffffff' +
|
||||
'bce6faad a7179e84 f3b9cac2 fc632551').
|
||||
replace(/ /g, ''), 'hex'),
|
||||
G: new Buffer(('04' +
|
||||
'6b17d1f2 e12c4247 f8bce6e5 63a440f2' +
|
||||
'77037d81 2deb33a0 f4a13945 d898c296' +
|
||||
'4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16' +
|
||||
'2bce3357 6b315ece cbb64068 37bf51f5').
|
||||
replace(/ /g, ''), 'hex')
|
||||
},
|
||||
'nistp384': {
|
||||
size: 384,
|
||||
pkcs8oid: '1.3.132.0.34',
|
||||
p: new Buffer(('00' +
|
||||
'ffffffff ffffffff ffffffff ffffffff' +
|
||||
'ffffffff ffffffff ffffffff fffffffe' +
|
||||
'ffffffff 00000000 00000000 ffffffff').
|
||||
replace(/ /g, ''), 'hex'),
|
||||
a: new Buffer(('00' +
|
||||
'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' +
|
||||
'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE' +
|
||||
'FFFFFFFF 00000000 00000000 FFFFFFFC').
|
||||
replace(/ /g, ''), 'hex'),
|
||||
b: new Buffer((
|
||||
'b3312fa7 e23ee7e4 988e056b e3f82d19' +
|
||||
'181d9c6e fe814112 0314088f 5013875a' +
|
||||
'c656398d 8a2ed19d 2a85c8ed d3ec2aef').
|
||||
replace(/ /g, ''), 'hex'),
|
||||
s: new Buffer(('00' +
|
||||
'a335926a a319a27a 1d00896a 6773a482' +
|
||||
'7acdac73').
|
||||
replace(/ /g, ''), 'hex'),
|
||||
n: new Buffer(('00' +
|
||||
'ffffffff ffffffff ffffffff ffffffff' +
|
||||
'ffffffff ffffffff c7634d81 f4372ddf' +
|
||||
'581a0db2 48b0a77a ecec196a ccc52973').
|
||||
replace(/ /g, ''), 'hex'),
|
||||
G: new Buffer(('04' +
|
||||
'aa87ca22 be8b0537 8eb1c71e f320ad74' +
|
||||
'6e1d3b62 8ba79b98 59f741e0 82542a38' +
|
||||
'5502f25d bf55296c 3a545e38 72760ab7' +
|
||||
'3617de4a 96262c6f 5d9e98bf 9292dc29' +
|
||||
'f8f41dbd 289a147c e9da3113 b5f0b8c0' +
|
||||
'0a60b1ce 1d7e819d 7a431d7c 90ea0e5f').
|
||||
replace(/ /g, ''), 'hex')
|
||||
},
|
||||
'nistp521': {
|
||||
size: 521,
|
||||
pkcs8oid: '1.3.132.0.35',
|
||||
p: new Buffer((
|
||||
'01ffffff ffffffff ffffffff ffffffff' +
|
||||
'ffffffff ffffffff ffffffff ffffffff' +
|
||||
'ffffffff ffffffff ffffffff ffffffff' +
|
||||
'ffffffff ffffffff ffffffff ffffffff' +
|
||||
'ffff').replace(/ /g, ''), 'hex'),
|
||||
a: new Buffer(('01FF' +
|
||||
'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' +
|
||||
'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' +
|
||||
'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' +
|
||||
'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFC').
|
||||
replace(/ /g, ''), 'hex'),
|
||||
b: new Buffer(('51' +
|
||||
'953eb961 8e1c9a1f 929a21a0 b68540ee' +
|
||||
'a2da725b 99b315f3 b8b48991 8ef109e1' +
|
||||
'56193951 ec7e937b 1652c0bd 3bb1bf07' +
|
||||
'3573df88 3d2c34f1 ef451fd4 6b503f00').
|
||||
replace(/ /g, ''), 'hex'),
|
||||
s: new Buffer(('00' +
|
||||
'd09e8800 291cb853 96cc6717 393284aa' +
|
||||
'a0da64ba').replace(/ /g, ''), 'hex'),
|
||||
n: new Buffer(('01ff' +
|
||||
'ffffffff ffffffff ffffffff ffffffff' +
|
||||
'ffffffff ffffffff ffffffff fffffffa' +
|
||||
'51868783 bf2f966b 7fcc0148 f709a5d0' +
|
||||
'3bb5c9b8 899c47ae bb6fb71e 91386409').
|
||||
replace(/ /g, ''), 'hex'),
|
||||
G: new Buffer(('04' +
|
||||
'00c6 858e06b7 0404e9cd 9e3ecb66 2395b442' +
|
||||
'9c648139 053fb521 f828af60 6b4d3dba' +
|
||||
'a14b5e77 efe75928 fe1dc127 a2ffa8de' +
|
||||
'3348b3c1 856a429b f97e7e31 c2e5bd66' +
|
||||
'0118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9' +
|
||||
'98f54449 579b4468 17afbd17 273e662c' +
|
||||
'97ee7299 5ef42640 c550b901 3fad0761' +
|
||||
'353c7086 a272c240 88be9476 9fd16650').
|
||||
replace(/ /g, ''), 'hex')
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
info: algInfo,
|
||||
privInfo: algPrivInfo,
|
||||
hashAlgs: hashAlgs,
|
||||
curves: curves
|
||||
};
|
377
node_modules/sshpk/lib/certificate.js
generated
vendored
Normal file
377
node_modules/sshpk/lib/certificate.js
generated
vendored
Normal file
@ -0,0 +1,377 @@
|
||||
// Copyright 2016 Joyent, Inc.
|
||||
|
||||
module.exports = Certificate;
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var algs = require('./algs');
|
||||
var crypto = require('crypto');
|
||||
var Fingerprint = require('./fingerprint');
|
||||
var Signature = require('./signature');
|
||||
var errs = require('./errors');
|
||||
var util = require('util');
|
||||
var utils = require('./utils');
|
||||
var Key = require('./key');
|
||||
var PrivateKey = require('./private-key');
|
||||
var Identity = require('./identity');
|
||||
|
||||
var formats = {};
|
||||
formats['openssh'] = require('./formats/openssh-cert');
|
||||
formats['x509'] = require('./formats/x509');
|
||||
formats['pem'] = require('./formats/x509-pem');
|
||||
|
||||
var CertificateParseError = errs.CertificateParseError;
|
||||
var InvalidAlgorithmError = errs.InvalidAlgorithmError;
|
||||
|
||||
function Certificate(opts) {
|
||||
assert.object(opts, 'options');
|
||||
assert.arrayOfObject(opts.subjects, 'options.subjects');
|
||||
utils.assertCompatible(opts.subjects[0], Identity, [1, 0],
|
||||
'options.subjects');
|
||||
utils.assertCompatible(opts.subjectKey, Key, [1, 0],
|
||||
'options.subjectKey');
|
||||
utils.assertCompatible(opts.issuer, Identity, [1, 0], 'options.issuer');
|
||||
if (opts.issuerKey !== undefined) {
|
||||
utils.assertCompatible(opts.issuerKey, Key, [1, 0],
|
||||
'options.issuerKey');
|
||||
}
|
||||
assert.object(opts.signatures, 'options.signatures');
|
||||
assert.buffer(opts.serial, 'options.serial');
|
||||
assert.date(opts.validFrom, 'options.validFrom');
|
||||
assert.date(opts.validUntil, 'optons.validUntil');
|
||||
|
||||
assert.optionalArrayOfString(opts.purposes, 'options.purposes');
|
||||
|
||||
this._hashCache = {};
|
||||
|
||||
this.subjects = opts.subjects;
|
||||
this.issuer = opts.issuer;
|
||||
this.subjectKey = opts.subjectKey;
|
||||
this.issuerKey = opts.issuerKey;
|
||||
this.signatures = opts.signatures;
|
||||
this.serial = opts.serial;
|
||||
this.validFrom = opts.validFrom;
|
||||
this.validUntil = opts.validUntil;
|
||||
this.purposes = opts.purposes;
|
||||
}
|
||||
|
||||
Certificate.formats = formats;
|
||||
|
||||
Certificate.prototype.toBuffer = function (format, options) {
|
||||
if (format === undefined)
|
||||
format = 'x509';
|
||||
assert.string(format, 'format');
|
||||
assert.object(formats[format], 'formats[format]');
|
||||
assert.optionalObject(options, 'options');
|
||||
|
||||
return (formats[format].write(this, options));
|
||||
};
|
||||
|
||||
Certificate.prototype.toString = function (format, options) {
|
||||
if (format === undefined)
|
||||
format = 'pem';
|
||||
return (this.toBuffer(format, options).toString());
|
||||
};
|
||||
|
||||
Certificate.prototype.fingerprint = function (algo) {
|
||||
if (algo === undefined)
|
||||
algo = 'sha256';
|
||||
assert.string(algo, 'algorithm');
|
||||
var opts = {
|
||||
type: 'certificate',
|
||||
hash: this.hash(algo),
|
||||
algorithm: algo
|
||||
};
|
||||
return (new Fingerprint(opts));
|
||||
};
|
||||
|
||||
Certificate.prototype.hash = function (algo) {
|
||||
assert.string(algo, 'algorithm');
|
||||
algo = algo.toLowerCase();
|
||||
if (algs.hashAlgs[algo] === undefined)
|
||||
throw (new InvalidAlgorithmError(algo));
|
||||
|
||||
if (this._hashCache[algo])
|
||||
return (this._hashCache[algo]);
|
||||
|
||||
var hash = crypto.createHash(algo).
|
||||
update(this.toBuffer('x509')).digest();
|
||||
this._hashCache[algo] = hash;
|
||||
return (hash);
|
||||
};
|
||||
|
||||
Certificate.prototype.isExpired = function (when) {
|
||||
if (when === undefined)
|
||||
when = new Date();
|
||||
return (!((when.getTime() >= this.validFrom.getTime()) &&
|
||||
(when.getTime() < this.validUntil.getTime())));
|
||||
};
|
||||
|
||||
Certificate.prototype.isSignedBy = function (issuerCert) {
|
||||
utils.assertCompatible(issuerCert, Certificate, [1, 0], 'issuer');
|
||||
|
||||
if (!this.issuer.equals(issuerCert.subjects[0]))
|
||||
return (false);
|
||||
if (this.issuer.purposes && this.issuer.purposes.length > 0 &&
|
||||
this.issuer.purposes.indexOf('ca') === -1) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (this.isSignedByKey(issuerCert.subjectKey));
|
||||
};
|
||||
|
||||
Certificate.prototype.isSignedByKey = function (issuerKey) {
|
||||
utils.assertCompatible(issuerKey, Key, [1, 2], 'issuerKey');
|
||||
|
||||
if (this.issuerKey !== undefined) {
|
||||
return (this.issuerKey.
|
||||
fingerprint('sha512').matches(issuerKey));
|
||||
}
|
||||
|
||||
var fmt = Object.keys(this.signatures)[0];
|
||||
var valid = formats[fmt].verify(this, issuerKey);
|
||||
if (valid)
|
||||
this.issuerKey = issuerKey;
|
||||
return (valid);
|
||||
};
|
||||
|
||||
Certificate.prototype.signWith = function (key) {
|
||||
utils.assertCompatible(key, PrivateKey, [1, 2], 'key');
|
||||
var fmts = Object.keys(formats);
|
||||
var didOne = false;
|
||||
for (var i = 0; i < fmts.length; ++i) {
|
||||
if (fmts[i] !== 'pem') {
|
||||
var ret = formats[fmts[i]].sign(this, key);
|
||||
if (ret === true)
|
||||
didOne = true;
|
||||
}
|
||||
}
|
||||
if (!didOne) {
|
||||
throw (new Error('Failed to sign the certificate for any ' +
|
||||
'available certificate formats'));
|
||||
}
|
||||
};
|
||||
|
||||
Certificate.createSelfSigned = function (subjectOrSubjects, key, options) {
|
||||
var subjects;
|
||||
if (Array.isArray(subjectOrSubjects))
|
||||
subjects = subjectOrSubjects;
|
||||
else
|
||||
subjects = [subjectOrSubjects];
|
||||
|
||||
assert.arrayOfObject(subjects);
|
||||
subjects.forEach(function (subject) {
|
||||
utils.assertCompatible(subject, Identity, [1, 0], 'subject');
|
||||
});
|
||||
|
||||
utils.assertCompatible(key, PrivateKey, [1, 2], 'private key');
|
||||
|
||||
assert.optionalObject(options, 'options');
|
||||
if (options === undefined)
|
||||
options = {};
|
||||
assert.optionalObject(options.validFrom, 'options.validFrom');
|
||||
assert.optionalObject(options.validUntil, 'options.validUntil');
|
||||
var validFrom = options.validFrom;
|
||||
var validUntil = options.validUntil;
|
||||
if (validFrom === undefined)
|
||||
validFrom = new Date();
|
||||
if (validUntil === undefined) {
|
||||
assert.optionalNumber(options.lifetime, 'options.lifetime');
|
||||
var lifetime = options.lifetime;
|
||||
if (lifetime === undefined)
|
||||
lifetime = 10*365*24*3600;
|
||||
validUntil = new Date();
|
||||
validUntil.setTime(validUntil.getTime() + lifetime*1000);
|
||||
}
|
||||
assert.optionalBuffer(options.serial, 'options.serial');
|
||||
var serial = options.serial;
|
||||
if (serial === undefined)
|
||||
serial = new Buffer('0000000000000001', 'hex');
|
||||
|
||||
var purposes = options.purposes;
|
||||
if (purposes === undefined)
|
||||
purposes = [];
|
||||
|
||||
if (purposes.indexOf('signature') === -1)
|
||||
purposes.push('signature');
|
||||
|
||||
/* Self-signed certs are always CAs. */
|
||||
if (purposes.indexOf('ca') === -1)
|
||||
purposes.push('ca');
|
||||
if (purposes.indexOf('crl') === -1)
|
||||
purposes.push('crl');
|
||||
|
||||
/*
|
||||
* If we weren't explicitly given any other purposes, do the sensible
|
||||
* thing and add some basic ones depending on the subject type.
|
||||
*/
|
||||
if (purposes.length <= 3) {
|
||||
var hostSubjects = subjects.filter(function (subject) {
|
||||
return (subject.type === 'host');
|
||||
});
|
||||
var userSubjects = subjects.filter(function (subject) {
|
||||
return (subject.type === 'user');
|
||||
});
|
||||
if (hostSubjects.length > 0) {
|
||||
if (purposes.indexOf('serverAuth') === -1)
|
||||
purposes.push('serverAuth');
|
||||
}
|
||||
if (userSubjects.length > 0) {
|
||||
if (purposes.indexOf('clientAuth') === -1)
|
||||
purposes.push('clientAuth');
|
||||
}
|
||||
if (userSubjects.length > 0 || hostSubjects.length > 0) {
|
||||
if (purposes.indexOf('keyAgreement') === -1)
|
||||
purposes.push('keyAgreement');
|
||||
if (key.type === 'rsa' &&
|
||||
purposes.indexOf('encryption') === -1)
|
||||
purposes.push('encryption');
|
||||
}
|
||||
}
|
||||
|
||||
var cert = new Certificate({
|
||||
subjects: subjects,
|
||||
issuer: subjects[0],
|
||||
subjectKey: key.toPublic(),
|
||||
issuerKey: key.toPublic(),
|
||||
signatures: {},
|
||||
serial: serial,
|
||||
validFrom: validFrom,
|
||||
validUntil: validUntil,
|
||||
purposes: purposes
|
||||
});
|
||||
cert.signWith(key);
|
||||
|
||||
return (cert);
|
||||
};
|
||||
|
||||
Certificate.create =
|
||||
function (subjectOrSubjects, key, issuer, issuerKey, options) {
|
||||
var subjects;
|
||||
if (Array.isArray(subjectOrSubjects))
|
||||
subjects = subjectOrSubjects;
|
||||
else
|
||||
subjects = [subjectOrSubjects];
|
||||
|
||||
assert.arrayOfObject(subjects);
|
||||
subjects.forEach(function (subject) {
|
||||
utils.assertCompatible(subject, Identity, [1, 0], 'subject');
|
||||
});
|
||||
|
||||
utils.assertCompatible(key, Key, [1, 0], 'key');
|
||||
if (PrivateKey.isPrivateKey(key))
|
||||
key = key.toPublic();
|
||||
utils.assertCompatible(issuer, Identity, [1, 0], 'issuer');
|
||||
utils.assertCompatible(issuerKey, PrivateKey, [1, 2], 'issuer key');
|
||||
|
||||
assert.optionalObject(options, 'options');
|
||||
if (options === undefined)
|
||||
options = {};
|
||||
assert.optionalObject(options.validFrom, 'options.validFrom');
|
||||
assert.optionalObject(options.validUntil, 'options.validUntil');
|
||||
var validFrom = options.validFrom;
|
||||
var validUntil = options.validUntil;
|
||||
if (validFrom === undefined)
|
||||
validFrom = new Date();
|
||||
if (validUntil === undefined) {
|
||||
assert.optionalNumber(options.lifetime, 'options.lifetime');
|
||||
var lifetime = options.lifetime;
|
||||
if (lifetime === undefined)
|
||||
lifetime = 10*365*24*3600;
|
||||
validUntil = new Date();
|
||||
validUntil.setTime(validUntil.getTime() + lifetime*1000);
|
||||
}
|
||||
assert.optionalBuffer(options.serial, 'options.serial');
|
||||
var serial = options.serial;
|
||||
if (serial === undefined)
|
||||
serial = new Buffer('0000000000000001', 'hex');
|
||||
|
||||
var purposes = options.purposes;
|
||||
if (purposes === undefined)
|
||||
purposes = [];
|
||||
|
||||
if (purposes.indexOf('signature') === -1)
|
||||
purposes.push('signature');
|
||||
|
||||
if (options.ca === true) {
|
||||
if (purposes.indexOf('ca') === -1)
|
||||
purposes.push('ca');
|
||||
if (purposes.indexOf('crl') === -1)
|
||||
purposes.push('crl');
|
||||
}
|
||||
|
||||
var hostSubjects = subjects.filter(function (subject) {
|
||||
return (subject.type === 'host');
|
||||
});
|
||||
var userSubjects = subjects.filter(function (subject) {
|
||||
return (subject.type === 'user');
|
||||
});
|
||||
if (hostSubjects.length > 0) {
|
||||
if (purposes.indexOf('serverAuth') === -1)
|
||||
purposes.push('serverAuth');
|
||||
}
|
||||
if (userSubjects.length > 0) {
|
||||
if (purposes.indexOf('clientAuth') === -1)
|
||||
purposes.push('clientAuth');
|
||||
}
|
||||
if (userSubjects.length > 0 || hostSubjects.length > 0) {
|
||||
if (purposes.indexOf('keyAgreement') === -1)
|
||||
purposes.push('keyAgreement');
|
||||
if (key.type === 'rsa' &&
|
||||
purposes.indexOf('encryption') === -1)
|
||||
purposes.push('encryption');
|
||||
}
|
||||
|
||||
var cert = new Certificate({
|
||||
subjects: subjects,
|
||||
issuer: issuer,
|
||||
subjectKey: key,
|
||||
issuerKey: issuerKey.toPublic(),
|
||||
signatures: {},
|
||||
serial: serial,
|
||||
validFrom: validFrom,
|
||||
validUntil: validUntil,
|
||||
purposes: purposes
|
||||
});
|
||||
cert.signWith(issuerKey);
|
||||
|
||||
return (cert);
|
||||
};
|
||||
|
||||
Certificate.parse = function (data, format, options) {
|
||||
if (typeof (data) !== 'string')
|
||||
assert.buffer(data, 'data');
|
||||
if (format === undefined)
|
||||
format = 'auto';
|
||||
assert.string(format, 'format');
|
||||
if (typeof (options) === 'string')
|
||||
options = { filename: options };
|
||||
assert.optionalObject(options, 'options');
|
||||
if (options === undefined)
|
||||
options = {};
|
||||
assert.optionalString(options.filename, 'options.filename');
|
||||
if (options.filename === undefined)
|
||||
options.filename = '(unnamed)';
|
||||
|
||||
assert.object(formats[format], 'formats[format]');
|
||||
|
||||
try {
|
||||
var k = formats[format].read(data, options);
|
||||
return (k);
|
||||
} catch (e) {
|
||||
throw (new CertificateParseError(options.filename, format, e));
|
||||
}
|
||||
};
|
||||
|
||||
Certificate.isCertificate = function (obj, ver) {
|
||||
return (utils.isCompatible(obj, Certificate, ver));
|
||||
};
|
||||
|
||||
/*
|
||||
* API versions for Certificate:
|
||||
* [1,0] -- initial ver
|
||||
*/
|
||||
Certificate.prototype._sshpkApiVersion = [1, 0];
|
||||
|
||||
Certificate._oldVersionDetect = function (obj) {
|
||||
return ([1, 0]);
|
||||
};
|
410
node_modules/sshpk/lib/dhe.js
generated
vendored
Normal file
410
node_modules/sshpk/lib/dhe.js
generated
vendored
Normal file
@ -0,0 +1,410 @@
|
||||
// Copyright 2017 Joyent, Inc.
|
||||
|
||||
module.exports = {
|
||||
DiffieHellman: DiffieHellman,
|
||||
generateECDSA: generateECDSA,
|
||||
generateED25519: generateED25519
|
||||
};
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var crypto = require('crypto');
|
||||
var algs = require('./algs');
|
||||
var utils = require('./utils');
|
||||
var ed;
|
||||
var nacl;
|
||||
|
||||
var Key = require('./key');
|
||||
var PrivateKey = require('./private-key');
|
||||
|
||||
var CRYPTO_HAVE_ECDH = (crypto.createECDH !== undefined);
|
||||
|
||||
var ecdh, ec, jsbn;
|
||||
|
||||
function DiffieHellman(key) {
|
||||
utils.assertCompatible(key, Key, [1, 4], 'key');
|
||||
this._isPriv = PrivateKey.isPrivateKey(key, [1, 3]);
|
||||
this._algo = key.type;
|
||||
this._curve = key.curve;
|
||||
this._key = key;
|
||||
if (key.type === 'dsa') {
|
||||
if (!CRYPTO_HAVE_ECDH) {
|
||||
throw (new Error('Due to bugs in the node 0.10 ' +
|
||||
'crypto API, node 0.12.x or later is required ' +
|
||||
'to use DH'));
|
||||
}
|
||||
this._dh = crypto.createDiffieHellman(
|
||||
key.part.p.data, undefined,
|
||||
key.part.g.data, undefined);
|
||||
this._p = key.part.p;
|
||||
this._g = key.part.g;
|
||||
if (this._isPriv)
|
||||
this._dh.setPrivateKey(key.part.x.data);
|
||||
this._dh.setPublicKey(key.part.y.data);
|
||||
|
||||
} else if (key.type === 'ecdsa') {
|
||||
if (!CRYPTO_HAVE_ECDH) {
|
||||
if (ecdh === undefined)
|
||||
ecdh = require('ecc-jsbn');
|
||||
if (ec === undefined)
|
||||
ec = require('ecc-jsbn/lib/ec');
|
||||
if (jsbn === undefined)
|
||||
jsbn = require('jsbn').BigInteger;
|
||||
|
||||
this._ecParams = new X9ECParameters(this._curve);
|
||||
|
||||
if (this._isPriv) {
|
||||
this._priv = new ECPrivate(
|
||||
this._ecParams, key.part.d.data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var curve = {
|
||||
'nistp256': 'prime256v1',
|
||||
'nistp384': 'secp384r1',
|
||||
'nistp521': 'secp521r1'
|
||||
}[key.curve];
|
||||
this._dh = crypto.createECDH(curve);
|
||||
if (typeof (this._dh) !== 'object' ||
|
||||
typeof (this._dh.setPrivateKey) !== 'function') {
|
||||
CRYPTO_HAVE_ECDH = false;
|
||||
DiffieHellman.call(this, key);
|
||||
return;
|
||||
}
|
||||
if (this._isPriv)
|
||||
this._dh.setPrivateKey(key.part.d.data);
|
||||
this._dh.setPublicKey(key.part.Q.data);
|
||||
|
||||
} else if (key.type === 'curve25519') {
|
||||
if (ed === undefined)
|
||||
ed = require('jodid25519');
|
||||
|
||||
if (this._isPriv) {
|
||||
this._priv = key.part.r.data;
|
||||
if (this._priv[0] === 0x00)
|
||||
this._priv = this._priv.slice(1);
|
||||
this._priv = this._priv.slice(0, 32);
|
||||
}
|
||||
|
||||
} else {
|
||||
throw (new Error('DH not supported for ' + key.type + ' keys'));
|
||||
}
|
||||
}
|
||||
|
||||
DiffieHellman.prototype.getPublicKey = function () {
|
||||
if (this._isPriv)
|
||||
return (this._key.toPublic());
|
||||
return (this._key);
|
||||
};
|
||||
|
||||
DiffieHellman.prototype.getPrivateKey = function () {
|
||||
if (this._isPriv)
|
||||
return (this._key);
|
||||
else
|
||||
return (undefined);
|
||||
};
|
||||
DiffieHellman.prototype.getKey = DiffieHellman.prototype.getPrivateKey;
|
||||
|
||||
DiffieHellman.prototype._keyCheck = function (pk, isPub) {
|
||||
assert.object(pk, 'key');
|
||||
if (!isPub)
|
||||
utils.assertCompatible(pk, PrivateKey, [1, 3], 'key');
|
||||
utils.assertCompatible(pk, Key, [1, 4], 'key');
|
||||
|
||||
if (pk.type !== this._algo) {
|
||||
throw (new Error('A ' + pk.type + ' key cannot be used in ' +
|
||||
this._algo + ' Diffie-Hellman'));
|
||||
}
|
||||
|
||||
if (pk.curve !== this._curve) {
|
||||
throw (new Error('A key from the ' + pk.curve + ' curve ' +
|
||||
'cannot be used with a ' + this._curve +
|
||||
' Diffie-Hellman'));
|
||||
}
|
||||
|
||||
if (pk.type === 'dsa') {
|
||||
assert.deepEqual(pk.part.p, this._p,
|
||||
'DSA key prime does not match');
|
||||
assert.deepEqual(pk.part.g, this._g,
|
||||
'DSA key generator does not match');
|
||||
}
|
||||
};
|
||||
|
||||
DiffieHellman.prototype.setKey = function (pk) {
|
||||
this._keyCheck(pk);
|
||||
|
||||
if (pk.type === 'dsa') {
|
||||
this._dh.setPrivateKey(pk.part.x.data);
|
||||
this._dh.setPublicKey(pk.part.y.data);
|
||||
|
||||
} else if (pk.type === 'ecdsa') {
|
||||
if (CRYPTO_HAVE_ECDH) {
|
||||
this._dh.setPrivateKey(pk.part.d.data);
|
||||
this._dh.setPublicKey(pk.part.Q.data);
|
||||
} else {
|
||||
this._priv = new ECPrivate(
|
||||
this._ecParams, pk.part.d.data);
|
||||
}
|
||||
|
||||
} else if (pk.type === 'curve25519') {
|
||||
this._priv = pk.part.r.data;
|
||||
if (this._priv[0] === 0x00)
|
||||
this._priv = this._priv.slice(1);
|
||||
this._priv = this._priv.slice(0, 32);
|
||||
}
|
||||
this._key = pk;
|
||||
this._isPriv = true;
|
||||
};
|
||||
DiffieHellman.prototype.setPrivateKey = DiffieHellman.prototype.setKey;
|
||||
|
||||
DiffieHellman.prototype.computeSecret = function (otherpk) {
|
||||
this._keyCheck(otherpk, true);
|
||||
if (!this._isPriv)
|
||||
throw (new Error('DH exchange has not been initialized with ' +
|
||||
'a private key yet'));
|
||||
|
||||
var pub;
|
||||
if (this._algo === 'dsa') {
|
||||
return (this._dh.computeSecret(
|
||||
otherpk.part.y.data));
|
||||
|
||||
} else if (this._algo === 'ecdsa') {
|
||||
if (CRYPTO_HAVE_ECDH) {
|
||||
return (this._dh.computeSecret(
|
||||
otherpk.part.Q.data));
|
||||
} else {
|
||||
pub = new ECPublic(
|
||||
this._ecParams, otherpk.part.Q.data);
|
||||
return (this._priv.deriveSharedSecret(pub));
|
||||
}
|
||||
|
||||
} else if (this._algo === 'curve25519') {
|
||||
pub = otherpk.part.R.data;
|
||||
if (pub[0] === 0x00)
|
||||
pub = pub.slice(1);
|
||||
|
||||
var secret = ed.dh.computeKey(
|
||||
this._priv.toString('binary'),
|
||||
pub.toString('binary'));
|
||||
|
||||
return (new Buffer(secret, 'binary'));
|
||||
}
|
||||
|
||||
throw (new Error('Invalid algorithm: ' + this._algo));
|
||||
};
|
||||
|
||||
DiffieHellman.prototype.generateKey = function () {
|
||||
var parts = [];
|
||||
var priv, pub;
|
||||
if (this._algo === 'dsa') {
|
||||
this._dh.generateKeys();
|
||||
|
||||
parts.push({name: 'p', data: this._p.data});
|
||||
parts.push({name: 'q', data: this._key.part.q.data});
|
||||
parts.push({name: 'g', data: this._g.data});
|
||||
parts.push({name: 'y', data: this._dh.getPublicKey()});
|
||||
parts.push({name: 'x', data: this._dh.getPrivateKey()});
|
||||
this._key = new PrivateKey({
|
||||
type: 'dsa',
|
||||
parts: parts
|
||||
});
|
||||
this._isPriv = true;
|
||||
return (this._key);
|
||||
|
||||
} else if (this._algo === 'ecdsa') {
|
||||
if (CRYPTO_HAVE_ECDH) {
|
||||
this._dh.generateKeys();
|
||||
|
||||
parts.push({name: 'curve',
|
||||
data: new Buffer(this._curve)});
|
||||
parts.push({name: 'Q', data: this._dh.getPublicKey()});
|
||||
parts.push({name: 'd', data: this._dh.getPrivateKey()});
|
||||
this._key = new PrivateKey({
|
||||
type: 'ecdsa',
|
||||
curve: this._curve,
|
||||
parts: parts
|
||||
});
|
||||
this._isPriv = true;
|
||||
return (this._key);
|
||||
|
||||
} else {
|
||||
var n = this._ecParams.getN();
|
||||
var r = new jsbn(crypto.randomBytes(n.bitLength()));
|
||||
var n1 = n.subtract(jsbn.ONE);
|
||||
priv = r.mod(n1).add(jsbn.ONE);
|
||||
pub = this._ecParams.getG().multiply(priv);
|
||||
|
||||
priv = new Buffer(priv.toByteArray());
|
||||
pub = new Buffer(this._ecParams.getCurve().
|
||||
encodePointHex(pub), 'hex');
|
||||
|
||||
this._priv = new ECPrivate(this._ecParams, priv);
|
||||
|
||||
parts.push({name: 'curve',
|
||||
data: new Buffer(this._curve)});
|
||||
parts.push({name: 'Q', data: pub});
|
||||
parts.push({name: 'd', data: priv});
|
||||
|
||||
this._key = new PrivateKey({
|
||||
type: 'ecdsa',
|
||||
curve: this._curve,
|
||||
parts: parts
|
||||
});
|
||||
this._isPriv = true;
|
||||
return (this._key);
|
||||
}
|
||||
|
||||
} else if (this._algo === 'curve25519') {
|
||||
priv = ed.dh.generateKey();
|
||||
pub = ed.dh.publicKey(priv);
|
||||
this._priv = priv = new Buffer(priv, 'binary');
|
||||
pub = new Buffer(pub, 'binary');
|
||||
|
||||
parts.push({name: 'R', data: pub});
|
||||
parts.push({name: 'r', data: Buffer.concat([priv, pub])});
|
||||
this._key = new PrivateKey({
|
||||
type: 'curve25519',
|
||||
parts: parts
|
||||
});
|
||||
this._isPriv = true;
|
||||
return (this._key);
|
||||
}
|
||||
|
||||
throw (new Error('Invalid algorithm: ' + this._algo));
|
||||
};
|
||||
DiffieHellman.prototype.generateKeys = DiffieHellman.prototype.generateKey;
|
||||
|
||||
/* These are helpers for using ecc-jsbn (for node 0.10 compatibility). */
|
||||
|
||||
function X9ECParameters(name) {
|
||||
var params = algs.curves[name];
|
||||
assert.object(params);
|
||||
|
||||
var p = new jsbn(params.p);
|
||||
var a = new jsbn(params.a);
|
||||
var b = new jsbn(params.b);
|
||||
var n = new jsbn(params.n);
|
||||
var h = jsbn.ONE;
|
||||
var curve = new ec.ECCurveFp(p, a, b);
|
||||
var G = curve.decodePointHex(params.G.toString('hex'));
|
||||
|
||||
this.curve = curve;
|
||||
this.g = G;
|
||||
this.n = n;
|
||||
this.h = h;
|
||||
}
|
||||
X9ECParameters.prototype.getCurve = function () { return (this.curve); };
|
||||
X9ECParameters.prototype.getG = function () { return (this.g); };
|
||||
X9ECParameters.prototype.getN = function () { return (this.n); };
|
||||
X9ECParameters.prototype.getH = function () { return (this.h); };
|
||||
|
||||
function ECPublic(params, buffer) {
|
||||
this._params = params;
|
||||
if (buffer[0] === 0x00)
|
||||
buffer = buffer.slice(1);
|
||||
this._pub = params.getCurve().decodePointHex(buffer.toString('hex'));
|
||||
}
|
||||
|
||||
function ECPrivate(params, buffer) {
|
||||
this._params = params;
|
||||
this._priv = new jsbn(utils.mpNormalize(buffer));
|
||||
}
|
||||
ECPrivate.prototype.deriveSharedSecret = function (pubKey) {
|
||||
assert.ok(pubKey instanceof ECPublic);
|
||||
var S = pubKey._pub.multiply(this._priv);
|
||||
return (new Buffer(S.getX().toBigInteger().toByteArray()));
|
||||
};
|
||||
|
||||
function generateED25519() {
|
||||
if (nacl === undefined)
|
||||
nacl = require('tweetnacl');
|
||||
|
||||
var pair = nacl.sign.keyPair();
|
||||
var priv = new Buffer(pair.secretKey);
|
||||
var pub = new Buffer(pair.publicKey);
|
||||
assert.strictEqual(priv.length, 64);
|
||||
assert.strictEqual(pub.length, 32);
|
||||
|
||||
var parts = [];
|
||||
parts.push({name: 'R', data: pub});
|
||||
parts.push({name: 'r', data: priv});
|
||||
var key = new PrivateKey({
|
||||
type: 'ed25519',
|
||||
parts: parts
|
||||
});
|
||||
return (key);
|
||||
}
|
||||
|
||||
/* Generates a new ECDSA private key on a given curve. */
|
||||
function generateECDSA(curve) {
|
||||
var parts = [];
|
||||
var key;
|
||||
|
||||
if (CRYPTO_HAVE_ECDH) {
|
||||
/*
|
||||
* Node crypto doesn't expose key generation directly, but the
|
||||
* ECDH instances can generate keys. It turns out this just
|
||||
* calls into the OpenSSL generic key generator, and we can
|
||||
* read its output happily without doing an actual DH. So we
|
||||
* use that here.
|
||||
*/
|
||||
var osCurve = {
|
||||
'nistp256': 'prime256v1',
|
||||
'nistp384': 'secp384r1',
|
||||
'nistp521': 'secp521r1'
|
||||
}[curve];
|
||||
|
||||
var dh = crypto.createECDH(osCurve);
|
||||
dh.generateKeys();
|
||||
|
||||
parts.push({name: 'curve',
|
||||
data: new Buffer(curve)});
|
||||
parts.push({name: 'Q', data: dh.getPublicKey()});
|
||||
parts.push({name: 'd', data: dh.getPrivateKey()});
|
||||
|
||||
key = new PrivateKey({
|
||||
type: 'ecdsa',
|
||||
curve: curve,
|
||||
parts: parts
|
||||
});
|
||||
return (key);
|
||||
|
||||
} else {
|
||||
if (ecdh === undefined)
|
||||
ecdh = require('ecc-jsbn');
|
||||
if (ec === undefined)
|
||||
ec = require('ecc-jsbn/lib/ec');
|
||||
if (jsbn === undefined)
|
||||
jsbn = require('jsbn').BigInteger;
|
||||
|
||||
var ecParams = new X9ECParameters(curve);
|
||||
|
||||
/* This algorithm taken from FIPS PUB 186-4 (section B.4.1) */
|
||||
var n = ecParams.getN();
|
||||
/*
|
||||
* The crypto.randomBytes() function can only give us whole
|
||||
* bytes, so taking a nod from X9.62, we round up.
|
||||
*/
|
||||
var cByteLen = Math.ceil((n.bitLength() + 64) / 8);
|
||||
var c = new jsbn(crypto.randomBytes(cByteLen));
|
||||
|
||||
var n1 = n.subtract(jsbn.ONE);
|
||||
var priv = c.mod(n1).add(jsbn.ONE);
|
||||
var pub = ecParams.getG().multiply(priv);
|
||||
|
||||
priv = new Buffer(priv.toByteArray());
|
||||
pub = new Buffer(ecParams.getCurve().
|
||||
encodePointHex(pub), 'hex');
|
||||
|
||||
parts.push({name: 'curve', data: new Buffer(curve)});
|
||||
parts.push({name: 'Q', data: pub});
|
||||
parts.push({name: 'd', data: priv});
|
||||
|
||||
key = new PrivateKey({
|
||||
type: 'ecdsa',
|
||||
curve: curve,
|
||||
parts: parts
|
||||
});
|
||||
return (key);
|
||||
}
|
||||
}
|
96
node_modules/sshpk/lib/ed-compat.js
generated
vendored
Normal file
96
node_modules/sshpk/lib/ed-compat.js
generated
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
// Copyright 2015 Joyent, Inc.
|
||||
|
||||
module.exports = {
|
||||
Verifier: Verifier,
|
||||
Signer: Signer
|
||||
};
|
||||
|
||||
var nacl;
|
||||
var stream = require('stream');
|
||||
var util = require('util');
|
||||
var assert = require('assert-plus');
|
||||
var Signature = require('./signature');
|
||||
|
||||
function Verifier(key, hashAlgo) {
|
||||
if (nacl === undefined)
|
||||
nacl = require('tweetnacl');
|
||||
|
||||
if (hashAlgo.toLowerCase() !== 'sha512')
|
||||
throw (new Error('ED25519 only supports the use of ' +
|
||||
'SHA-512 hashes'));
|
||||
|
||||
this.key = key;
|
||||
this.chunks = [];
|
||||
|
||||
stream.Writable.call(this, {});
|
||||
}
|
||||
util.inherits(Verifier, stream.Writable);
|
||||
|
||||
Verifier.prototype._write = function (chunk, enc, cb) {
|
||||
this.chunks.push(chunk);
|
||||
cb();
|
||||
};
|
||||
|
||||
Verifier.prototype.update = function (chunk) {
|
||||
if (typeof (chunk) === 'string')
|
||||
chunk = new Buffer(chunk, 'binary');
|
||||
this.chunks.push(chunk);
|
||||
};
|
||||
|
||||
Verifier.prototype.verify = function (signature, fmt) {
|
||||
var sig;
|
||||
if (Signature.isSignature(signature, [2, 0])) {
|
||||
if (signature.type !== 'ed25519')
|
||||
return (false);
|
||||
sig = signature.toBuffer('raw');
|
||||
|
||||
} else if (typeof (signature) === 'string') {
|
||||
sig = new Buffer(signature, 'base64');
|
||||
|
||||
} else if (Signature.isSignature(signature, [1, 0])) {
|
||||
throw (new Error('signature was created by too old ' +
|
||||
'a version of sshpk and cannot be verified'));
|
||||
}
|
||||
|
||||
assert.buffer(sig);
|
||||
return (nacl.sign.detached.verify(
|
||||
new Uint8Array(Buffer.concat(this.chunks)),
|
||||
new Uint8Array(sig),
|
||||
new Uint8Array(this.key.part.R.data)));
|
||||
};
|
||||
|
||||
function Signer(key, hashAlgo) {
|
||||
if (nacl === undefined)
|
||||
nacl = require('tweetnacl');
|
||||
|
||||
if (hashAlgo.toLowerCase() !== 'sha512')
|
||||
throw (new Error('ED25519 only supports the use of ' +
|
||||
'SHA-512 hashes'));
|
||||
|
||||
this.key = key;
|
||||
this.chunks = [];
|
||||
|
||||
stream.Writable.call(this, {});
|
||||
}
|
||||
util.inherits(Signer, stream.Writable);
|
||||
|
||||
Signer.prototype._write = function (chunk, enc, cb) {
|
||||
this.chunks.push(chunk);
|
||||
cb();
|
||||
};
|
||||
|
||||
Signer.prototype.update = function (chunk) {
|
||||
if (typeof (chunk) === 'string')
|
||||
chunk = new Buffer(chunk, 'binary');
|
||||
this.chunks.push(chunk);
|
||||
};
|
||||
|
||||
Signer.prototype.sign = function () {
|
||||
var sig = nacl.sign.detached(
|
||||
new Uint8Array(Buffer.concat(this.chunks)),
|
||||
new Uint8Array(this.key.part.r.data));
|
||||
var sigBuf = new Buffer(sig);
|
||||
var sigObj = Signature.parse(sigBuf, 'ed25519', 'raw');
|
||||
sigObj.hashAlgorithm = 'sha512';
|
||||
return (sigObj);
|
||||
};
|
84
node_modules/sshpk/lib/errors.js
generated
vendored
Normal file
84
node_modules/sshpk/lib/errors.js
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
// Copyright 2015 Joyent, Inc.
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var util = require('util');
|
||||
|
||||
function FingerprintFormatError(fp, format) {
|
||||
if (Error.captureStackTrace)
|
||||
Error.captureStackTrace(this, FingerprintFormatError);
|
||||
this.name = 'FingerprintFormatError';
|
||||
this.fingerprint = fp;
|
||||
this.format = format;
|
||||
this.message = 'Fingerprint format is not supported, or is invalid: ';
|
||||
if (fp !== undefined)
|
||||
this.message += ' fingerprint = ' + fp;
|
||||
if (format !== undefined)
|
||||
this.message += ' format = ' + format;
|
||||
}
|
||||
util.inherits(FingerprintFormatError, Error);
|
||||
|
||||
function InvalidAlgorithmError(alg) {
|
||||
if (Error.captureStackTrace)
|
||||
Error.captureStackTrace(this, InvalidAlgorithmError);
|
||||
this.name = 'InvalidAlgorithmError';
|
||||
this.algorithm = alg;
|
||||
this.message = 'Algorithm "' + alg + '" is not supported';
|
||||
}
|
||||
util.inherits(InvalidAlgorithmError, Error);
|
||||
|
||||
function KeyParseError(name, format, innerErr) {
|
||||
if (Error.captureStackTrace)
|
||||
Error.captureStackTrace(this, KeyParseError);
|
||||
this.name = 'KeyParseError';
|
||||
this.format = format;
|
||||
this.keyName = name;
|
||||
this.innerErr = innerErr;
|
||||
this.message = 'Failed to parse ' + name + ' as a valid ' + format +
|
||||
' format key: ' + innerErr.message;
|
||||
}
|
||||
util.inherits(KeyParseError, Error);
|
||||
|
||||
function SignatureParseError(type, format, innerErr) {
|
||||
if (Error.captureStackTrace)
|
||||
Error.captureStackTrace(this, SignatureParseError);
|
||||
this.name = 'SignatureParseError';
|
||||
this.type = type;
|
||||
this.format = format;
|
||||
this.innerErr = innerErr;
|
||||
this.message = 'Failed to parse the given data as a ' + type +
|
||||
' signature in ' + format + ' format: ' + innerErr.message;
|
||||
}
|
||||
util.inherits(SignatureParseError, Error);
|
||||
|
||||
function CertificateParseError(name, format, innerErr) {
|
||||
if (Error.captureStackTrace)
|
||||
Error.captureStackTrace(this, CertificateParseError);
|
||||
this.name = 'CertificateParseError';
|
||||
this.format = format;
|
||||
this.certName = name;
|
||||
this.innerErr = innerErr;
|
||||
this.message = 'Failed to parse ' + name + ' as a valid ' + format +
|
||||
' format certificate: ' + innerErr.message;
|
||||
}
|
||||
util.inherits(CertificateParseError, Error);
|
||||
|
||||
function KeyEncryptedError(name, format) {
|
||||
if (Error.captureStackTrace)
|
||||
Error.captureStackTrace(this, KeyEncryptedError);
|
||||
this.name = 'KeyEncryptedError';
|
||||
this.format = format;
|
||||
this.keyName = name;
|
||||
this.message = 'The ' + format + ' format key ' + name + ' is ' +
|
||||
'encrypted (password-protected), and no passphrase was ' +
|
||||
'provided in `options`';
|
||||
}
|
||||
util.inherits(KeyEncryptedError, Error);
|
||||
|
||||
module.exports = {
|
||||
FingerprintFormatError: FingerprintFormatError,
|
||||
InvalidAlgorithmError: InvalidAlgorithmError,
|
||||
KeyParseError: KeyParseError,
|
||||
SignatureParseError: SignatureParseError,
|
||||
KeyEncryptedError: KeyEncryptedError,
|
||||
CertificateParseError: CertificateParseError
|
||||
};
|
161
node_modules/sshpk/lib/fingerprint.js
generated
vendored
Normal file
161
node_modules/sshpk/lib/fingerprint.js
generated
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
// Copyright 2015 Joyent, Inc.
|
||||
|
||||
module.exports = Fingerprint;
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var algs = require('./algs');
|
||||
var crypto = require('crypto');
|
||||
var errs = require('./errors');
|
||||
var Key = require('./key');
|
||||
var Certificate = require('./certificate');
|
||||
var utils = require('./utils');
|
||||
|
||||
var FingerprintFormatError = errs.FingerprintFormatError;
|
||||
var InvalidAlgorithmError = errs.InvalidAlgorithmError;
|
||||
|
||||
function Fingerprint(opts) {
|
||||
assert.object(opts, 'options');
|
||||
assert.string(opts.type, 'options.type');
|
||||
assert.buffer(opts.hash, 'options.hash');
|
||||
assert.string(opts.algorithm, 'options.algorithm');
|
||||
|
||||
this.algorithm = opts.algorithm.toLowerCase();
|
||||
if (algs.hashAlgs[this.algorithm] !== true)
|
||||
throw (new InvalidAlgorithmError(this.algorithm));
|
||||
|
||||
this.hash = opts.hash;
|
||||
this.type = opts.type;
|
||||
}
|
||||
|
||||
Fingerprint.prototype.toString = function (format) {
|
||||
if (format === undefined) {
|
||||
if (this.algorithm === 'md5')
|
||||
format = 'hex';
|
||||
else
|
||||
format = 'base64';
|
||||
}
|
||||
assert.string(format);
|
||||
|
||||
switch (format) {
|
||||
case 'hex':
|
||||
return (addColons(this.hash.toString('hex')));
|
||||
case 'base64':
|
||||
return (sshBase64Format(this.algorithm,
|
||||
this.hash.toString('base64')));
|
||||
default:
|
||||
throw (new FingerprintFormatError(undefined, format));
|
||||
}
|
||||
};
|
||||
|
||||
Fingerprint.prototype.matches = function (other) {
|
||||
assert.object(other, 'key or certificate');
|
||||
if (this.type === 'key') {
|
||||
utils.assertCompatible(other, Key, [1, 0], 'key');
|
||||
} else {
|
||||
utils.assertCompatible(other, Certificate, [1, 0],
|
||||
'certificate');
|
||||
}
|
||||
|
||||
var theirHash = other.hash(this.algorithm);
|
||||
var theirHash2 = crypto.createHash(this.algorithm).
|
||||
update(theirHash).digest('base64');
|
||||
|
||||
if (this.hash2 === undefined)
|
||||
this.hash2 = crypto.createHash(this.algorithm).
|
||||
update(this.hash).digest('base64');
|
||||
|
||||
return (this.hash2 === theirHash2);
|
||||
};
|
||||
|
||||
Fingerprint.parse = function (fp, options) {
|
||||
assert.string(fp, 'fingerprint');
|
||||
|
||||
var alg, hash, enAlgs;
|
||||
if (Array.isArray(options)) {
|
||||
enAlgs = options;
|
||||
options = {};
|
||||
}
|
||||
assert.optionalObject(options, 'options');
|
||||
if (options === undefined)
|
||||
options = {};
|
||||
if (options.enAlgs !== undefined)
|
||||
enAlgs = options.enAlgs;
|
||||
assert.optionalArrayOfString(enAlgs, 'algorithms');
|
||||
|
||||
var parts = fp.split(':');
|
||||
if (parts.length == 2) {
|
||||
alg = parts[0].toLowerCase();
|
||||
/*JSSTYLED*/
|
||||
var base64RE = /^[A-Za-z0-9+\/=]+$/;
|
||||
if (!base64RE.test(parts[1]))
|
||||
throw (new FingerprintFormatError(fp));
|
||||
try {
|
||||
hash = new Buffer(parts[1], 'base64');
|
||||
} catch (e) {
|
||||
throw (new FingerprintFormatError(fp));
|
||||
}
|
||||
} else if (parts.length > 2) {
|
||||
alg = 'md5';
|
||||
if (parts[0].toLowerCase() === 'md5')
|
||||
parts = parts.slice(1);
|
||||
parts = parts.join('');
|
||||
/*JSSTYLED*/
|
||||
var md5RE = /^[a-fA-F0-9]+$/;
|
||||
if (!md5RE.test(parts))
|
||||
throw (new FingerprintFormatError(fp));
|
||||
try {
|
||||
hash = new Buffer(parts, 'hex');
|
||||
} catch (e) {
|
||||
throw (new FingerprintFormatError(fp));
|
||||
}
|
||||
}
|
||||
|
||||
if (alg === undefined)
|
||||
throw (new FingerprintFormatError(fp));
|
||||
|
||||
if (algs.hashAlgs[alg] === undefined)
|
||||
throw (new InvalidAlgorithmError(alg));
|
||||
|
||||
if (enAlgs !== undefined) {
|
||||
enAlgs = enAlgs.map(function (a) { return a.toLowerCase(); });
|
||||
if (enAlgs.indexOf(alg) === -1)
|
||||
throw (new InvalidAlgorithmError(alg));
|
||||
}
|
||||
|
||||
return (new Fingerprint({
|
||||
algorithm: alg,
|
||||
hash: hash,
|
||||
type: options.type || 'key'
|
||||
}));
|
||||
};
|
||||
|
||||
function addColons(s) {
|
||||
/*JSSTYLED*/
|
||||
return (s.replace(/(.{2})(?=.)/g, '$1:'));
|
||||
}
|
||||
|
||||
function base64Strip(s) {
|
||||
/*JSSTYLED*/
|
||||
return (s.replace(/=*$/, ''));
|
||||
}
|
||||
|
||||
function sshBase64Format(alg, h) {
|
||||
return (alg.toUpperCase() + ':' + base64Strip(h));
|
||||
}
|
||||
|
||||
Fingerprint.isFingerprint = function (obj, ver) {
|
||||
return (utils.isCompatible(obj, Fingerprint, ver));
|
||||
};
|
||||
|
||||
/*
|
||||
* API versions for Fingerprint:
|
||||
* [1,0] -- initial ver
|
||||
* [1,1] -- first tagged ver
|
||||
*/
|
||||
Fingerprint.prototype._sshpkApiVersion = [1, 1];
|
||||
|
||||
Fingerprint._oldVersionDetect = function (obj) {
|
||||
assert.func(obj.toString);
|
||||
assert.func(obj.matches);
|
||||
return ([1, 0]);
|
||||
};
|
73
node_modules/sshpk/lib/formats/auto.js
generated
vendored
Normal file
73
node_modules/sshpk/lib/formats/auto.js
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
// Copyright 2015 Joyent, Inc.
|
||||
|
||||
module.exports = {
|
||||
read: read,
|
||||
write: write
|
||||
};
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var utils = require('../utils');
|
||||
var Key = require('../key');
|
||||
var PrivateKey = require('../private-key');
|
||||
|
||||
var pem = require('./pem');
|
||||
var ssh = require('./ssh');
|
||||
var rfc4253 = require('./rfc4253');
|
||||
|
||||
function read(buf, options) {
|
||||
if (typeof (buf) === 'string') {
|
||||
if (buf.trim().match(/^[-]+[ ]*BEGIN/))
|
||||
return (pem.read(buf, options));
|
||||
if (buf.match(/^\s*ssh-[a-z]/))
|
||||
return (ssh.read(buf, options));
|
||||
if (buf.match(/^\s*ecdsa-/))
|
||||
return (ssh.read(buf, options));
|
||||
buf = new Buffer(buf, 'binary');
|
||||
} else {
|
||||
assert.buffer(buf);
|
||||
if (findPEMHeader(buf))
|
||||
return (pem.read(buf, options));
|
||||
if (findSSHHeader(buf))
|
||||
return (ssh.read(buf, options));
|
||||
}
|
||||
if (buf.readUInt32BE(0) < buf.length)
|
||||
return (rfc4253.read(buf, options));
|
||||
throw (new Error('Failed to auto-detect format of key'));
|
||||
}
|
||||
|
||||
function findSSHHeader(buf) {
|
||||
var offset = 0;
|
||||
while (offset < buf.length &&
|
||||
(buf[offset] === 32 || buf[offset] === 10 || buf[offset] === 9))
|
||||
++offset;
|
||||
if (offset + 4 <= buf.length &&
|
||||
buf.slice(offset, offset + 4).toString('ascii') === 'ssh-')
|
||||
return (true);
|
||||
if (offset + 6 <= buf.length &&
|
||||
buf.slice(offset, offset + 6).toString('ascii') === 'ecdsa-')
|
||||
return (true);
|
||||
return (false);
|
||||
}
|
||||
|
||||
function findPEMHeader(buf) {
|
||||
var offset = 0;
|
||||
while (offset < buf.length &&
|
||||
(buf[offset] === 32 || buf[offset] === 10))
|
||||
++offset;
|
||||
if (buf[offset] !== 45)
|
||||
return (false);
|
||||
while (offset < buf.length &&
|
||||
(buf[offset] === 45))
|
||||
++offset;
|
||||
while (offset < buf.length &&
|
||||
(buf[offset] === 32))
|
||||
++offset;
|
||||
if (offset + 5 > buf.length ||
|
||||
buf.slice(offset, offset + 5).toString('ascii') !== 'BEGIN')
|
||||
return (false);
|
||||
return (true);
|
||||
}
|
||||
|
||||
function write(key, options) {
|
||||
throw (new Error('"auto" format cannot be used for writing'));
|
||||
}
|
322
node_modules/sshpk/lib/formats/openssh-cert.js
generated
vendored
Normal file
322
node_modules/sshpk/lib/formats/openssh-cert.js
generated
vendored
Normal file
@ -0,0 +1,322 @@
|
||||
// Copyright 2017 Joyent, Inc.
|
||||
|
||||
module.exports = {
|
||||
read: read,
|
||||
verify: verify,
|
||||
sign: sign,
|
||||
signAsync: signAsync,
|
||||
write: write,
|
||||
|
||||
/* Internal private API */
|
||||
fromBuffer: fromBuffer,
|
||||
toBuffer: toBuffer
|
||||
};
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var SSHBuffer = require('../ssh-buffer');
|
||||
var crypto = require('crypto');
|
||||
var algs = require('../algs');
|
||||
var Key = require('../key');
|
||||
var PrivateKey = require('../private-key');
|
||||
var Identity = require('../identity');
|
||||
var rfc4253 = require('./rfc4253');
|
||||
var Signature = require('../signature');
|
||||
var utils = require('../utils');
|
||||
var Certificate = require('../certificate');
|
||||
|
||||
function verify(cert, key) {
|
||||
/*
|
||||
* We always give an issuerKey, so if our verify() is being called then
|
||||
* there was no signature. Return false.
|
||||
*/
|
||||
return (false);
|
||||
}
|
||||
|
||||
var TYPES = {
|
||||
'user': 1,
|
||||
'host': 2
|
||||
};
|
||||
Object.keys(TYPES).forEach(function (k) { TYPES[TYPES[k]] = k; });
|
||||
|
||||
var ECDSA_ALGO = /^ecdsa-sha2-([^@-]+)-cert-v01@openssh.com$/;
|
||||
|
||||
function read(buf, options) {
|
||||
if (Buffer.isBuffer(buf))
|
||||
buf = buf.toString('ascii');
|
||||
var parts = buf.trim().split(/[ \t\n]+/g);
|
||||
if (parts.length < 2 || parts.length > 3)
|
||||
throw (new Error('Not a valid SSH certificate line'));
|
||||
|
||||
var algo = parts[0];
|
||||
var data = parts[1];
|
||||
|
||||
data = new Buffer(data, 'base64');
|
||||
return (fromBuffer(data, algo));
|
||||
}
|
||||
|
||||
function fromBuffer(data, algo, partial) {
|
||||
var sshbuf = new SSHBuffer({ buffer: data });
|
||||
var innerAlgo = sshbuf.readString();
|
||||
if (algo !== undefined && innerAlgo !== algo)
|
||||
throw (new Error('SSH certificate algorithm mismatch'));
|
||||
if (algo === undefined)
|
||||
algo = innerAlgo;
|
||||
|
||||
var cert = {};
|
||||
cert.signatures = {};
|
||||
cert.signatures.openssh = {};
|
||||
|
||||
cert.signatures.openssh.nonce = sshbuf.readBuffer();
|
||||
|
||||
var key = {};
|
||||
var parts = (key.parts = []);
|
||||
key.type = getAlg(algo);
|
||||
|
||||
var partCount = algs.info[key.type].parts.length;
|
||||
while (parts.length < partCount)
|
||||
parts.push(sshbuf.readPart());
|
||||
assert.ok(parts.length >= 1, 'key must have at least one part');
|
||||
|
||||
var algInfo = algs.info[key.type];
|
||||
if (key.type === 'ecdsa') {
|
||||
var res = ECDSA_ALGO.exec(algo);
|
||||
assert.ok(res !== null);
|
||||
assert.strictEqual(res[1], parts[0].data.toString());
|
||||
}
|
||||
|
||||
for (var i = 0; i < algInfo.parts.length; ++i) {
|
||||
parts[i].name = algInfo.parts[i];
|
||||
if (parts[i].name !== 'curve' &&
|
||||
algInfo.normalize !== false) {
|
||||
var p = parts[i];
|
||||
p.data = utils.mpNormalize(p.data);
|
||||
}
|
||||
}
|
||||
|
||||
cert.subjectKey = new Key(key);
|
||||
|
||||
cert.serial = sshbuf.readInt64();
|
||||
|
||||
var type = TYPES[sshbuf.readInt()];
|
||||
assert.string(type, 'valid cert type');
|
||||
|
||||
cert.signatures.openssh.keyId = sshbuf.readString();
|
||||
|
||||
var principals = [];
|
||||
var pbuf = sshbuf.readBuffer();
|
||||
var psshbuf = new SSHBuffer({ buffer: pbuf });
|
||||
while (!psshbuf.atEnd())
|
||||
principals.push(psshbuf.readString());
|
||||
if (principals.length === 0)
|
||||
principals = ['*'];
|
||||
|
||||
cert.subjects = principals.map(function (pr) {
|
||||
if (type === 'user')
|
||||
return (Identity.forUser(pr));
|
||||
else if (type === 'host')
|
||||
return (Identity.forHost(pr));
|
||||
throw (new Error('Unknown identity type ' + type));
|
||||
});
|
||||
|
||||
cert.validFrom = int64ToDate(sshbuf.readInt64());
|
||||
cert.validUntil = int64ToDate(sshbuf.readInt64());
|
||||
|
||||
cert.signatures.openssh.critical = sshbuf.readBuffer();
|
||||
cert.signatures.openssh.exts = sshbuf.readBuffer();
|
||||
|
||||
/* reserved */
|
||||
sshbuf.readBuffer();
|
||||
|
||||
var signingKeyBuf = sshbuf.readBuffer();
|
||||
cert.issuerKey = rfc4253.read(signingKeyBuf);
|
||||
|
||||
/*
|
||||
* OpenSSH certs don't give the identity of the issuer, just their
|
||||
* public key. So, we use an Identity that matches anything. The
|
||||
* isSignedBy() function will later tell you if the key matches.
|
||||
*/
|
||||
cert.issuer = Identity.forHost('**');
|
||||
|
||||
var sigBuf = sshbuf.readBuffer();
|
||||
cert.signatures.openssh.signature =
|
||||
Signature.parse(sigBuf, cert.issuerKey.type, 'ssh');
|
||||
|
||||
if (partial !== undefined) {
|
||||
partial.remainder = sshbuf.remainder();
|
||||
partial.consumed = sshbuf._offset;
|
||||
}
|
||||
|
||||
return (new Certificate(cert));
|
||||
}
|
||||
|
||||
function int64ToDate(buf) {
|
||||
var i = buf.readUInt32BE(0) * 4294967296;
|
||||
i += buf.readUInt32BE(4);
|
||||
var d = new Date();
|
||||
d.setTime(i * 1000);
|
||||
d.sourceInt64 = buf;
|
||||
return (d);
|
||||
}
|
||||
|
||||
function dateToInt64(date) {
|
||||
if (date.sourceInt64 !== undefined)
|
||||
return (date.sourceInt64);
|
||||
var i = Math.round(date.getTime() / 1000);
|
||||
var upper = Math.floor(i / 4294967296);
|
||||
var lower = Math.floor(i % 4294967296);
|
||||
var buf = new Buffer(8);
|
||||
buf.writeUInt32BE(upper, 0);
|
||||
buf.writeUInt32BE(lower, 4);
|
||||
return (buf);
|
||||
}
|
||||
|
||||
function sign(cert, key) {
|
||||
if (cert.signatures.openssh === undefined)
|
||||
cert.signatures.openssh = {};
|
||||
try {
|
||||
var blob = toBuffer(cert, true);
|
||||
} catch (e) {
|
||||
delete (cert.signatures.openssh);
|
||||
return (false);
|
||||
}
|
||||
var sig = cert.signatures.openssh;
|
||||
var hashAlgo = undefined;
|
||||
if (key.type === 'rsa' || key.type === 'dsa')
|
||||
hashAlgo = 'sha1';
|
||||
var signer = key.createSign(hashAlgo);
|
||||
signer.write(blob);
|
||||
sig.signature = signer.sign();
|
||||
return (true);
|
||||
}
|
||||
|
||||
function signAsync(cert, signer, done) {
|
||||
if (cert.signatures.openssh === undefined)
|
||||
cert.signatures.openssh = {};
|
||||
try {
|
||||
var blob = toBuffer(cert, true);
|
||||
} catch (e) {
|
||||
delete (cert.signatures.openssh);
|
||||
done(e);
|
||||
return;
|
||||
}
|
||||
var sig = cert.signatures.openssh;
|
||||
|
||||
signer(blob, function (err, signature) {
|
||||
if (err) {
|
||||
done(err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
/*
|
||||
* This will throw if the signature isn't of a
|
||||
* type/algo that can be used for SSH.
|
||||
*/
|
||||
signature.toBuffer('ssh');
|
||||
} catch (e) {
|
||||
done(e);
|
||||
return;
|
||||
}
|
||||
sig.signature = signature;
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
function write(cert, options) {
|
||||
if (options === undefined)
|
||||
options = {};
|
||||
|
||||
var blob = toBuffer(cert);
|
||||
var out = getCertType(cert.subjectKey) + ' ' + blob.toString('base64');
|
||||
if (options.comment)
|
||||
out = out + ' ' + options.comment;
|
||||
return (out);
|
||||
}
|
||||
|
||||
|
||||
function toBuffer(cert, noSig) {
|
||||
assert.object(cert.signatures.openssh, 'signature for openssh format');
|
||||
var sig = cert.signatures.openssh;
|
||||
|
||||
if (sig.nonce === undefined)
|
||||
sig.nonce = crypto.randomBytes(16);
|
||||
var buf = new SSHBuffer({});
|
||||
buf.writeString(getCertType(cert.subjectKey));
|
||||
buf.writeBuffer(sig.nonce);
|
||||
|
||||
var key = cert.subjectKey;
|
||||
var algInfo = algs.info[key.type];
|
||||
algInfo.parts.forEach(function (part) {
|
||||
buf.writePart(key.part[part]);
|
||||
});
|
||||
|
||||
buf.writeInt64(cert.serial);
|
||||
|
||||
var type = cert.subjects[0].type;
|
||||
assert.notStrictEqual(type, 'unknown');
|
||||
cert.subjects.forEach(function (id) {
|
||||
assert.strictEqual(id.type, type);
|
||||
});
|
||||
type = TYPES[type];
|
||||
buf.writeInt(type);
|
||||
|
||||
if (sig.keyId === undefined) {
|
||||
sig.keyId = cert.subjects[0].type + '_' +
|
||||
(cert.subjects[0].uid || cert.subjects[0].hostname);
|
||||
}
|
||||
buf.writeString(sig.keyId);
|
||||
|
||||
var sub = new SSHBuffer({});
|
||||
cert.subjects.forEach(function (id) {
|
||||
if (type === TYPES.host)
|
||||
sub.writeString(id.hostname);
|
||||
else if (type === TYPES.user)
|
||||
sub.writeString(id.uid);
|
||||
});
|
||||
buf.writeBuffer(sub.toBuffer());
|
||||
|
||||
buf.writeInt64(dateToInt64(cert.validFrom));
|
||||
buf.writeInt64(dateToInt64(cert.validUntil));
|
||||
|
||||
if (sig.critical === undefined)
|
||||
sig.critical = new Buffer(0);
|
||||
buf.writeBuffer(sig.critical);
|
||||
|
||||
if (sig.exts === undefined)
|
||||
sig.exts = new Buffer(0);
|
||||
buf.writeBuffer(sig.exts);
|
||||
|
||||
/* reserved */
|
||||
buf.writeBuffer(new Buffer(0));
|
||||
|
||||
sub = rfc4253.write(cert.issuerKey);
|
||||
buf.writeBuffer(sub);
|
||||
|
||||
if (!noSig)
|
||||
buf.writeBuffer(sig.signature.toBuffer('ssh'));
|
||||
|
||||
return (buf.toBuffer());
|
||||
}
|
||||
|
||||
function getAlg(certType) {
|
||||
if (certType === 'ssh-rsa-cert-v01@openssh.com')
|
||||
return ('rsa');
|
||||
if (certType === 'ssh-dss-cert-v01@openssh.com')
|
||||
return ('dsa');
|
||||
if (certType.match(ECDSA_ALGO))
|
||||
return ('ecdsa');
|
||||
if (certType === 'ssh-ed25519-cert-v01@openssh.com')
|
||||
return ('ed25519');
|
||||
throw (new Error('Unsupported cert type ' + certType));
|
||||
}
|
||||
|
||||
function getCertType(key) {
|
||||
if (key.type === 'rsa')
|
||||
return ('ssh-rsa-cert-v01@openssh.com');
|
||||
if (key.type === 'dsa')
|
||||
return ('ssh-dss-cert-v01@openssh.com');
|
||||
if (key.type === 'ecdsa')
|
||||
return ('ecdsa-sha2-' + key.curve + '-cert-v01@openssh.com');
|
||||
if (key.type === 'ed25519')
|
||||
return ('ssh-ed25519-cert-v01@openssh.com');
|
||||
throw (new Error('Unsupported key type ' + key.type));
|
||||
}
|
186
node_modules/sshpk/lib/formats/pem.js
generated
vendored
Normal file
186
node_modules/sshpk/lib/formats/pem.js
generated
vendored
Normal file
@ -0,0 +1,186 @@
|
||||
// Copyright 2015 Joyent, Inc.
|
||||
|
||||
module.exports = {
|
||||
read: read,
|
||||
write: write
|
||||
};
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var asn1 = require('asn1');
|
||||
var crypto = require('crypto');
|
||||
var algs = require('../algs');
|
||||
var utils = require('../utils');
|
||||
var Key = require('../key');
|
||||
var PrivateKey = require('../private-key');
|
||||
|
||||
var pkcs1 = require('./pkcs1');
|
||||
var pkcs8 = require('./pkcs8');
|
||||
var sshpriv = require('./ssh-private');
|
||||
var rfc4253 = require('./rfc4253');
|
||||
|
||||
var errors = require('../errors');
|
||||
|
||||
/*
|
||||
* For reading we support both PKCS#1 and PKCS#8. If we find a private key,
|
||||
* we just take the public component of it and use that.
|
||||
*/
|
||||
function read(buf, options, forceType) {
|
||||
var input = buf;
|
||||
if (typeof (buf) !== 'string') {
|
||||
assert.buffer(buf, 'buf');
|
||||
buf = buf.toString('ascii');
|
||||
}
|
||||
|
||||
var lines = buf.trim().split('\n');
|
||||
|
||||
var m = lines[0].match(/*JSSTYLED*/
|
||||
/[-]+[ ]*BEGIN ([A-Z0-9]+ )?(PUBLIC|PRIVATE) KEY[ ]*[-]+/);
|
||||
assert.ok(m, 'invalid PEM header');
|
||||
|
||||
var m2 = lines[lines.length - 1].match(/*JSSTYLED*/
|
||||
/[-]+[ ]*END ([A-Z0-9]+ )?(PUBLIC|PRIVATE) KEY[ ]*[-]+/);
|
||||
assert.ok(m2, 'invalid PEM footer');
|
||||
|
||||
/* Begin and end banners must match key type */
|
||||
assert.equal(m[2], m2[2]);
|
||||
var type = m[2].toLowerCase();
|
||||
|
||||
var alg;
|
||||
if (m[1]) {
|
||||
/* They also must match algorithms, if given */
|
||||
assert.equal(m[1], m2[1], 'PEM header and footer mismatch');
|
||||
alg = m[1].trim();
|
||||
}
|
||||
|
||||
var headers = {};
|
||||
while (true) {
|
||||
lines = lines.slice(1);
|
||||
m = lines[0].match(/*JSSTYLED*/
|
||||
/^([A-Za-z0-9-]+): (.+)$/);
|
||||
if (!m)
|
||||
break;
|
||||
headers[m[1].toLowerCase()] = m[2];
|
||||
}
|
||||
|
||||
var cipher, key, iv;
|
||||
if (headers['proc-type']) {
|
||||
var parts = headers['proc-type'].split(',');
|
||||
if (parts[0] === '4' && parts[1] === 'ENCRYPTED') {
|
||||
if (typeof (options.passphrase) === 'string') {
|
||||
options.passphrase = new Buffer(
|
||||
options.passphrase, 'utf-8');
|
||||
}
|
||||
if (!Buffer.isBuffer(options.passphrase)) {
|
||||
throw (new errors.KeyEncryptedError(
|
||||
options.filename, 'PEM'));
|
||||
} else {
|
||||
parts = headers['dek-info'].split(',');
|
||||
assert.ok(parts.length === 2);
|
||||
cipher = parts[0].toLowerCase();
|
||||
iv = new Buffer(parts[1], 'hex');
|
||||
key = utils.opensslKeyDeriv(cipher, iv,
|
||||
options.passphrase, 1).key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Chop off the first and last lines */
|
||||
lines = lines.slice(0, -1).join('');
|
||||
buf = new Buffer(lines, 'base64');
|
||||
|
||||
if (cipher && key && iv) {
|
||||
var cipherStream = crypto.createDecipheriv(cipher, key, iv);
|
||||
var chunk, chunks = [];
|
||||
cipherStream.once('error', function (e) {
|
||||
if (e.toString().indexOf('bad decrypt') !== -1) {
|
||||
throw (new Error('Incorrect passphrase ' +
|
||||
'supplied, could not decrypt key'));
|
||||
}
|
||||
throw (e);
|
||||
});
|
||||
cipherStream.write(buf);
|
||||
cipherStream.end();
|
||||
while ((chunk = cipherStream.read()) !== null)
|
||||
chunks.push(chunk);
|
||||
buf = Buffer.concat(chunks);
|
||||
}
|
||||
|
||||
/* The new OpenSSH internal format abuses PEM headers */
|
||||
if (alg && alg.toLowerCase() === 'openssh')
|
||||
return (sshpriv.readSSHPrivate(type, buf, options));
|
||||
if (alg && alg.toLowerCase() === 'ssh2')
|
||||
return (rfc4253.readType(type, buf, options));
|
||||
|
||||
var der = new asn1.BerReader(buf);
|
||||
der.originalInput = input;
|
||||
|
||||
/*
|
||||
* All of the PEM file types start with a sequence tag, so chop it
|
||||
* off here
|
||||
*/
|
||||
der.readSequence();
|
||||
|
||||
/* PKCS#1 type keys name an algorithm in the banner explicitly */
|
||||
if (alg) {
|
||||
if (forceType)
|
||||
assert.strictEqual(forceType, 'pkcs1');
|
||||
return (pkcs1.readPkcs1(alg, type, der));
|
||||
} else {
|
||||
if (forceType)
|
||||
assert.strictEqual(forceType, 'pkcs8');
|
||||
return (pkcs8.readPkcs8(alg, type, der));
|
||||
}
|
||||
}
|
||||
|
||||
function write(key, options, type) {
|
||||
assert.object(key);
|
||||
|
||||
var alg = {'ecdsa': 'EC', 'rsa': 'RSA', 'dsa': 'DSA'}[key.type];
|
||||
var header;
|
||||
|
||||
var der = new asn1.BerWriter();
|
||||
|
||||
if (PrivateKey.isPrivateKey(key)) {
|
||||
if (type && type === 'pkcs8') {
|
||||
header = 'PRIVATE KEY';
|
||||
pkcs8.writePkcs8(der, key);
|
||||
} else {
|
||||
if (type)
|
||||
assert.strictEqual(type, 'pkcs1');
|
||||
header = alg + ' PRIVATE KEY';
|
||||
pkcs1.writePkcs1(der, key);
|
||||
}
|
||||
|
||||
} else if (Key.isKey(key)) {
|
||||
if (type && type === 'pkcs1') {
|
||||
header = alg + ' PUBLIC KEY';
|
||||
pkcs1.writePkcs1(der, key);
|
||||
} else {
|
||||
if (type)
|
||||
assert.strictEqual(type, 'pkcs8');
|
||||
header = 'PUBLIC KEY';
|
||||
pkcs8.writePkcs8(der, key);
|
||||
}
|
||||
|
||||
} else {
|
||||
throw (new Error('key is not a Key or PrivateKey'));
|
||||
}
|
||||
|
||||
var tmp = der.buffer.toString('base64');
|
||||
var len = tmp.length + (tmp.length / 64) +
|
||||
18 + 16 + header.length*2 + 10;
|
||||
var buf = new Buffer(len);
|
||||
var o = 0;
|
||||
o += buf.write('-----BEGIN ' + header + '-----\n', o);
|
||||
for (var i = 0; i < tmp.length; ) {
|
||||
var limit = i + 64;
|
||||
if (limit > tmp.length)
|
||||
limit = tmp.length;
|
||||
o += buf.write(tmp.slice(i, limit), o);
|
||||
buf[o++] = 10;
|
||||
i = limit;
|
||||
}
|
||||
o += buf.write('-----END ' + header + '-----\n', o);
|
||||
|
||||
return (buf.slice(0, o));
|
||||
}
|
320
node_modules/sshpk/lib/formats/pkcs1.js
generated
vendored
Normal file
320
node_modules/sshpk/lib/formats/pkcs1.js
generated
vendored
Normal file
@ -0,0 +1,320 @@
|
||||
// Copyright 2015 Joyent, Inc.
|
||||
|
||||
module.exports = {
|
||||
read: read,
|
||||
readPkcs1: readPkcs1,
|
||||
write: write,
|
||||
writePkcs1: writePkcs1
|
||||
};
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var asn1 = require('asn1');
|
||||
var algs = require('../algs');
|
||||
var utils = require('../utils');
|
||||
|
||||
var Key = require('../key');
|
||||
var PrivateKey = require('../private-key');
|
||||
var pem = require('./pem');
|
||||
|
||||
var pkcs8 = require('./pkcs8');
|
||||
var readECDSACurve = pkcs8.readECDSACurve;
|
||||
|
||||
function read(buf, options) {
|
||||
return (pem.read(buf, options, 'pkcs1'));
|
||||
}
|
||||
|
||||
function write(key, options) {
|
||||
return (pem.write(key, options, 'pkcs1'));
|
||||
}
|
||||
|
||||
/* Helper to read in a single mpint */
|
||||
function readMPInt(der, nm) {
|
||||
assert.strictEqual(der.peek(), asn1.Ber.Integer,
|
||||
nm + ' is not an Integer');
|
||||
return (utils.mpNormalize(der.readString(asn1.Ber.Integer, true)));
|
||||
}
|
||||
|
||||
function readPkcs1(alg, type, der) {
|
||||
switch (alg) {
|
||||
case 'RSA':
|
||||
if (type === 'public')
|
||||
return (readPkcs1RSAPublic(der));
|
||||
else if (type === 'private')
|
||||
return (readPkcs1RSAPrivate(der));
|
||||
throw (new Error('Unknown key type: ' + type));
|
||||
case 'DSA':
|
||||
if (type === 'public')
|
||||
return (readPkcs1DSAPublic(der));
|
||||
else if (type === 'private')
|
||||
return (readPkcs1DSAPrivate(der));
|
||||
throw (new Error('Unknown key type: ' + type));
|
||||
case 'EC':
|
||||
case 'ECDSA':
|
||||
if (type === 'private')
|
||||
return (readPkcs1ECDSAPrivate(der));
|
||||
else if (type === 'public')
|
||||
return (readPkcs1ECDSAPublic(der));
|
||||
throw (new Error('Unknown key type: ' + type));
|
||||
default:
|
||||
throw (new Error('Unknown key algo: ' + alg));
|
||||
}
|
||||
}
|
||||
|
||||
function readPkcs1RSAPublic(der) {
|
||||
// modulus and exponent
|
||||
var n = readMPInt(der, 'modulus');
|
||||
var e = readMPInt(der, 'exponent');
|
||||
|
||||
// now, make the key
|
||||
var key = {
|
||||
type: 'rsa',
|
||||
parts: [
|
||||
{ name: 'e', data: e },
|
||||
{ name: 'n', data: n }
|
||||
]
|
||||
};
|
||||
|
||||
return (new Key(key));
|
||||
}
|
||||
|
||||
function readPkcs1RSAPrivate(der) {
|
||||
var version = readMPInt(der, 'version');
|
||||
assert.strictEqual(version[0], 0);
|
||||
|
||||
// modulus then public exponent
|
||||
var n = readMPInt(der, 'modulus');
|
||||
var e = readMPInt(der, 'public exponent');
|
||||
var d = readMPInt(der, 'private exponent');
|
||||
var p = readMPInt(der, 'prime1');
|
||||
var q = readMPInt(der, 'prime2');
|
||||
var dmodp = readMPInt(der, 'exponent1');
|
||||
var dmodq = readMPInt(der, 'exponent2');
|
||||
var iqmp = readMPInt(der, 'iqmp');
|
||||
|
||||
// now, make the key
|
||||
var key = {
|
||||
type: 'rsa',
|
||||
parts: [
|
||||
{ name: 'n', data: n },
|
||||
{ name: 'e', data: e },
|
||||
{ name: 'd', data: d },
|
||||
{ name: 'iqmp', data: iqmp },
|
||||
{ name: 'p', data: p },
|
||||
{ name: 'q', data: q },
|
||||
{ name: 'dmodp', data: dmodp },
|
||||
{ name: 'dmodq', data: dmodq }
|
||||
]
|
||||
};
|
||||
|
||||
return (new PrivateKey(key));
|
||||
}
|
||||
|
||||
function readPkcs1DSAPrivate(der) {
|
||||
var version = readMPInt(der, 'version');
|
||||
assert.strictEqual(version.readUInt8(0), 0);
|
||||
|
||||
var p = readMPInt(der, 'p');
|
||||
var q = readMPInt(der, 'q');
|
||||
var g = readMPInt(der, 'g');
|
||||
var y = readMPInt(der, 'y');
|
||||
var x = readMPInt(der, 'x');
|
||||
|
||||
// now, make the key
|
||||
var key = {
|
||||
type: 'dsa',
|
||||
parts: [
|
||||
{ name: 'p', data: p },
|
||||
{ name: 'q', data: q },
|
||||
{ name: 'g', data: g },
|
||||
{ name: 'y', data: y },
|
||||
{ name: 'x', data: x }
|
||||
]
|
||||
};
|
||||
|
||||
return (new PrivateKey(key));
|
||||
}
|
||||
|
||||
function readPkcs1DSAPublic(der) {
|
||||
var y = readMPInt(der, 'y');
|
||||
var p = readMPInt(der, 'p');
|
||||
var q = readMPInt(der, 'q');
|
||||
var g = readMPInt(der, 'g');
|
||||
|
||||
var key = {
|
||||
type: 'dsa',
|
||||
parts: [
|
||||
{ name: 'y', data: y },
|
||||
{ name: 'p', data: p },
|
||||
{ name: 'q', data: q },
|
||||
{ name: 'g', data: g }
|
||||
]
|
||||
};
|
||||
|
||||
return (new Key(key));
|
||||
}
|
||||
|
||||
function readPkcs1ECDSAPublic(der) {
|
||||
der.readSequence();
|
||||
|
||||
var oid = der.readOID();
|
||||
assert.strictEqual(oid, '1.2.840.10045.2.1', 'must be ecPublicKey');
|
||||
|
||||
var curveOid = der.readOID();
|
||||
|
||||
var curve;
|
||||
var curves = Object.keys(algs.curves);
|
||||
for (var j = 0; j < curves.length; ++j) {
|
||||
var c = curves[j];
|
||||
var cd = algs.curves[c];
|
||||
if (cd.pkcs8oid === curveOid) {
|
||||
curve = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert.string(curve, 'a known ECDSA named curve');
|
||||
|
||||
var Q = der.readString(asn1.Ber.BitString, true);
|
||||
Q = utils.ecNormalize(Q);
|
||||
|
||||
var key = {
|
||||
type: 'ecdsa',
|
||||
parts: [
|
||||
{ name: 'curve', data: new Buffer(curve) },
|
||||
{ name: 'Q', data: Q }
|
||||
]
|
||||
};
|
||||
|
||||
return (new Key(key));
|
||||
}
|
||||
|
||||
function readPkcs1ECDSAPrivate(der) {
|
||||
var version = readMPInt(der, 'version');
|
||||
assert.strictEqual(version.readUInt8(0), 1);
|
||||
|
||||
// private key
|
||||
var d = der.readString(asn1.Ber.OctetString, true);
|
||||
|
||||
der.readSequence(0xa0);
|
||||
var curve = readECDSACurve(der);
|
||||
assert.string(curve, 'a known elliptic curve');
|
||||
|
||||
der.readSequence(0xa1);
|
||||
var Q = der.readString(asn1.Ber.BitString, true);
|
||||
Q = utils.ecNormalize(Q);
|
||||
|
||||
var key = {
|
||||
type: 'ecdsa',
|
||||
parts: [
|
||||
{ name: 'curve', data: new Buffer(curve) },
|
||||
{ name: 'Q', data: Q },
|
||||
{ name: 'd', data: d }
|
||||
]
|
||||
};
|
||||
|
||||
return (new PrivateKey(key));
|
||||
}
|
||||
|
||||
function writePkcs1(der, key) {
|
||||
der.startSequence();
|
||||
|
||||
switch (key.type) {
|
||||
case 'rsa':
|
||||
if (PrivateKey.isPrivateKey(key))
|
||||
writePkcs1RSAPrivate(der, key);
|
||||
else
|
||||
writePkcs1RSAPublic(der, key);
|
||||
break;
|
||||
case 'dsa':
|
||||
if (PrivateKey.isPrivateKey(key))
|
||||
writePkcs1DSAPrivate(der, key);
|
||||
else
|
||||
writePkcs1DSAPublic(der, key);
|
||||
break;
|
||||
case 'ecdsa':
|
||||
if (PrivateKey.isPrivateKey(key))
|
||||
writePkcs1ECDSAPrivate(der, key);
|
||||
else
|
||||
writePkcs1ECDSAPublic(der, key);
|
||||
break;
|
||||
default:
|
||||
throw (new Error('Unknown key algo: ' + key.type));
|
||||
}
|
||||
|
||||
der.endSequence();
|
||||
}
|
||||
|
||||
function writePkcs1RSAPublic(der, key) {
|
||||
der.writeBuffer(key.part.n.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.e.data, asn1.Ber.Integer);
|
||||
}
|
||||
|
||||
function writePkcs1RSAPrivate(der, key) {
|
||||
var ver = new Buffer(1);
|
||||
ver[0] = 0;
|
||||
der.writeBuffer(ver, asn1.Ber.Integer);
|
||||
|
||||
der.writeBuffer(key.part.n.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.e.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.d.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.p.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.q.data, asn1.Ber.Integer);
|
||||
if (!key.part.dmodp || !key.part.dmodq)
|
||||
utils.addRSAMissing(key);
|
||||
der.writeBuffer(key.part.dmodp.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.dmodq.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.iqmp.data, asn1.Ber.Integer);
|
||||
}
|
||||
|
||||
function writePkcs1DSAPrivate(der, key) {
|
||||
var ver = new Buffer(1);
|
||||
ver[0] = 0;
|
||||
der.writeBuffer(ver, asn1.Ber.Integer);
|
||||
|
||||
der.writeBuffer(key.part.p.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.q.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.g.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.y.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.x.data, asn1.Ber.Integer);
|
||||
}
|
||||
|
||||
function writePkcs1DSAPublic(der, key) {
|
||||
der.writeBuffer(key.part.y.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.p.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.q.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.g.data, asn1.Ber.Integer);
|
||||
}
|
||||
|
||||
function writePkcs1ECDSAPublic(der, key) {
|
||||
der.startSequence();
|
||||
|
||||
der.writeOID('1.2.840.10045.2.1'); /* ecPublicKey */
|
||||
var curve = key.part.curve.data.toString();
|
||||
var curveOid = algs.curves[curve].pkcs8oid;
|
||||
assert.string(curveOid, 'a known ECDSA named curve');
|
||||
der.writeOID(curveOid);
|
||||
|
||||
der.endSequence();
|
||||
|
||||
var Q = utils.ecNormalize(key.part.Q.data, true);
|
||||
der.writeBuffer(Q, asn1.Ber.BitString);
|
||||
}
|
||||
|
||||
function writePkcs1ECDSAPrivate(der, key) {
|
||||
var ver = new Buffer(1);
|
||||
ver[0] = 1;
|
||||
der.writeBuffer(ver, asn1.Ber.Integer);
|
||||
|
||||
der.writeBuffer(key.part.d.data, asn1.Ber.OctetString);
|
||||
|
||||
der.startSequence(0xa0);
|
||||
var curve = key.part.curve.data.toString();
|
||||
var curveOid = algs.curves[curve].pkcs8oid;
|
||||
assert.string(curveOid, 'a known ECDSA named curve');
|
||||
der.writeOID(curveOid);
|
||||
der.endSequence();
|
||||
|
||||
der.startSequence(0xa1);
|
||||
var Q = utils.ecNormalize(key.part.Q.data, true);
|
||||
der.writeBuffer(Q, asn1.Ber.BitString);
|
||||
der.endSequence();
|
||||
}
|
505
node_modules/sshpk/lib/formats/pkcs8.js
generated
vendored
Normal file
505
node_modules/sshpk/lib/formats/pkcs8.js
generated
vendored
Normal file
@ -0,0 +1,505 @@
|
||||
// Copyright 2015 Joyent, Inc.
|
||||
|
||||
module.exports = {
|
||||
read: read,
|
||||
readPkcs8: readPkcs8,
|
||||
write: write,
|
||||
writePkcs8: writePkcs8,
|
||||
|
||||
readECDSACurve: readECDSACurve,
|
||||
writeECDSACurve: writeECDSACurve
|
||||
};
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var asn1 = require('asn1');
|
||||
var algs = require('../algs');
|
||||
var utils = require('../utils');
|
||||
var Key = require('../key');
|
||||
var PrivateKey = require('../private-key');
|
||||
var pem = require('./pem');
|
||||
|
||||
function read(buf, options) {
|
||||
return (pem.read(buf, options, 'pkcs8'));
|
||||
}
|
||||
|
||||
function write(key, options) {
|
||||
return (pem.write(key, options, 'pkcs8'));
|
||||
}
|
||||
|
||||
/* Helper to read in a single mpint */
|
||||
function readMPInt(der, nm) {
|
||||
assert.strictEqual(der.peek(), asn1.Ber.Integer,
|
||||
nm + ' is not an Integer');
|
||||
return (utils.mpNormalize(der.readString(asn1.Ber.Integer, true)));
|
||||
}
|
||||
|
||||
function readPkcs8(alg, type, der) {
|
||||
/* Private keys in pkcs#8 format have a weird extra int */
|
||||
if (der.peek() === asn1.Ber.Integer) {
|
||||
assert.strictEqual(type, 'private',
|
||||
'unexpected Integer at start of public key');
|
||||
der.readString(asn1.Ber.Integer, true);
|
||||
}
|
||||
|
||||
der.readSequence();
|
||||
var next = der.offset + der.length;
|
||||
|
||||
var oid = der.readOID();
|
||||
switch (oid) {
|
||||
case '1.2.840.113549.1.1.1':
|
||||
der._offset = next;
|
||||
if (type === 'public')
|
||||
return (readPkcs8RSAPublic(der));
|
||||
else
|
||||
return (readPkcs8RSAPrivate(der));
|
||||
case '1.2.840.10040.4.1':
|
||||
if (type === 'public')
|
||||
return (readPkcs8DSAPublic(der));
|
||||
else
|
||||
return (readPkcs8DSAPrivate(der));
|
||||
case '1.2.840.10045.2.1':
|
||||
if (type === 'public')
|
||||
return (readPkcs8ECDSAPublic(der));
|
||||
else
|
||||
return (readPkcs8ECDSAPrivate(der));
|
||||
default:
|
||||
throw (new Error('Unknown key type OID ' + oid));
|
||||
}
|
||||
}
|
||||
|
||||
function readPkcs8RSAPublic(der) {
|
||||
// bit string sequence
|
||||
der.readSequence(asn1.Ber.BitString);
|
||||
der.readByte();
|
||||
der.readSequence();
|
||||
|
||||
// modulus
|
||||
var n = readMPInt(der, 'modulus');
|
||||
var e = readMPInt(der, 'exponent');
|
||||
|
||||
// now, make the key
|
||||
var key = {
|
||||
type: 'rsa',
|
||||
source: der.originalInput,
|
||||
parts: [
|
||||
{ name: 'e', data: e },
|
||||
{ name: 'n', data: n }
|
||||
]
|
||||
};
|
||||
|
||||
return (new Key(key));
|
||||
}
|
||||
|
||||
function readPkcs8RSAPrivate(der) {
|
||||
der.readSequence(asn1.Ber.OctetString);
|
||||
der.readSequence();
|
||||
|
||||
var ver = readMPInt(der, 'version');
|
||||
assert.equal(ver[0], 0x0, 'unknown RSA private key version');
|
||||
|
||||
// modulus then public exponent
|
||||
var n = readMPInt(der, 'modulus');
|
||||
var e = readMPInt(der, 'public exponent');
|
||||
var d = readMPInt(der, 'private exponent');
|
||||
var p = readMPInt(der, 'prime1');
|
||||
var q = readMPInt(der, 'prime2');
|
||||
var dmodp = readMPInt(der, 'exponent1');
|
||||
var dmodq = readMPInt(der, 'exponent2');
|
||||
var iqmp = readMPInt(der, 'iqmp');
|
||||
|
||||
// now, make the key
|
||||
var key = {
|
||||
type: 'rsa',
|
||||
parts: [
|
||||
{ name: 'n', data: n },
|
||||
{ name: 'e', data: e },
|
||||
{ name: 'd', data: d },
|
||||
{ name: 'iqmp', data: iqmp },
|
||||
{ name: 'p', data: p },
|
||||
{ name: 'q', data: q },
|
||||
{ name: 'dmodp', data: dmodp },
|
||||
{ name: 'dmodq', data: dmodq }
|
||||
]
|
||||
};
|
||||
|
||||
return (new PrivateKey(key));
|
||||
}
|
||||
|
||||
function readPkcs8DSAPublic(der) {
|
||||
der.readSequence();
|
||||
|
||||
var p = readMPInt(der, 'p');
|
||||
var q = readMPInt(der, 'q');
|
||||
var g = readMPInt(der, 'g');
|
||||
|
||||
// bit string sequence
|
||||
der.readSequence(asn1.Ber.BitString);
|
||||
der.readByte();
|
||||
|
||||
var y = readMPInt(der, 'y');
|
||||
|
||||
// now, make the key
|
||||
var key = {
|
||||
type: 'dsa',
|
||||
parts: [
|
||||
{ name: 'p', data: p },
|
||||
{ name: 'q', data: q },
|
||||
{ name: 'g', data: g },
|
||||
{ name: 'y', data: y }
|
||||
]
|
||||
};
|
||||
|
||||
return (new Key(key));
|
||||
}
|
||||
|
||||
function readPkcs8DSAPrivate(der) {
|
||||
der.readSequence();
|
||||
|
||||
var p = readMPInt(der, 'p');
|
||||
var q = readMPInt(der, 'q');
|
||||
var g = readMPInt(der, 'g');
|
||||
|
||||
der.readSequence(asn1.Ber.OctetString);
|
||||
var x = readMPInt(der, 'x');
|
||||
|
||||
/* The pkcs#8 format does not include the public key */
|
||||
var y = utils.calculateDSAPublic(g, p, x);
|
||||
|
||||
var key = {
|
||||
type: 'dsa',
|
||||
parts: [
|
||||
{ name: 'p', data: p },
|
||||
{ name: 'q', data: q },
|
||||
{ name: 'g', data: g },
|
||||
{ name: 'y', data: y },
|
||||
{ name: 'x', data: x }
|
||||
]
|
||||
};
|
||||
|
||||
return (new PrivateKey(key));
|
||||
}
|
||||
|
||||
function readECDSACurve(der) {
|
||||
var curveName, curveNames;
|
||||
var j, c, cd;
|
||||
|
||||
if (der.peek() === asn1.Ber.OID) {
|
||||
var oid = der.readOID();
|
||||
|
||||
curveNames = Object.keys(algs.curves);
|
||||
for (j = 0; j < curveNames.length; ++j) {
|
||||
c = curveNames[j];
|
||||
cd = algs.curves[c];
|
||||
if (cd.pkcs8oid === oid) {
|
||||
curveName = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// ECParameters sequence
|
||||
der.readSequence();
|
||||
var version = der.readString(asn1.Ber.Integer, true);
|
||||
assert.strictEqual(version[0], 1, 'ECDSA key not version 1');
|
||||
|
||||
var curve = {};
|
||||
|
||||
// FieldID sequence
|
||||
der.readSequence();
|
||||
var fieldTypeOid = der.readOID();
|
||||
assert.strictEqual(fieldTypeOid, '1.2.840.10045.1.1',
|
||||
'ECDSA key is not from a prime-field');
|
||||
var p = curve.p = utils.mpNormalize(
|
||||
der.readString(asn1.Ber.Integer, true));
|
||||
/*
|
||||
* p always starts with a 1 bit, so count the zeros to get its
|
||||
* real size.
|
||||
*/
|
||||
curve.size = p.length * 8 - utils.countZeros(p);
|
||||
|
||||
// Curve sequence
|
||||
der.readSequence();
|
||||
curve.a = utils.mpNormalize(
|
||||
der.readString(asn1.Ber.OctetString, true));
|
||||
curve.b = utils.mpNormalize(
|
||||
der.readString(asn1.Ber.OctetString, true));
|
||||
if (der.peek() === asn1.Ber.BitString)
|
||||
curve.s = der.readString(asn1.Ber.BitString, true);
|
||||
|
||||
// Combined Gx and Gy
|
||||
curve.G = der.readString(asn1.Ber.OctetString, true);
|
||||
assert.strictEqual(curve.G[0], 0x4,
|
||||
'uncompressed G is required');
|
||||
|
||||
curve.n = utils.mpNormalize(
|
||||
der.readString(asn1.Ber.Integer, true));
|
||||
curve.h = utils.mpNormalize(
|
||||
der.readString(asn1.Ber.Integer, true));
|
||||
assert.strictEqual(curve.h[0], 0x1, 'a cofactor=1 curve is ' +
|
||||
'required');
|
||||
|
||||
curveNames = Object.keys(algs.curves);
|
||||
var ks = Object.keys(curve);
|
||||
for (j = 0; j < curveNames.length; ++j) {
|
||||
c = curveNames[j];
|
||||
cd = algs.curves[c];
|
||||
var equal = true;
|
||||
for (var i = 0; i < ks.length; ++i) {
|
||||
var k = ks[i];
|
||||
if (cd[k] === undefined)
|
||||
continue;
|
||||
if (typeof (cd[k]) === 'object' &&
|
||||
cd[k].equals !== undefined) {
|
||||
if (!cd[k].equals(curve[k])) {
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
} else if (Buffer.isBuffer(cd[k])) {
|
||||
if (cd[k].toString('binary')
|
||||
!== curve[k].toString('binary')) {
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (cd[k] !== curve[k]) {
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (equal) {
|
||||
curveName = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (curveName);
|
||||
}
|
||||
|
||||
function readPkcs8ECDSAPrivate(der) {
|
||||
var curveName = readECDSACurve(der);
|
||||
assert.string(curveName, 'a known elliptic curve');
|
||||
|
||||
der.readSequence(asn1.Ber.OctetString);
|
||||
der.readSequence();
|
||||
|
||||
var version = readMPInt(der, 'version');
|
||||
assert.equal(version[0], 1, 'unknown version of ECDSA key');
|
||||
|
||||
var d = der.readString(asn1.Ber.OctetString, true);
|
||||
der.readSequence(0xa1);
|
||||
|
||||
var Q = der.readString(asn1.Ber.BitString, true);
|
||||
Q = utils.ecNormalize(Q);
|
||||
|
||||
var key = {
|
||||
type: 'ecdsa',
|
||||
parts: [
|
||||
{ name: 'curve', data: new Buffer(curveName) },
|
||||
{ name: 'Q', data: Q },
|
||||
{ name: 'd', data: d }
|
||||
]
|
||||
};
|
||||
|
||||
return (new PrivateKey(key));
|
||||
}
|
||||
|
||||
function readPkcs8ECDSAPublic(der) {
|
||||
var curveName = readECDSACurve(der);
|
||||
assert.string(curveName, 'a known elliptic curve');
|
||||
|
||||
var Q = der.readString(asn1.Ber.BitString, true);
|
||||
Q = utils.ecNormalize(Q);
|
||||
|
||||
var key = {
|
||||
type: 'ecdsa',
|
||||
parts: [
|
||||
{ name: 'curve', data: new Buffer(curveName) },
|
||||
{ name: 'Q', data: Q }
|
||||
]
|
||||
};
|
||||
|
||||
return (new Key(key));
|
||||
}
|
||||
|
||||
function writePkcs8(der, key) {
|
||||
der.startSequence();
|
||||
|
||||
if (PrivateKey.isPrivateKey(key)) {
|
||||
var sillyInt = new Buffer(1);
|
||||
sillyInt[0] = 0x0;
|
||||
der.writeBuffer(sillyInt, asn1.Ber.Integer);
|
||||
}
|
||||
|
||||
der.startSequence();
|
||||
switch (key.type) {
|
||||
case 'rsa':
|
||||
der.writeOID('1.2.840.113549.1.1.1');
|
||||
if (PrivateKey.isPrivateKey(key))
|
||||
writePkcs8RSAPrivate(key, der);
|
||||
else
|
||||
writePkcs8RSAPublic(key, der);
|
||||
break;
|
||||
case 'dsa':
|
||||
der.writeOID('1.2.840.10040.4.1');
|
||||
if (PrivateKey.isPrivateKey(key))
|
||||
writePkcs8DSAPrivate(key, der);
|
||||
else
|
||||
writePkcs8DSAPublic(key, der);
|
||||
break;
|
||||
case 'ecdsa':
|
||||
der.writeOID('1.2.840.10045.2.1');
|
||||
if (PrivateKey.isPrivateKey(key))
|
||||
writePkcs8ECDSAPrivate(key, der);
|
||||
else
|
||||
writePkcs8ECDSAPublic(key, der);
|
||||
break;
|
||||
default:
|
||||
throw (new Error('Unsupported key type: ' + key.type));
|
||||
}
|
||||
|
||||
der.endSequence();
|
||||
}
|
||||
|
||||
function writePkcs8RSAPrivate(key, der) {
|
||||
der.writeNull();
|
||||
der.endSequence();
|
||||
|
||||
der.startSequence(asn1.Ber.OctetString);
|
||||
der.startSequence();
|
||||
|
||||
var version = new Buffer(1);
|
||||
version[0] = 0;
|
||||
der.writeBuffer(version, asn1.Ber.Integer);
|
||||
|
||||
der.writeBuffer(key.part.n.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.e.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.d.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.p.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.q.data, asn1.Ber.Integer);
|
||||
if (!key.part.dmodp || !key.part.dmodq)
|
||||
utils.addRSAMissing(key);
|
||||
der.writeBuffer(key.part.dmodp.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.dmodq.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.iqmp.data, asn1.Ber.Integer);
|
||||
|
||||
der.endSequence();
|
||||
der.endSequence();
|
||||
}
|
||||
|
||||
function writePkcs8RSAPublic(key, der) {
|
||||
der.writeNull();
|
||||
der.endSequence();
|
||||
|
||||
der.startSequence(asn1.Ber.BitString);
|
||||
der.writeByte(0x00);
|
||||
|
||||
der.startSequence();
|
||||
der.writeBuffer(key.part.n.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.e.data, asn1.Ber.Integer);
|
||||
der.endSequence();
|
||||
|
||||
der.endSequence();
|
||||
}
|
||||
|
||||
function writePkcs8DSAPrivate(key, der) {
|
||||
der.startSequence();
|
||||
der.writeBuffer(key.part.p.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.q.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.g.data, asn1.Ber.Integer);
|
||||
der.endSequence();
|
||||
|
||||
der.endSequence();
|
||||
|
||||
der.startSequence(asn1.Ber.OctetString);
|
||||
der.writeBuffer(key.part.x.data, asn1.Ber.Integer);
|
||||
der.endSequence();
|
||||
}
|
||||
|
||||
function writePkcs8DSAPublic(key, der) {
|
||||
der.startSequence();
|
||||
der.writeBuffer(key.part.p.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.q.data, asn1.Ber.Integer);
|
||||
der.writeBuffer(key.part.g.data, asn1.Ber.Integer);
|
||||
der.endSequence();
|
||||
der.endSequence();
|
||||
|
||||
der.startSequence(asn1.Ber.BitString);
|
||||
der.writeByte(0x00);
|
||||
der.writeBuffer(key.part.y.data, asn1.Ber.Integer);
|
||||
der.endSequence();
|
||||
}
|
||||
|
||||
function writeECDSACurve(key, der) {
|
||||
var curve = algs.curves[key.curve];
|
||||
if (curve.pkcs8oid) {
|
||||
/* This one has a name in pkcs#8, so just write the oid */
|
||||
der.writeOID(curve.pkcs8oid);
|
||||
|
||||
} else {
|
||||
// ECParameters sequence
|
||||
der.startSequence();
|
||||
|
||||
var version = new Buffer(1);
|
||||
version.writeUInt8(1, 0);
|
||||
der.writeBuffer(version, asn1.Ber.Integer);
|
||||
|
||||
// FieldID sequence
|
||||
der.startSequence();
|
||||
der.writeOID('1.2.840.10045.1.1'); // prime-field
|
||||
der.writeBuffer(curve.p, asn1.Ber.Integer);
|
||||
der.endSequence();
|
||||
|
||||
// Curve sequence
|
||||
der.startSequence();
|
||||
var a = curve.p;
|
||||
if (a[0] === 0x0)
|
||||
a = a.slice(1);
|
||||
der.writeBuffer(a, asn1.Ber.OctetString);
|
||||
der.writeBuffer(curve.b, asn1.Ber.OctetString);
|
||||
der.writeBuffer(curve.s, asn1.Ber.BitString);
|
||||
der.endSequence();
|
||||
|
||||
der.writeBuffer(curve.G, asn1.Ber.OctetString);
|
||||
der.writeBuffer(curve.n, asn1.Ber.Integer);
|
||||
var h = curve.h;
|
||||
if (!h) {
|
||||
h = new Buffer(1);
|
||||
h[0] = 1;
|
||||
}
|
||||
der.writeBuffer(h, asn1.Ber.Integer);
|
||||
|
||||
// ECParameters
|
||||
der.endSequence();
|
||||
}
|
||||
}
|
||||
|
||||
function writePkcs8ECDSAPublic(key, der) {
|
||||
writeECDSACurve(key, der);
|
||||
der.endSequence();
|
||||
|
||||
var Q = utils.ecNormalize(key.part.Q.data, true);
|
||||
der.writeBuffer(Q, asn1.Ber.BitString);
|
||||
}
|
||||
|
||||
function writePkcs8ECDSAPrivate(key, der) {
|
||||
writeECDSACurve(key, der);
|
||||
der.endSequence();
|
||||
|
||||
der.startSequence(asn1.Ber.OctetString);
|
||||
der.startSequence();
|
||||
|
||||
var version = new Buffer(1);
|
||||
version[0] = 1;
|
||||
der.writeBuffer(version, asn1.Ber.Integer);
|
||||
|
||||
der.writeBuffer(key.part.d.data, asn1.Ber.OctetString);
|
||||
|
||||
der.startSequence(0xa1);
|
||||
var Q = utils.ecNormalize(key.part.Q.data, true);
|
||||
der.writeBuffer(Q, asn1.Ber.BitString);
|
||||
der.endSequence();
|
||||
|
||||
der.endSequence();
|
||||
der.endSequence();
|
||||
}
|
146
node_modules/sshpk/lib/formats/rfc4253.js
generated
vendored
Normal file
146
node_modules/sshpk/lib/formats/rfc4253.js
generated
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
// Copyright 2015 Joyent, Inc.
|
||||
|
||||
module.exports = {
|
||||
read: read.bind(undefined, false, undefined),
|
||||
readType: read.bind(undefined, false),
|
||||
write: write,
|
||||
/* semi-private api, used by sshpk-agent */
|
||||
readPartial: read.bind(undefined, true),
|
||||
|
||||
/* shared with ssh format */
|
||||
readInternal: read,
|
||||
keyTypeToAlg: keyTypeToAlg,
|
||||
algToKeyType: algToKeyType
|
||||
};
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var algs = require('../algs');
|
||||
var utils = require('../utils');
|
||||
var Key = require('../key');
|
||||
var PrivateKey = require('../private-key');
|
||||
var SSHBuffer = require('../ssh-buffer');
|
||||
|
||||
function algToKeyType(alg) {
|
||||
assert.string(alg);
|
||||
if (alg === 'ssh-dss')
|
||||
return ('dsa');
|
||||
else if (alg === 'ssh-rsa')
|
||||
return ('rsa');
|
||||
else if (alg === 'ssh-ed25519')
|
||||
return ('ed25519');
|
||||
else if (alg === 'ssh-curve25519')
|
||||
return ('curve25519');
|
||||
else if (alg.match(/^ecdsa-sha2-/))
|
||||
return ('ecdsa');
|
||||
else
|
||||
throw (new Error('Unknown algorithm ' + alg));
|
||||
}
|
||||
|
||||
function keyTypeToAlg(key) {
|
||||
assert.object(key);
|
||||
if (key.type === 'dsa')
|
||||
return ('ssh-dss');
|
||||
else if (key.type === 'rsa')
|
||||
return ('ssh-rsa');
|
||||
else if (key.type === 'ed25519')
|
||||
return ('ssh-ed25519');
|
||||
else if (key.type === 'curve25519')
|
||||
return ('ssh-curve25519');
|
||||
else if (key.type === 'ecdsa')
|
||||
return ('ecdsa-sha2-' + key.part.curve.data.toString());
|
||||
else
|
||||
throw (new Error('Unknown key type ' + key.type));
|
||||
}
|
||||
|
||||
function read(partial, type, buf, options) {
|
||||
if (typeof (buf) === 'string')
|
||||
buf = new Buffer(buf);
|
||||
assert.buffer(buf, 'buf');
|
||||
|
||||
var key = {};
|
||||
|
||||
var parts = key.parts = [];
|
||||
var sshbuf = new SSHBuffer({buffer: buf});
|
||||
|
||||
var alg = sshbuf.readString();
|
||||
assert.ok(!sshbuf.atEnd(), 'key must have at least one part');
|
||||
|
||||
key.type = algToKeyType(alg);
|
||||
|
||||
var partCount = algs.info[key.type].parts.length;
|
||||
if (type && type === 'private')
|
||||
partCount = algs.privInfo[key.type].parts.length;
|
||||
|
||||
while (!sshbuf.atEnd() && parts.length < partCount)
|
||||
parts.push(sshbuf.readPart());
|
||||
while (!partial && !sshbuf.atEnd())
|
||||
parts.push(sshbuf.readPart());
|
||||
|
||||
assert.ok(parts.length >= 1,
|
||||
'key must have at least one part');
|
||||
assert.ok(partial || sshbuf.atEnd(),
|
||||
'leftover bytes at end of key');
|
||||
|
||||
var Constructor = Key;
|
||||
var algInfo = algs.info[key.type];
|
||||
if (type === 'private' || algInfo.parts.length !== parts.length) {
|
||||
algInfo = algs.privInfo[key.type];
|
||||
Constructor = PrivateKey;
|
||||
}
|
||||
assert.strictEqual(algInfo.parts.length, parts.length);
|
||||
|
||||
if (key.type === 'ecdsa') {
|
||||
var res = /^ecdsa-sha2-(.+)$/.exec(alg);
|
||||
assert.ok(res !== null);
|
||||
assert.strictEqual(res[1], parts[0].data.toString());
|
||||
}
|
||||
|
||||
var normalized = true;
|
||||
for (var i = 0; i < algInfo.parts.length; ++i) {
|
||||
parts[i].name = algInfo.parts[i];
|
||||
if (parts[i].name !== 'curve' &&
|
||||
algInfo.normalize !== false) {
|
||||
var p = parts[i];
|
||||
var nd = utils.mpNormalize(p.data);
|
||||
if (nd !== p.data) {
|
||||
p.data = nd;
|
||||
normalized = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (normalized)
|
||||
key._rfc4253Cache = sshbuf.toBuffer();
|
||||
|
||||
if (partial && typeof (partial) === 'object') {
|
||||
partial.remainder = sshbuf.remainder();
|
||||
partial.consumed = sshbuf._offset;
|
||||
}
|
||||
|
||||
return (new Constructor(key));
|
||||
}
|
||||
|
||||
function write(key, options) {
|
||||
assert.object(key);
|
||||
|
||||
var alg = keyTypeToAlg(key);
|
||||
var i;
|
||||
|
||||
var algInfo = algs.info[key.type];
|
||||
if (PrivateKey.isPrivateKey(key))
|
||||
algInfo = algs.privInfo[key.type];
|
||||
var parts = algInfo.parts;
|
||||
|
||||
var buf = new SSHBuffer({});
|
||||
|
||||
buf.writeString(alg);
|
||||
|
||||
for (i = 0; i < parts.length; ++i) {
|
||||
var data = key.part[parts[i]].data;
|
||||
if (algInfo.normalize !== false)
|
||||
data = utils.mpNormalize(data);
|
||||
buf.writeBuffer(data);
|
||||
}
|
||||
|
||||
return (buf.toBuffer());
|
||||
}
|
261
node_modules/sshpk/lib/formats/ssh-private.js
generated
vendored
Normal file
261
node_modules/sshpk/lib/formats/ssh-private.js
generated
vendored
Normal file
@ -0,0 +1,261 @@
|
||||
// Copyright 2015 Joyent, Inc.
|
||||
|
||||
module.exports = {
|
||||
read: read,
|
||||
readSSHPrivate: readSSHPrivate,
|
||||
write: write
|
||||
};
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var asn1 = require('asn1');
|
||||
var algs = require('../algs');
|
||||
var utils = require('../utils');
|
||||
var crypto = require('crypto');
|
||||
|
||||
var Key = require('../key');
|
||||
var PrivateKey = require('../private-key');
|
||||
var pem = require('./pem');
|
||||
var rfc4253 = require('./rfc4253');
|
||||
var SSHBuffer = require('../ssh-buffer');
|
||||
var errors = require('../errors');
|
||||
|
||||
var bcrypt;
|
||||
|
||||
function read(buf, options) {
|
||||
return (pem.read(buf, options));
|
||||
}
|
||||
|
||||
var MAGIC = 'openssh-key-v1';
|
||||
|
||||
function readSSHPrivate(type, buf, options) {
|
||||
buf = new SSHBuffer({buffer: buf});
|
||||
|
||||
var magic = buf.readCString();
|
||||
assert.strictEqual(magic, MAGIC, 'bad magic string');
|
||||
|
||||
var cipher = buf.readString();
|
||||
var kdf = buf.readString();
|
||||
var kdfOpts = buf.readBuffer();
|
||||
|
||||
var nkeys = buf.readInt();
|
||||
if (nkeys !== 1) {
|
||||
throw (new Error('OpenSSH-format key file contains ' +
|
||||
'multiple keys: this is unsupported.'));
|
||||
}
|
||||
|
||||
var pubKey = buf.readBuffer();
|
||||
|
||||
if (type === 'public') {
|
||||
assert.ok(buf.atEnd(), 'excess bytes left after key');
|
||||
return (rfc4253.read(pubKey));
|
||||
}
|
||||
|
||||
var privKeyBlob = buf.readBuffer();
|
||||
assert.ok(buf.atEnd(), 'excess bytes left after key');
|
||||
|
||||
var kdfOptsBuf = new SSHBuffer({ buffer: kdfOpts });
|
||||
switch (kdf) {
|
||||
case 'none':
|
||||
if (cipher !== 'none') {
|
||||
throw (new Error('OpenSSH-format key uses KDF "none" ' +
|
||||
'but specifies a cipher other than "none"'));
|
||||
}
|
||||
break;
|
||||
case 'bcrypt':
|
||||
var salt = kdfOptsBuf.readBuffer();
|
||||
var rounds = kdfOptsBuf.readInt();
|
||||
var cinf = utils.opensshCipherInfo(cipher);
|
||||
if (bcrypt === undefined) {
|
||||
bcrypt = require('bcrypt-pbkdf');
|
||||
}
|
||||
|
||||
if (typeof (options.passphrase) === 'string') {
|
||||
options.passphrase = new Buffer(options.passphrase,
|
||||
'utf-8');
|
||||
}
|
||||
if (!Buffer.isBuffer(options.passphrase)) {
|
||||
throw (new errors.KeyEncryptedError(
|
||||
options.filename, 'OpenSSH'));
|
||||
}
|
||||
|
||||
var pass = new Uint8Array(options.passphrase);
|
||||
var salti = new Uint8Array(salt);
|
||||
/* Use the pbkdf to derive both the key and the IV. */
|
||||
var out = new Uint8Array(cinf.keySize + cinf.blockSize);
|
||||
var res = bcrypt.pbkdf(pass, pass.length, salti, salti.length,
|
||||
out, out.length, rounds);
|
||||
if (res !== 0) {
|
||||
throw (new Error('bcrypt_pbkdf function returned ' +
|
||||
'failure, parameters invalid'));
|
||||
}
|
||||
out = new Buffer(out);
|
||||
var ckey = out.slice(0, cinf.keySize);
|
||||
var iv = out.slice(cinf.keySize, cinf.keySize + cinf.blockSize);
|
||||
var cipherStream = crypto.createDecipheriv(cinf.opensslName,
|
||||
ckey, iv);
|
||||
cipherStream.setAutoPadding(false);
|
||||
var chunk, chunks = [];
|
||||
cipherStream.once('error', function (e) {
|
||||
if (e.toString().indexOf('bad decrypt') !== -1) {
|
||||
throw (new Error('Incorrect passphrase ' +
|
||||
'supplied, could not decrypt key'));
|
||||
}
|
||||
throw (e);
|
||||
});
|
||||
cipherStream.write(privKeyBlob);
|
||||
cipherStream.end();
|
||||
while ((chunk = cipherStream.read()) !== null)
|
||||
chunks.push(chunk);
|
||||
privKeyBlob = Buffer.concat(chunks);
|
||||
break;
|
||||
default:
|
||||
throw (new Error(
|
||||
'OpenSSH-format key uses unknown KDF "' + kdf + '"'));
|
||||
}
|
||||
|
||||
buf = new SSHBuffer({buffer: privKeyBlob});
|
||||
|
||||
var checkInt1 = buf.readInt();
|
||||
var checkInt2 = buf.readInt();
|
||||
if (checkInt1 !== checkInt2) {
|
||||
throw (new Error('Incorrect passphrase supplied, could not ' +
|
||||
'decrypt key'));
|
||||
}
|
||||
|
||||
var ret = {};
|
||||
var key = rfc4253.readInternal(ret, 'private', buf.remainder());
|
||||
|
||||
buf.skip(ret.consumed);
|
||||
|
||||
var comment = buf.readString();
|
||||
key.comment = comment;
|
||||
|
||||
return (key);
|
||||
}
|
||||
|
||||
function write(key, options) {
|
||||
var pubKey;
|
||||
if (PrivateKey.isPrivateKey(key))
|
||||
pubKey = key.toPublic();
|
||||
else
|
||||
pubKey = key;
|
||||
|
||||
var cipher = 'none';
|
||||
var kdf = 'none';
|
||||
var kdfopts = new Buffer(0);
|
||||
var cinf = { blockSize: 8 };
|
||||
var passphrase;
|
||||
if (options !== undefined) {
|
||||
passphrase = options.passphrase;
|
||||
if (typeof (passphrase) === 'string')
|
||||
passphrase = new Buffer(passphrase, 'utf-8');
|
||||
if (passphrase !== undefined) {
|
||||
assert.buffer(passphrase, 'options.passphrase');
|
||||
assert.optionalString(options.cipher, 'options.cipher');
|
||||
cipher = options.cipher;
|
||||
if (cipher === undefined)
|
||||
cipher = 'aes128-ctr';
|
||||
cinf = utils.opensshCipherInfo(cipher);
|
||||
kdf = 'bcrypt';
|
||||
}
|
||||
}
|
||||
|
||||
var privBuf;
|
||||
if (PrivateKey.isPrivateKey(key)) {
|
||||
privBuf = new SSHBuffer({});
|
||||
var checkInt = crypto.randomBytes(4).readUInt32BE(0);
|
||||
privBuf.writeInt(checkInt);
|
||||
privBuf.writeInt(checkInt);
|
||||
privBuf.write(key.toBuffer('rfc4253'));
|
||||
privBuf.writeString(key.comment || '');
|
||||
|
||||
var n = 1;
|
||||
while (privBuf._offset % cinf.blockSize !== 0)
|
||||
privBuf.writeChar(n++);
|
||||
privBuf = privBuf.toBuffer();
|
||||
}
|
||||
|
||||
switch (kdf) {
|
||||
case 'none':
|
||||
break;
|
||||
case 'bcrypt':
|
||||
var salt = crypto.randomBytes(16);
|
||||
var rounds = 16;
|
||||
var kdfssh = new SSHBuffer({});
|
||||
kdfssh.writeBuffer(salt);
|
||||
kdfssh.writeInt(rounds);
|
||||
kdfopts = kdfssh.toBuffer();
|
||||
|
||||
if (bcrypt === undefined) {
|
||||
bcrypt = require('bcrypt-pbkdf');
|
||||
}
|
||||
var pass = new Uint8Array(passphrase);
|
||||
var salti = new Uint8Array(salt);
|
||||
/* Use the pbkdf to derive both the key and the IV. */
|
||||
var out = new Uint8Array(cinf.keySize + cinf.blockSize);
|
||||
var res = bcrypt.pbkdf(pass, pass.length, salti, salti.length,
|
||||
out, out.length, rounds);
|
||||
if (res !== 0) {
|
||||
throw (new Error('bcrypt_pbkdf function returned ' +
|
||||
'failure, parameters invalid'));
|
||||
}
|
||||
out = new Buffer(out);
|
||||
var ckey = out.slice(0, cinf.keySize);
|
||||
var iv = out.slice(cinf.keySize, cinf.keySize + cinf.blockSize);
|
||||
|
||||
var cipherStream = crypto.createCipheriv(cinf.opensslName,
|
||||
ckey, iv);
|
||||
cipherStream.setAutoPadding(false);
|
||||
var chunk, chunks = [];
|
||||
cipherStream.once('error', function (e) {
|
||||
throw (e);
|
||||
});
|
||||
cipherStream.write(privBuf);
|
||||
cipherStream.end();
|
||||
while ((chunk = cipherStream.read()) !== null)
|
||||
chunks.push(chunk);
|
||||
privBuf = Buffer.concat(chunks);
|
||||
break;
|
||||
default:
|
||||
throw (new Error('Unsupported kdf ' + kdf));
|
||||
}
|
||||
|
||||
var buf = new SSHBuffer({});
|
||||
|
||||
buf.writeCString(MAGIC);
|
||||
buf.writeString(cipher); /* cipher */
|
||||
buf.writeString(kdf); /* kdf */
|
||||
buf.writeBuffer(kdfopts); /* kdfoptions */
|
||||
|
||||
buf.writeInt(1); /* nkeys */
|
||||
buf.writeBuffer(pubKey.toBuffer('rfc4253'));
|
||||
|
||||
if (privBuf)
|
||||
buf.writeBuffer(privBuf);
|
||||
|
||||
buf = buf.toBuffer();
|
||||
|
||||
var header;
|
||||
if (PrivateKey.isPrivateKey(key))
|
||||
header = 'OPENSSH PRIVATE KEY';
|
||||
else
|
||||
header = 'OPENSSH PUBLIC KEY';
|
||||
|
||||
var tmp = buf.toString('base64');
|
||||
var len = tmp.length + (tmp.length / 70) +
|
||||
18 + 16 + header.length*2 + 10;
|
||||
buf = new Buffer(len);
|
||||
var o = 0;
|
||||
o += buf.write('-----BEGIN ' + header + '-----\n', o);
|
||||
for (var i = 0; i < tmp.length; ) {
|
||||
var limit = i + 70;
|
||||
if (limit > tmp.length)
|
||||
limit = tmp.length;
|
||||
o += buf.write(tmp.slice(i, limit), o);
|
||||
buf[o++] = 10;
|
||||
i = limit;
|
||||
}
|
||||
o += buf.write('-----END ' + header + '-----\n', o);
|
||||
|
||||
return (buf.slice(0, o));
|
||||
}
|
114
node_modules/sshpk/lib/formats/ssh.js
generated
vendored
Normal file
114
node_modules/sshpk/lib/formats/ssh.js
generated
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
// Copyright 2015 Joyent, Inc.
|
||||
|
||||
module.exports = {
|
||||
read: read,
|
||||
write: write
|
||||
};
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var rfc4253 = require('./rfc4253');
|
||||
var utils = require('../utils');
|
||||
var Key = require('../key');
|
||||
var PrivateKey = require('../private-key');
|
||||
|
||||
var sshpriv = require('./ssh-private');
|
||||
|
||||
/*JSSTYLED*/
|
||||
var SSHKEY_RE = /^([a-z0-9-]+)[ \t]+([a-zA-Z0-9+\/]+[=]*)([\n \t]+([^\n]+))?$/;
|
||||
/*JSSTYLED*/
|
||||
var SSHKEY_RE2 = /^([a-z0-9-]+)[ \t]+([a-zA-Z0-9+\/ \t\n]+[=]*)(.*)$/;
|
||||
|
||||
function read(buf, options) {
|
||||
if (typeof (buf) !== 'string') {
|
||||
assert.buffer(buf, 'buf');
|
||||
buf = buf.toString('ascii');
|
||||
}
|
||||
|
||||
var trimmed = buf.trim().replace(/[\\\r]/g, '');
|
||||
var m = trimmed.match(SSHKEY_RE);
|
||||
if (!m)
|
||||
m = trimmed.match(SSHKEY_RE2);
|
||||
assert.ok(m, 'key must match regex');
|
||||
|
||||
var type = rfc4253.algToKeyType(m[1]);
|
||||
var kbuf = new Buffer(m[2], 'base64');
|
||||
|
||||
/*
|
||||
* This is a bit tricky. If we managed to parse the key and locate the
|
||||
* key comment with the regex, then do a non-partial read and assert
|
||||
* that we have consumed all bytes. If we couldn't locate the key
|
||||
* comment, though, there may be whitespace shenanigans going on that
|
||||
* have conjoined the comment to the rest of the key. We do a partial
|
||||
* read in this case to try to make the best out of a sorry situation.
|
||||
*/
|
||||
var key;
|
||||
var ret = {};
|
||||
if (m[4]) {
|
||||
try {
|
||||
key = rfc4253.read(kbuf);
|
||||
|
||||
} catch (e) {
|
||||
m = trimmed.match(SSHKEY_RE2);
|
||||
assert.ok(m, 'key must match regex');
|
||||
kbuf = new Buffer(m[2], 'base64');
|
||||
key = rfc4253.readInternal(ret, 'public', kbuf);
|
||||
}
|
||||
} else {
|
||||
key = rfc4253.readInternal(ret, 'public', kbuf);
|
||||
}
|
||||
|
||||
assert.strictEqual(type, key.type);
|
||||
|
||||
if (m[4] && m[4].length > 0) {
|
||||
key.comment = m[4];
|
||||
|
||||
} else if (ret.consumed) {
|
||||
/*
|
||||
* Now the magic: trying to recover the key comment when it's
|
||||
* gotten conjoined to the key or otherwise shenanigan'd.
|
||||
*
|
||||
* Work out how much base64 we used, then drop all non-base64
|
||||
* chars from the beginning up to this point in the the string.
|
||||
* Then offset in this and try to make up for missing = chars.
|
||||
*/
|
||||
var data = m[2] + m[3];
|
||||
var realOffset = Math.ceil(ret.consumed / 3) * 4;
|
||||
data = data.slice(0, realOffset - 2). /*JSSTYLED*/
|
||||
replace(/[^a-zA-Z0-9+\/=]/g, '') +
|
||||
data.slice(realOffset - 2);
|
||||
|
||||
var padding = ret.consumed % 3;
|
||||
if (padding > 0 &&
|
||||
data.slice(realOffset - 1, realOffset) !== '=')
|
||||
realOffset--;
|
||||
while (data.slice(realOffset, realOffset + 1) === '=')
|
||||
realOffset++;
|
||||
|
||||
/* Finally, grab what we think is the comment & clean it up. */
|
||||
var trailer = data.slice(realOffset);
|
||||
trailer = trailer.replace(/[\r\n]/g, ' ').
|
||||
replace(/^\s+/, '');
|
||||
if (trailer.match(/^[a-zA-Z0-9]/))
|
||||
key.comment = trailer;
|
||||
}
|
||||
|
||||
return (key);
|
||||
}
|
||||
|
||||
function write(key, options) {
|
||||
assert.object(key);
|
||||
if (!Key.isKey(key))
|
||||
throw (new Error('Must be a public key'));
|
||||
|
||||
var parts = [];
|
||||
var alg = rfc4253.keyTypeToAlg(key);
|
||||
parts.push(alg);
|
||||
|
||||
var buf = rfc4253.write(key);
|
||||
parts.push(buf.toString('base64'));
|
||||
|
||||
if (key.comment)
|
||||
parts.push(key.comment);
|
||||
|
||||
return (new Buffer(parts.join(' ')));
|
||||
}
|
77
node_modules/sshpk/lib/formats/x509-pem.js
generated
vendored
Normal file
77
node_modules/sshpk/lib/formats/x509-pem.js
generated
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright 2016 Joyent, Inc.
|
||||
|
||||
var x509 = require('./x509');
|
||||
|
||||
module.exports = {
|
||||
read: read,
|
||||
verify: x509.verify,
|
||||
sign: x509.sign,
|
||||
write: write
|
||||
};
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var asn1 = require('asn1');
|
||||
var algs = require('../algs');
|
||||
var utils = require('../utils');
|
||||
var Key = require('../key');
|
||||
var PrivateKey = require('../private-key');
|
||||
var pem = require('./pem');
|
||||
var Identity = require('../identity');
|
||||
var Signature = require('../signature');
|
||||
var Certificate = require('../certificate');
|
||||
|
||||
function read(buf, options) {
|
||||
if (typeof (buf) !== 'string') {
|
||||
assert.buffer(buf, 'buf');
|
||||
buf = buf.toString('ascii');
|
||||
}
|
||||
|
||||
var lines = buf.trim().split(/[\r\n]+/g);
|
||||
|
||||
var m = lines[0].match(/*JSSTYLED*/
|
||||
/[-]+[ ]*BEGIN CERTIFICATE[ ]*[-]+/);
|
||||
assert.ok(m, 'invalid PEM header');
|
||||
|
||||
var m2 = lines[lines.length - 1].match(/*JSSTYLED*/
|
||||
/[-]+[ ]*END CERTIFICATE[ ]*[-]+/);
|
||||
assert.ok(m2, 'invalid PEM footer');
|
||||
|
||||
var headers = {};
|
||||
while (true) {
|
||||
lines = lines.slice(1);
|
||||
m = lines[0].match(/*JSSTYLED*/
|
||||
/^([A-Za-z0-9-]+): (.+)$/);
|
||||
if (!m)
|
||||
break;
|
||||
headers[m[1].toLowerCase()] = m[2];
|
||||
}
|
||||
|
||||
/* Chop off the first and last lines */
|
||||
lines = lines.slice(0, -1).join('');
|
||||
buf = new Buffer(lines, 'base64');
|
||||
|
||||
return (x509.read(buf, options));
|
||||
}
|
||||
|
||||
function write(cert, options) {
|
||||
var dbuf = x509.write(cert, options);
|
||||
|
||||
var header = 'CERTIFICATE';
|
||||
var tmp = dbuf.toString('base64');
|
||||
var len = tmp.length + (tmp.length / 64) +
|
||||
18 + 16 + header.length*2 + 10;
|
||||
var buf = new Buffer(len);
|
||||
var o = 0;
|
||||
o += buf.write('-----BEGIN ' + header + '-----\n', o);
|
||||
for (var i = 0; i < tmp.length; ) {
|
||||
var limit = i + 64;
|
||||
if (limit > tmp.length)
|
||||
limit = tmp.length;
|
||||
o += buf.write(tmp.slice(i, limit), o);
|
||||
buf[o++] = 10;
|
||||
i = limit;
|
||||
}
|
||||
o += buf.write('-----END ' + header + '-----\n', o);
|
||||
|
||||
return (buf.slice(0, o));
|
||||
}
|
726
node_modules/sshpk/lib/formats/x509.js
generated
vendored
Normal file
726
node_modules/sshpk/lib/formats/x509.js
generated
vendored
Normal file
@ -0,0 +1,726 @@
|
||||
// Copyright 2017 Joyent, Inc.
|
||||
|
||||
module.exports = {
|
||||
read: read,
|
||||
verify: verify,
|
||||
sign: sign,
|
||||
signAsync: signAsync,
|
||||
write: write
|
||||
};
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var asn1 = require('asn1');
|
||||
var algs = require('../algs');
|
||||
var utils = require('../utils');
|
||||
var Key = require('../key');
|
||||
var PrivateKey = require('../private-key');
|
||||
var pem = require('./pem');
|
||||
var Identity = require('../identity');
|
||||
var Signature = require('../signature');
|
||||
var Certificate = require('../certificate');
|
||||
var pkcs8 = require('./pkcs8');
|
||||
|
||||
/*
|
||||
* This file is based on RFC5280 (X.509).
|
||||
*/
|
||||
|
||||
/* Helper to read in a single mpint */
|
||||
function readMPInt(der, nm) {
|
||||
assert.strictEqual(der.peek(), asn1.Ber.Integer,
|
||||
nm + ' is not an Integer');
|
||||
return (utils.mpNormalize(der.readString(asn1.Ber.Integer, true)));
|
||||
}
|
||||
|
||||
function verify(cert, key) {
|
||||
var sig = cert.signatures.x509;
|
||||
assert.object(sig, 'x509 signature');
|
||||
|
||||
var algParts = sig.algo.split('-');
|
||||
if (algParts[0] !== key.type)
|
||||
return (false);
|
||||
|
||||
var blob = sig.cache;
|
||||
if (blob === undefined) {
|
||||
var der = new asn1.BerWriter();
|
||||
writeTBSCert(cert, der);
|
||||
blob = der.buffer;
|
||||
}
|
||||
|
||||
var verifier = key.createVerify(algParts[1]);
|
||||
verifier.write(blob);
|
||||
return (verifier.verify(sig.signature));
|
||||
}
|
||||
|
||||
function Local(i) {
|
||||
return (asn1.Ber.Context | asn1.Ber.Constructor | i);
|
||||
}
|
||||
|
||||
function Context(i) {
|
||||
return (asn1.Ber.Context | i);
|
||||
}
|
||||
|
||||
var SIGN_ALGS = {
|
||||
'rsa-md5': '1.2.840.113549.1.1.4',
|
||||
'rsa-sha1': '1.2.840.113549.1.1.5',
|
||||
'rsa-sha256': '1.2.840.113549.1.1.11',
|
||||
'rsa-sha384': '1.2.840.113549.1.1.12',
|
||||
'rsa-sha512': '1.2.840.113549.1.1.13',
|
||||
'dsa-sha1': '1.2.840.10040.4.3',
|
||||
'dsa-sha256': '2.16.840.1.101.3.4.3.2',
|
||||
'ecdsa-sha1': '1.2.840.10045.4.1',
|
||||
'ecdsa-sha256': '1.2.840.10045.4.3.2',
|
||||
'ecdsa-sha384': '1.2.840.10045.4.3.3',
|
||||
'ecdsa-sha512': '1.2.840.10045.4.3.4'
|
||||
};
|
||||
Object.keys(SIGN_ALGS).forEach(function (k) {
|
||||
SIGN_ALGS[SIGN_ALGS[k]] = k;
|
||||
});
|
||||
SIGN_ALGS['1.3.14.3.2.3'] = 'rsa-md5';
|
||||
SIGN_ALGS['1.3.14.3.2.29'] = 'rsa-sha1';
|
||||
|
||||
var EXTS = {
|
||||
'issuerKeyId': '2.5.29.35',
|
||||
'altName': '2.5.29.17',
|
||||
'basicConstraints': '2.5.29.19',
|
||||
'keyUsage': '2.5.29.15',
|
||||
'extKeyUsage': '2.5.29.37'
|
||||
};
|
||||
|
||||
function read(buf, options) {
|
||||
if (typeof (buf) === 'string') {
|
||||
buf = new Buffer(buf, 'binary');
|
||||
}
|
||||
assert.buffer(buf, 'buf');
|
||||
|
||||
var der = new asn1.BerReader(buf);
|
||||
|
||||
der.readSequence();
|
||||
if (Math.abs(der.length - der.remain) > 1) {
|
||||
throw (new Error('DER sequence does not contain whole byte ' +
|
||||
'stream'));
|
||||
}
|
||||
|
||||
var tbsStart = der.offset;
|
||||
der.readSequence();
|
||||
var sigOffset = der.offset + der.length;
|
||||
var tbsEnd = sigOffset;
|
||||
|
||||
if (der.peek() === Local(0)) {
|
||||
der.readSequence(Local(0));
|
||||
var version = der.readInt();
|
||||
assert.ok(version <= 3,
|
||||
'only x.509 versions up to v3 supported');
|
||||
}
|
||||
|
||||
var cert = {};
|
||||
cert.signatures = {};
|
||||
var sig = (cert.signatures.x509 = {});
|
||||
sig.extras = {};
|
||||
|
||||
cert.serial = readMPInt(der, 'serial');
|
||||
|
||||
der.readSequence();
|
||||
var after = der.offset + der.length;
|
||||
var certAlgOid = der.readOID();
|
||||
var certAlg = SIGN_ALGS[certAlgOid];
|
||||
if (certAlg === undefined)
|
||||
throw (new Error('unknown signature algorithm ' + certAlgOid));
|
||||
|
||||
der._offset = after;
|
||||
cert.issuer = Identity.parseAsn1(der);
|
||||
|
||||
der.readSequence();
|
||||
cert.validFrom = readDate(der);
|
||||
cert.validUntil = readDate(der);
|
||||
|
||||
cert.subjects = [Identity.parseAsn1(der)];
|
||||
|
||||
der.readSequence();
|
||||
after = der.offset + der.length;
|
||||
cert.subjectKey = pkcs8.readPkcs8(undefined, 'public', der);
|
||||
der._offset = after;
|
||||
|
||||
/* issuerUniqueID */
|
||||
if (der.peek() === Local(1)) {
|
||||
der.readSequence(Local(1));
|
||||
sig.extras.issuerUniqueID =
|
||||
buf.slice(der.offset, der.offset + der.length);
|
||||
der._offset += der.length;
|
||||
}
|
||||
|
||||
/* subjectUniqueID */
|
||||
if (der.peek() === Local(2)) {
|
||||
der.readSequence(Local(2));
|
||||
sig.extras.subjectUniqueID =
|
||||
buf.slice(der.offset, der.offset + der.length);
|
||||
der._offset += der.length;
|
||||
}
|
||||
|
||||
/* extensions */
|
||||
if (der.peek() === Local(3)) {
|
||||
der.readSequence(Local(3));
|
||||
var extEnd = der.offset + der.length;
|
||||
der.readSequence();
|
||||
|
||||
while (der.offset < extEnd)
|
||||
readExtension(cert, buf, der);
|
||||
|
||||
assert.strictEqual(der.offset, extEnd);
|
||||
}
|
||||
|
||||
assert.strictEqual(der.offset, sigOffset);
|
||||
|
||||
der.readSequence();
|
||||
after = der.offset + der.length;
|
||||
var sigAlgOid = der.readOID();
|
||||
var sigAlg = SIGN_ALGS[sigAlgOid];
|
||||
if (sigAlg === undefined)
|
||||
throw (new Error('unknown signature algorithm ' + sigAlgOid));
|
||||
der._offset = after;
|
||||
|
||||
var sigData = der.readString(asn1.Ber.BitString, true);
|
||||
if (sigData[0] === 0)
|
||||
sigData = sigData.slice(1);
|
||||
var algParts = sigAlg.split('-');
|
||||
|
||||
sig.signature = Signature.parse(sigData, algParts[0], 'asn1');
|
||||
sig.signature.hashAlgorithm = algParts[1];
|
||||
sig.algo = sigAlg;
|
||||
sig.cache = buf.slice(tbsStart, tbsEnd);
|
||||
|
||||
return (new Certificate(cert));
|
||||
}
|
||||
|
||||
function readDate(der) {
|
||||
if (der.peek() === asn1.Ber.UTCTime) {
|
||||
return (utcTimeToDate(der.readString(asn1.Ber.UTCTime)));
|
||||
} else if (der.peek() === asn1.Ber.GeneralizedTime) {
|
||||
return (gTimeToDate(der.readString(asn1.Ber.GeneralizedTime)));
|
||||
} else {
|
||||
throw (new Error('Unsupported date format'));
|
||||
}
|
||||
}
|
||||
|
||||
/* RFC5280, section 4.2.1.6 (GeneralName type) */
|
||||
var ALTNAME = {
|
||||
OtherName: Local(0),
|
||||
RFC822Name: Context(1),
|
||||
DNSName: Context(2),
|
||||
X400Address: Local(3),
|
||||
DirectoryName: Local(4),
|
||||
EDIPartyName: Local(5),
|
||||
URI: Context(6),
|
||||
IPAddress: Context(7),
|
||||
OID: Context(8)
|
||||
};
|
||||
|
||||
/* RFC5280, section 4.2.1.12 (KeyPurposeId) */
|
||||
var EXTPURPOSE = {
|
||||
'serverAuth': '1.3.6.1.5.5.7.3.1',
|
||||
'clientAuth': '1.3.6.1.5.5.7.3.2',
|
||||
'codeSigning': '1.3.6.1.5.5.7.3.3',
|
||||
|
||||
/* See https://github.com/joyent/oid-docs/blob/master/root.md */
|
||||
'joyentDocker': '1.3.6.1.4.1.38678.1.4.1',
|
||||
'joyentCmon': '1.3.6.1.4.1.38678.1.4.2'
|
||||
};
|
||||
var EXTPURPOSE_REV = {};
|
||||
Object.keys(EXTPURPOSE).forEach(function (k) {
|
||||
EXTPURPOSE_REV[EXTPURPOSE[k]] = k;
|
||||
});
|
||||
|
||||
var KEYUSEBITS = [
|
||||
'signature', 'identity', 'keyEncryption',
|
||||
'encryption', 'keyAgreement', 'ca', 'crl'
|
||||
];
|
||||
|
||||
function readExtension(cert, buf, der) {
|
||||
der.readSequence();
|
||||
var after = der.offset + der.length;
|
||||
var extId = der.readOID();
|
||||
var id;
|
||||
var sig = cert.signatures.x509;
|
||||
sig.extras.exts = [];
|
||||
|
||||
var critical;
|
||||
if (der.peek() === asn1.Ber.Boolean)
|
||||
critical = der.readBoolean();
|
||||
|
||||
switch (extId) {
|
||||
case (EXTS.basicConstraints):
|
||||
der.readSequence(asn1.Ber.OctetString);
|
||||
der.readSequence();
|
||||
var bcEnd = der.offset + der.length;
|
||||
var ca = false;
|
||||
if (der.peek() === asn1.Ber.Boolean)
|
||||
ca = der.readBoolean();
|
||||
if (cert.purposes === undefined)
|
||||
cert.purposes = [];
|
||||
if (ca === true)
|
||||
cert.purposes.push('ca');
|
||||
var bc = { oid: extId, critical: critical };
|
||||
if (der.offset < bcEnd && der.peek() === asn1.Ber.Integer)
|
||||
bc.pathLen = der.readInt();
|
||||
sig.extras.exts.push(bc);
|
||||
break;
|
||||
case (EXTS.extKeyUsage):
|
||||
der.readSequence(asn1.Ber.OctetString);
|
||||
der.readSequence();
|
||||
if (cert.purposes === undefined)
|
||||
cert.purposes = [];
|
||||
var ekEnd = der.offset + der.length;
|
||||
while (der.offset < ekEnd) {
|
||||
var oid = der.readOID();
|
||||
cert.purposes.push(EXTPURPOSE_REV[oid] || oid);
|
||||
}
|
||||
/*
|
||||
* This is a bit of a hack: in the case where we have a cert
|
||||
* that's only allowed to do serverAuth or clientAuth (and not
|
||||
* the other), we want to make sure all our Subjects are of
|
||||
* the right type. But we already parsed our Subjects and
|
||||
* decided if they were hosts or users earlier (since it appears
|
||||
* first in the cert).
|
||||
*
|
||||
* So we go through and mutate them into the right kind here if
|
||||
* it doesn't match. This might not be hugely beneficial, as it
|
||||
* seems that single-purpose certs are not often seen in the
|
||||
* wild.
|
||||
*/
|
||||
if (cert.purposes.indexOf('serverAuth') !== -1 &&
|
||||
cert.purposes.indexOf('clientAuth') === -1) {
|
||||
cert.subjects.forEach(function (ide) {
|
||||
if (ide.type !== 'host') {
|
||||
ide.type = 'host';
|
||||
ide.hostname = ide.uid ||
|
||||
ide.email ||
|
||||
ide.components[0].value;
|
||||
}
|
||||
});
|
||||
} else if (cert.purposes.indexOf('clientAuth') !== -1 &&
|
||||
cert.purposes.indexOf('serverAuth') === -1) {
|
||||
cert.subjects.forEach(function (ide) {
|
||||
if (ide.type !== 'user') {
|
||||
ide.type = 'user';
|
||||
ide.uid = ide.hostname ||
|
||||
ide.email ||
|
||||
ide.components[0].value;
|
||||
}
|
||||
});
|
||||
}
|
||||
sig.extras.exts.push({ oid: extId, critical: critical });
|
||||
break;
|
||||
case (EXTS.keyUsage):
|
||||
der.readSequence(asn1.Ber.OctetString);
|
||||
var bits = der.readString(asn1.Ber.BitString, true);
|
||||
var setBits = readBitField(bits, KEYUSEBITS);
|
||||
setBits.forEach(function (bit) {
|
||||
if (cert.purposes === undefined)
|
||||
cert.purposes = [];
|
||||
if (cert.purposes.indexOf(bit) === -1)
|
||||
cert.purposes.push(bit);
|
||||
});
|
||||
sig.extras.exts.push({ oid: extId, critical: critical,
|
||||
bits: bits });
|
||||
break;
|
||||
case (EXTS.altName):
|
||||
der.readSequence(asn1.Ber.OctetString);
|
||||
der.readSequence();
|
||||
var aeEnd = der.offset + der.length;
|
||||
while (der.offset < aeEnd) {
|
||||
switch (der.peek()) {
|
||||
case ALTNAME.OtherName:
|
||||
case ALTNAME.EDIPartyName:
|
||||
der.readSequence();
|
||||
der._offset += der.length;
|
||||
break;
|
||||
case ALTNAME.OID:
|
||||
der.readOID(ALTNAME.OID);
|
||||
break;
|
||||
case ALTNAME.RFC822Name:
|
||||
/* RFC822 specifies email addresses */
|
||||
var email = der.readString(ALTNAME.RFC822Name);
|
||||
id = Identity.forEmail(email);
|
||||
if (!cert.subjects[0].equals(id))
|
||||
cert.subjects.push(id);
|
||||
break;
|
||||
case ALTNAME.DirectoryName:
|
||||
der.readSequence(ALTNAME.DirectoryName);
|
||||
id = Identity.parseAsn1(der);
|
||||
if (!cert.subjects[0].equals(id))
|
||||
cert.subjects.push(id);
|
||||
break;
|
||||
case ALTNAME.DNSName:
|
||||
var host = der.readString(
|
||||
ALTNAME.DNSName);
|
||||
id = Identity.forHost(host);
|
||||
if (!cert.subjects[0].equals(id))
|
||||
cert.subjects.push(id);
|
||||
break;
|
||||
default:
|
||||
der.readString(der.peek());
|
||||
break;
|
||||
}
|
||||
}
|
||||
sig.extras.exts.push({ oid: extId, critical: critical });
|
||||
break;
|
||||
default:
|
||||
sig.extras.exts.push({
|
||||
oid: extId,
|
||||
critical: critical,
|
||||
data: der.readString(asn1.Ber.OctetString, true)
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
der._offset = after;
|
||||
}
|
||||
|
||||
var UTCTIME_RE =
|
||||
/^([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})?Z$/;
|
||||
function utcTimeToDate(t) {
|
||||
var m = t.match(UTCTIME_RE);
|
||||
assert.ok(m, 'timestamps must be in UTC');
|
||||
var d = new Date();
|
||||
|
||||
var thisYear = d.getUTCFullYear();
|
||||
var century = Math.floor(thisYear / 100) * 100;
|
||||
|
||||
var year = parseInt(m[1], 10);
|
||||
if (thisYear % 100 < 50 && year >= 60)
|
||||
year += (century - 1);
|
||||
else
|
||||
year += century;
|
||||
d.setUTCFullYear(year, parseInt(m[2], 10) - 1, parseInt(m[3], 10));
|
||||
d.setUTCHours(parseInt(m[4], 10), parseInt(m[5], 10));
|
||||
if (m[6] && m[6].length > 0)
|
||||
d.setUTCSeconds(parseInt(m[6], 10));
|
||||
return (d);
|
||||
}
|
||||
|
||||
var GTIME_RE =
|
||||
/^([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})?Z$/;
|
||||
function gTimeToDate(t) {
|
||||
var m = t.match(GTIME_RE);
|
||||
assert.ok(m);
|
||||
var d = new Date();
|
||||
|
||||
d.setUTCFullYear(parseInt(m[1], 10), parseInt(m[2], 10) - 1,
|
||||
parseInt(m[3], 10));
|
||||
d.setUTCHours(parseInt(m[4], 10), parseInt(m[5], 10));
|
||||
if (m[6] && m[6].length > 0)
|
||||
d.setUTCSeconds(parseInt(m[6], 10));
|
||||
return (d);
|
||||
}
|
||||
|
||||
function zeroPad(n) {
|
||||
var s = '' + n;
|
||||
while (s.length < 2)
|
||||
s = '0' + s;
|
||||
return (s);
|
||||
}
|
||||
|
||||
function dateToUTCTime(d) {
|
||||
var s = '';
|
||||
s += zeroPad(d.getUTCFullYear() % 100);
|
||||
s += zeroPad(d.getUTCMonth() + 1);
|
||||
s += zeroPad(d.getUTCDate());
|
||||
s += zeroPad(d.getUTCHours());
|
||||
s += zeroPad(d.getUTCMinutes());
|
||||
s += zeroPad(d.getUTCSeconds());
|
||||
s += 'Z';
|
||||
return (s);
|
||||
}
|
||||
|
||||
function sign(cert, key) {
|
||||
if (cert.signatures.x509 === undefined)
|
||||
cert.signatures.x509 = {};
|
||||
var sig = cert.signatures.x509;
|
||||
|
||||
sig.algo = key.type + '-' + key.defaultHashAlgorithm();
|
||||
if (SIGN_ALGS[sig.algo] === undefined)
|
||||
return (false);
|
||||
|
||||
var der = new asn1.BerWriter();
|
||||
writeTBSCert(cert, der);
|
||||
var blob = der.buffer;
|
||||
sig.cache = blob;
|
||||
|
||||
var signer = key.createSign();
|
||||
signer.write(blob);
|
||||
cert.signatures.x509.signature = signer.sign();
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
function signAsync(cert, signer, done) {
|
||||
if (cert.signatures.x509 === undefined)
|
||||
cert.signatures.x509 = {};
|
||||
var sig = cert.signatures.x509;
|
||||
|
||||
var der = new asn1.BerWriter();
|
||||
writeTBSCert(cert, der);
|
||||
var blob = der.buffer;
|
||||
sig.cache = blob;
|
||||
|
||||
signer(blob, function (err, signature) {
|
||||
if (err) {
|
||||
done(err);
|
||||
return;
|
||||
}
|
||||
sig.algo = signature.type + '-' + signature.hashAlgorithm;
|
||||
if (SIGN_ALGS[sig.algo] === undefined) {
|
||||
done(new Error('Invalid signing algorithm "' +
|
||||
sig.algo + '"'));
|
||||
return;
|
||||
}
|
||||
sig.signature = signature;
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
function write(cert, options) {
|
||||
var sig = cert.signatures.x509;
|
||||
assert.object(sig, 'x509 signature');
|
||||
|
||||
var der = new asn1.BerWriter();
|
||||
der.startSequence();
|
||||
if (sig.cache) {
|
||||
der._ensure(sig.cache.length);
|
||||
sig.cache.copy(der._buf, der._offset);
|
||||
der._offset += sig.cache.length;
|
||||
} else {
|
||||
writeTBSCert(cert, der);
|
||||
}
|
||||
|
||||
der.startSequence();
|
||||
der.writeOID(SIGN_ALGS[sig.algo]);
|
||||
if (sig.algo.match(/^rsa-/))
|
||||
der.writeNull();
|
||||
der.endSequence();
|
||||
|
||||
var sigData = sig.signature.toBuffer('asn1');
|
||||
var data = new Buffer(sigData.length + 1);
|
||||
data[0] = 0;
|
||||
sigData.copy(data, 1);
|
||||
der.writeBuffer(data, asn1.Ber.BitString);
|
||||
der.endSequence();
|
||||
|
||||
return (der.buffer);
|
||||
}
|
||||
|
||||
function writeTBSCert(cert, der) {
|
||||
var sig = cert.signatures.x509;
|
||||
assert.object(sig, 'x509 signature');
|
||||
|
||||
der.startSequence();
|
||||
|
||||
der.startSequence(Local(0));
|
||||
der.writeInt(2);
|
||||
der.endSequence();
|
||||
|
||||
der.writeBuffer(utils.mpNormalize(cert.serial), asn1.Ber.Integer);
|
||||
|
||||
der.startSequence();
|
||||
der.writeOID(SIGN_ALGS[sig.algo]);
|
||||
der.endSequence();
|
||||
|
||||
cert.issuer.toAsn1(der);
|
||||
|
||||
der.startSequence();
|
||||
der.writeString(dateToUTCTime(cert.validFrom), asn1.Ber.UTCTime);
|
||||
der.writeString(dateToUTCTime(cert.validUntil), asn1.Ber.UTCTime);
|
||||
der.endSequence();
|
||||
|
||||
var subject = cert.subjects[0];
|
||||
var altNames = cert.subjects.slice(1);
|
||||
subject.toAsn1(der);
|
||||
|
||||
pkcs8.writePkcs8(der, cert.subjectKey);
|
||||
|
||||
if (sig.extras && sig.extras.issuerUniqueID) {
|
||||
der.writeBuffer(sig.extras.issuerUniqueID, Local(1));
|
||||
}
|
||||
|
||||
if (sig.extras && sig.extras.subjectUniqueID) {
|
||||
der.writeBuffer(sig.extras.subjectUniqueID, Local(2));
|
||||
}
|
||||
|
||||
if (altNames.length > 0 || subject.type === 'host' ||
|
||||
(cert.purposes !== undefined && cert.purposes.length > 0) ||
|
||||
(sig.extras && sig.extras.exts)) {
|
||||
der.startSequence(Local(3));
|
||||
der.startSequence();
|
||||
|
||||
var exts = [];
|
||||
if (cert.purposes !== undefined && cert.purposes.length > 0) {
|
||||
exts.push({
|
||||
oid: EXTS.basicConstraints,
|
||||
critical: true
|
||||
});
|
||||
exts.push({
|
||||
oid: EXTS.keyUsage,
|
||||
critical: true
|
||||
});
|
||||
exts.push({
|
||||
oid: EXTS.extKeyUsage,
|
||||
critical: true
|
||||
});
|
||||
}
|
||||
exts.push({ oid: EXTS.altName });
|
||||
if (sig.extras && sig.extras.exts)
|
||||
exts = sig.extras.exts;
|
||||
|
||||
for (var i = 0; i < exts.length; ++i) {
|
||||
der.startSequence();
|
||||
der.writeOID(exts[i].oid);
|
||||
|
||||
if (exts[i].critical !== undefined)
|
||||
der.writeBoolean(exts[i].critical);
|
||||
|
||||
if (exts[i].oid === EXTS.altName) {
|
||||
der.startSequence(asn1.Ber.OctetString);
|
||||
der.startSequence();
|
||||
if (subject.type === 'host') {
|
||||
der.writeString(subject.hostname,
|
||||
Context(2));
|
||||
}
|
||||
for (var j = 0; j < altNames.length; ++j) {
|
||||
if (altNames[j].type === 'host') {
|
||||
der.writeString(
|
||||
altNames[j].hostname,
|
||||
ALTNAME.DNSName);
|
||||
} else if (altNames[j].type ===
|
||||
'email') {
|
||||
der.writeString(
|
||||
altNames[j].email,
|
||||
ALTNAME.RFC822Name);
|
||||
} else {
|
||||
/*
|
||||
* Encode anything else as a
|
||||
* DN style name for now.
|
||||
*/
|
||||
der.startSequence(
|
||||
ALTNAME.DirectoryName);
|
||||
altNames[j].toAsn1(der);
|
||||
der.endSequence();
|
||||
}
|
||||
}
|
||||
der.endSequence();
|
||||
der.endSequence();
|
||||
} else if (exts[i].oid === EXTS.basicConstraints) {
|
||||
der.startSequence(asn1.Ber.OctetString);
|
||||
der.startSequence();
|
||||
var ca = (cert.purposes.indexOf('ca') !== -1);
|
||||
var pathLen = exts[i].pathLen;
|
||||
der.writeBoolean(ca);
|
||||
if (pathLen !== undefined)
|
||||
der.writeInt(pathLen);
|
||||
der.endSequence();
|
||||
der.endSequence();
|
||||
} else if (exts[i].oid === EXTS.extKeyUsage) {
|
||||
der.startSequence(asn1.Ber.OctetString);
|
||||
der.startSequence();
|
||||
cert.purposes.forEach(function (purpose) {
|
||||
if (purpose === 'ca')
|
||||
return;
|
||||
if (KEYUSEBITS.indexOf(purpose) !== -1)
|
||||
return;
|
||||
var oid = purpose;
|
||||
if (EXTPURPOSE[purpose] !== undefined)
|
||||
oid = EXTPURPOSE[purpose];
|
||||
der.writeOID(oid);
|
||||
});
|
||||
der.endSequence();
|
||||
der.endSequence();
|
||||
} else if (exts[i].oid === EXTS.keyUsage) {
|
||||
der.startSequence(asn1.Ber.OctetString);
|
||||
/*
|
||||
* If we parsed this certificate from a byte
|
||||
* stream (i.e. we didn't generate it in sshpk)
|
||||
* then we'll have a ".bits" property on the
|
||||
* ext with the original raw byte contents.
|
||||
*
|
||||
* If we have this, use it here instead of
|
||||
* regenerating it. This guarantees we output
|
||||
* the same data we parsed, so signatures still
|
||||
* validate.
|
||||
*/
|
||||
if (exts[i].bits !== undefined) {
|
||||
der.writeBuffer(exts[i].bits,
|
||||
asn1.Ber.BitString);
|
||||
} else {
|
||||
var bits = writeBitField(cert.purposes,
|
||||
KEYUSEBITS);
|
||||
der.writeBuffer(bits,
|
||||
asn1.Ber.BitString);
|
||||
}
|
||||
der.endSequence();
|
||||
} else {
|
||||
der.writeBuffer(exts[i].data,
|
||||
asn1.Ber.OctetString);
|
||||
}
|
||||
|
||||
der.endSequence();
|
||||
}
|
||||
|
||||
der.endSequence();
|
||||
der.endSequence();
|
||||
}
|
||||
|
||||
der.endSequence();
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads an ASN.1 BER bitfield out of the Buffer produced by doing
|
||||
* `BerReader#readString(asn1.Ber.BitString)`. That function gives us the raw
|
||||
* contents of the BitString tag, which is a count of unused bits followed by
|
||||
* the bits as a right-padded byte string.
|
||||
*
|
||||
* `bits` is the Buffer, `bitIndex` should contain an array of string names
|
||||
* for the bits in the string, ordered starting with bit #0 in the ASN.1 spec.
|
||||
*
|
||||
* Returns an array of Strings, the names of the bits that were set to 1.
|
||||
*/
|
||||
function readBitField(bits, bitIndex) {
|
||||
var bitLen = 8 * (bits.length - 1) - bits[0];
|
||||
var setBits = {};
|
||||
for (var i = 0; i < bitLen; ++i) {
|
||||
var byteN = 1 + Math.floor(i / 8);
|
||||
var bit = 7 - (i % 8);
|
||||
var mask = 1 << bit;
|
||||
var bitVal = ((bits[byteN] & mask) !== 0);
|
||||
var name = bitIndex[i];
|
||||
if (bitVal && typeof (name) === 'string') {
|
||||
setBits[name] = true;
|
||||
}
|
||||
}
|
||||
return (Object.keys(setBits));
|
||||
}
|
||||
|
||||
/*
|
||||
* `setBits` is an array of strings, containing the names for each bit that
|
||||
* sould be set to 1. `bitIndex` is same as in `readBitField()`.
|
||||
*
|
||||
* Returns a Buffer, ready to be written out with `BerWriter#writeString()`.
|
||||
*/
|
||||
function writeBitField(setBits, bitIndex) {
|
||||
var bitLen = bitIndex.length;
|
||||
var blen = Math.ceil(bitLen / 8);
|
||||
var unused = blen * 8 - bitLen;
|
||||
var bits = new Buffer(1 + blen);
|
||||
bits.fill(0);
|
||||
bits[0] = unused;
|
||||
for (var i = 0; i < bitLen; ++i) {
|
||||
var byteN = 1 + Math.floor(i / 8);
|
||||
var bit = 7 - (i % 8);
|
||||
var mask = 1 << bit;
|
||||
var name = bitIndex[i];
|
||||
if (name === undefined)
|
||||
continue;
|
||||
var bitVal = (setBits.indexOf(name) !== -1);
|
||||
if (bitVal) {
|
||||
bits[byteN] |= mask;
|
||||
}
|
||||
}
|
||||
return (bits);
|
||||
}
|
277
node_modules/sshpk/lib/identity.js
generated
vendored
Normal file
277
node_modules/sshpk/lib/identity.js
generated
vendored
Normal file
@ -0,0 +1,277 @@
|
||||
// Copyright 2017 Joyent, Inc.
|
||||
|
||||
module.exports = Identity;
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var algs = require('./algs');
|
||||
var crypto = require('crypto');
|
||||
var Fingerprint = require('./fingerprint');
|
||||
var Signature = require('./signature');
|
||||
var errs = require('./errors');
|
||||
var util = require('util');
|
||||
var utils = require('./utils');
|
||||
var asn1 = require('asn1');
|
||||
|
||||
/*JSSTYLED*/
|
||||
var DNS_NAME_RE = /^([*]|[a-z0-9][a-z0-9\-]{0,62})(?:\.([*]|[a-z0-9][a-z0-9\-]{0,62}))*$/i;
|
||||
|
||||
var oids = {};
|
||||
oids.cn = '2.5.4.3';
|
||||
oids.o = '2.5.4.10';
|
||||
oids.ou = '2.5.4.11';
|
||||
oids.l = '2.5.4.7';
|
||||
oids.s = '2.5.4.8';
|
||||
oids.c = '2.5.4.6';
|
||||
oids.sn = '2.5.4.4';
|
||||
oids.dc = '0.9.2342.19200300.100.1.25';
|
||||
oids.uid = '0.9.2342.19200300.100.1.1';
|
||||
oids.mail = '0.9.2342.19200300.100.1.3';
|
||||
|
||||
var unoids = {};
|
||||
Object.keys(oids).forEach(function (k) {
|
||||
unoids[oids[k]] = k;
|
||||
});
|
||||
|
||||
function Identity(opts) {
|
||||
var self = this;
|
||||
assert.object(opts, 'options');
|
||||
assert.arrayOfObject(opts.components, 'options.components');
|
||||
this.components = opts.components;
|
||||
this.componentLookup = {};
|
||||
this.components.forEach(function (c) {
|
||||
if (c.name && !c.oid)
|
||||
c.oid = oids[c.name];
|
||||
if (c.oid && !c.name)
|
||||
c.name = unoids[c.oid];
|
||||
if (self.componentLookup[c.name] === undefined)
|
||||
self.componentLookup[c.name] = [];
|
||||
self.componentLookup[c.name].push(c);
|
||||
});
|
||||
if (this.componentLookup.cn && this.componentLookup.cn.length > 0) {
|
||||
this.cn = this.componentLookup.cn[0].value;
|
||||
}
|
||||
assert.optionalString(opts.type, 'options.type');
|
||||
if (opts.type === undefined) {
|
||||
if (this.components.length === 1 &&
|
||||
this.componentLookup.cn &&
|
||||
this.componentLookup.cn.length === 1 &&
|
||||
this.componentLookup.cn[0].value.match(DNS_NAME_RE)) {
|
||||
this.type = 'host';
|
||||
this.hostname = this.componentLookup.cn[0].value;
|
||||
|
||||
} else if (this.componentLookup.dc &&
|
||||
this.components.length === this.componentLookup.dc.length) {
|
||||
this.type = 'host';
|
||||
this.hostname = this.componentLookup.dc.map(
|
||||
function (c) {
|
||||
return (c.value);
|
||||
}).join('.');
|
||||
|
||||
} else if (this.componentLookup.uid &&
|
||||
this.components.length ===
|
||||
this.componentLookup.uid.length) {
|
||||
this.type = 'user';
|
||||
this.uid = this.componentLookup.uid[0].value;
|
||||
|
||||
} else if (this.componentLookup.cn &&
|
||||
this.componentLookup.cn.length === 1 &&
|
||||
this.componentLookup.cn[0].value.match(DNS_NAME_RE)) {
|
||||
this.type = 'host';
|
||||
this.hostname = this.componentLookup.cn[0].value;
|
||||
|
||||
} else if (this.componentLookup.uid &&
|
||||
this.componentLookup.uid.length === 1) {
|
||||
this.type = 'user';
|
||||
this.uid = this.componentLookup.uid[0].value;
|
||||
|
||||
} else if (this.componentLookup.mail &&
|
||||
this.componentLookup.mail.length === 1) {
|
||||
this.type = 'email';
|
||||
this.email = this.componentLookup.mail[0].value;
|
||||
|
||||
} else if (this.componentLookup.cn &&
|
||||
this.componentLookup.cn.length === 1) {
|
||||
this.type = 'user';
|
||||
this.uid = this.componentLookup.cn[0].value;
|
||||
|
||||
} else {
|
||||
this.type = 'unknown';
|
||||
}
|
||||
} else {
|
||||
this.type = opts.type;
|
||||
if (this.type === 'host')
|
||||
this.hostname = opts.hostname;
|
||||
else if (this.type === 'user')
|
||||
this.uid = opts.uid;
|
||||
else if (this.type === 'email')
|
||||
this.email = opts.email;
|
||||
else
|
||||
throw (new Error('Unknown type ' + this.type));
|
||||
}
|
||||
}
|
||||
|
||||
Identity.prototype.toString = function () {
|
||||
return (this.components.map(function (c) {
|
||||
return (c.name.toUpperCase() + '=' + c.value);
|
||||
}).join(', '));
|
||||
};
|
||||
|
||||
/*
|
||||
* These are from X.680 -- PrintableString allowed chars are in section 37.4
|
||||
* table 8. Spec for IA5Strings is "1,6 + SPACE + DEL" where 1 refers to
|
||||
* ISO IR #001 (standard ASCII control characters) and 6 refers to ISO IR #006
|
||||
* (the basic ASCII character set).
|
||||
*/
|
||||
/* JSSTYLED */
|
||||
var NOT_PRINTABLE = /[^a-zA-Z0-9 '(),+.\/:=?-]/;
|
||||
/* JSSTYLED */
|
||||
var NOT_IA5 = /[^\x00-\x7f]/;
|
||||
|
||||
Identity.prototype.toAsn1 = function (der, tag) {
|
||||
der.startSequence(tag);
|
||||
this.components.forEach(function (c) {
|
||||
der.startSequence(asn1.Ber.Constructor | asn1.Ber.Set);
|
||||
der.startSequence();
|
||||
der.writeOID(c.oid);
|
||||
/*
|
||||
* If we fit in a PrintableString, use that. Otherwise use an
|
||||
* IA5String or UTF8String.
|
||||
*/
|
||||
if (c.value.match(NOT_IA5)) {
|
||||
var v = new Buffer(c.value, 'utf8');
|
||||
der.writeBuffer(v, asn1.Ber.Utf8String);
|
||||
} else if (c.value.match(NOT_PRINTABLE)) {
|
||||
der.writeString(c.value, asn1.Ber.IA5String);
|
||||
} else {
|
||||
der.writeString(c.value, asn1.Ber.PrintableString);
|
||||
}
|
||||
der.endSequence();
|
||||
der.endSequence();
|
||||
});
|
||||
der.endSequence();
|
||||
};
|
||||
|
||||
function globMatch(a, b) {
|
||||
if (a === '**' || b === '**')
|
||||
return (true);
|
||||
var aParts = a.split('.');
|
||||
var bParts = b.split('.');
|
||||
if (aParts.length !== bParts.length)
|
||||
return (false);
|
||||
for (var i = 0; i < aParts.length; ++i) {
|
||||
if (aParts[i] === '*' || bParts[i] === '*')
|
||||
continue;
|
||||
if (aParts[i] !== bParts[i])
|
||||
return (false);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
Identity.prototype.equals = function (other) {
|
||||
if (!Identity.isIdentity(other, [1, 0]))
|
||||
return (false);
|
||||
if (other.components.length !== this.components.length)
|
||||
return (false);
|
||||
for (var i = 0; i < this.components.length; ++i) {
|
||||
if (this.components[i].oid !== other.components[i].oid)
|
||||
return (false);
|
||||
if (!globMatch(this.components[i].value,
|
||||
other.components[i].value)) {
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
return (true);
|
||||
};
|
||||
|
||||
Identity.forHost = function (hostname) {
|
||||
assert.string(hostname, 'hostname');
|
||||
return (new Identity({
|
||||
type: 'host',
|
||||
hostname: hostname,
|
||||
components: [ { name: 'cn', value: hostname } ]
|
||||
}));
|
||||
};
|
||||
|
||||
Identity.forUser = function (uid) {
|
||||
assert.string(uid, 'uid');
|
||||
return (new Identity({
|
||||
type: 'user',
|
||||
uid: uid,
|
||||
components: [ { name: 'uid', value: uid } ]
|
||||
}));
|
||||
};
|
||||
|
||||
Identity.forEmail = function (email) {
|
||||
assert.string(email, 'email');
|
||||
return (new Identity({
|
||||
type: 'email',
|
||||
email: email,
|
||||
components: [ { name: 'mail', value: email } ]
|
||||
}));
|
||||
};
|
||||
|
||||
Identity.parseDN = function (dn) {
|
||||
assert.string(dn, 'dn');
|
||||
var parts = dn.split(',');
|
||||
var cmps = parts.map(function (c) {
|
||||
c = c.trim();
|
||||
var eqPos = c.indexOf('=');
|
||||
var name = c.slice(0, eqPos).toLowerCase();
|
||||
var value = c.slice(eqPos + 1);
|
||||
return ({ name: name, value: value });
|
||||
});
|
||||
return (new Identity({ components: cmps }));
|
||||
};
|
||||
|
||||
Identity.parseAsn1 = function (der, top) {
|
||||
var components = [];
|
||||
der.readSequence(top);
|
||||
var end = der.offset + der.length;
|
||||
while (der.offset < end) {
|
||||
der.readSequence(asn1.Ber.Constructor | asn1.Ber.Set);
|
||||
var after = der.offset + der.length;
|
||||
der.readSequence();
|
||||
var oid = der.readOID();
|
||||
var type = der.peek();
|
||||
var value;
|
||||
switch (type) {
|
||||
case asn1.Ber.PrintableString:
|
||||
case asn1.Ber.IA5String:
|
||||
case asn1.Ber.OctetString:
|
||||
case asn1.Ber.T61String:
|
||||
value = der.readString(type);
|
||||
break;
|
||||
case asn1.Ber.Utf8String:
|
||||
value = der.readString(type, true);
|
||||
value = value.toString('utf8');
|
||||
break;
|
||||
case asn1.Ber.CharacterString:
|
||||
case asn1.Ber.BMPString:
|
||||
value = der.readString(type, true);
|
||||
value = value.toString('utf16le');
|
||||
break;
|
||||
default:
|
||||
throw (new Error('Unknown asn1 type ' + type));
|
||||
}
|
||||
components.push({ oid: oid, value: value });
|
||||
der._offset = after;
|
||||
}
|
||||
der._offset = end;
|
||||
return (new Identity({
|
||||
components: components
|
||||
}));
|
||||
};
|
||||
|
||||
Identity.isIdentity = function (obj, ver) {
|
||||
return (utils.isCompatible(obj, Identity, ver));
|
||||
};
|
||||
|
||||
/*
|
||||
* API versions for Identity:
|
||||
* [1,0] -- initial ver
|
||||
*/
|
||||
Identity.prototype._sshpkApiVersion = [1, 0];
|
||||
|
||||
Identity._oldVersionDetect = function (obj) {
|
||||
return ([1, 0]);
|
||||
};
|
39
node_modules/sshpk/lib/index.js
generated
vendored
Normal file
39
node_modules/sshpk/lib/index.js
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2015 Joyent, Inc.
|
||||
|
||||
var Key = require('./key');
|
||||
var Fingerprint = require('./fingerprint');
|
||||
var Signature = require('./signature');
|
||||
var PrivateKey = require('./private-key');
|
||||
var Certificate = require('./certificate');
|
||||
var Identity = require('./identity');
|
||||
var errs = require('./errors');
|
||||
|
||||
module.exports = {
|
||||
/* top-level classes */
|
||||
Key: Key,
|
||||
parseKey: Key.parse,
|
||||
Fingerprint: Fingerprint,
|
||||
parseFingerprint: Fingerprint.parse,
|
||||
Signature: Signature,
|
||||
parseSignature: Signature.parse,
|
||||
PrivateKey: PrivateKey,
|
||||
parsePrivateKey: PrivateKey.parse,
|
||||
generatePrivateKey: PrivateKey.generate,
|
||||
Certificate: Certificate,
|
||||
parseCertificate: Certificate.parse,
|
||||
createSelfSignedCertificate: Certificate.createSelfSigned,
|
||||
createCertificate: Certificate.create,
|
||||
Identity: Identity,
|
||||
identityFromDN: Identity.parseDN,
|
||||
identityForHost: Identity.forHost,
|
||||
identityForUser: Identity.forUser,
|
||||
identityForEmail: Identity.forEmail,
|
||||
|
||||
/* errors */
|
||||
FingerprintFormatError: errs.FingerprintFormatError,
|
||||
InvalidAlgorithmError: errs.InvalidAlgorithmError,
|
||||
KeyParseError: errs.KeyParseError,
|
||||
SignatureParseError: errs.SignatureParseError,
|
||||
KeyEncryptedError: errs.KeyEncryptedError,
|
||||
CertificateParseError: errs.CertificateParseError
|
||||
};
|
274
node_modules/sshpk/lib/key.js
generated
vendored
Normal file
274
node_modules/sshpk/lib/key.js
generated
vendored
Normal file
@ -0,0 +1,274 @@
|
||||
// Copyright 2017 Joyent, Inc.
|
||||
|
||||
module.exports = Key;
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var algs = require('./algs');
|
||||
var crypto = require('crypto');
|
||||
var Fingerprint = require('./fingerprint');
|
||||
var Signature = require('./signature');
|
||||
var DiffieHellman = require('./dhe').DiffieHellman;
|
||||
var errs = require('./errors');
|
||||
var utils = require('./utils');
|
||||
var PrivateKey = require('./private-key');
|
||||
var edCompat;
|
||||
|
||||
try {
|
||||
edCompat = require('./ed-compat');
|
||||
} catch (e) {
|
||||
/* Just continue through, and bail out if we try to use it. */
|
||||
}
|
||||
|
||||
var InvalidAlgorithmError = errs.InvalidAlgorithmError;
|
||||
var KeyParseError = errs.KeyParseError;
|
||||
|
||||
var formats = {};
|
||||
formats['auto'] = require('./formats/auto');
|
||||
formats['pem'] = require('./formats/pem');
|
||||
formats['pkcs1'] = require('./formats/pkcs1');
|
||||
formats['pkcs8'] = require('./formats/pkcs8');
|
||||
formats['rfc4253'] = require('./formats/rfc4253');
|
||||
formats['ssh'] = require('./formats/ssh');
|
||||
formats['ssh-private'] = require('./formats/ssh-private');
|
||||
formats['openssh'] = formats['ssh-private'];
|
||||
|
||||
function Key(opts) {
|
||||
assert.object(opts, 'options');
|
||||
assert.arrayOfObject(opts.parts, 'options.parts');
|
||||
assert.string(opts.type, 'options.type');
|
||||
assert.optionalString(opts.comment, 'options.comment');
|
||||
|
||||
var algInfo = algs.info[opts.type];
|
||||
if (typeof (algInfo) !== 'object')
|
||||
throw (new InvalidAlgorithmError(opts.type));
|
||||
|
||||
var partLookup = {};
|
||||
for (var i = 0; i < opts.parts.length; ++i) {
|
||||
var part = opts.parts[i];
|
||||
partLookup[part.name] = part;
|
||||
}
|
||||
|
||||
this.type = opts.type;
|
||||
this.parts = opts.parts;
|
||||
this.part = partLookup;
|
||||
this.comment = undefined;
|
||||
this.source = opts.source;
|
||||
|
||||
/* for speeding up hashing/fingerprint operations */
|
||||
this._rfc4253Cache = opts._rfc4253Cache;
|
||||
this._hashCache = {};
|
||||
|
||||
var sz;
|
||||
this.curve = undefined;
|
||||
if (this.type === 'ecdsa') {
|
||||
var curve = this.part.curve.data.toString();
|
||||
this.curve = curve;
|
||||
sz = algs.curves[curve].size;
|
||||
} else if (this.type === 'ed25519') {
|
||||
sz = 256;
|
||||
this.curve = 'curve25519';
|
||||
} else {
|
||||
var szPart = this.part[algInfo.sizePart];
|
||||
sz = szPart.data.length;
|
||||
sz = sz * 8 - utils.countZeros(szPart.data);
|
||||
}
|
||||
this.size = sz;
|
||||
}
|
||||
|
||||
Key.formats = formats;
|
||||
|
||||
Key.prototype.toBuffer = function (format, options) {
|
||||
if (format === undefined)
|
||||
format = 'ssh';
|
||||
assert.string(format, 'format');
|
||||
assert.object(formats[format], 'formats[format]');
|
||||
assert.optionalObject(options, 'options');
|
||||
|
||||
if (format === 'rfc4253') {
|
||||
if (this._rfc4253Cache === undefined)
|
||||
this._rfc4253Cache = formats['rfc4253'].write(this);
|
||||
return (this._rfc4253Cache);
|
||||
}
|
||||
|
||||
return (formats[format].write(this, options));
|
||||
};
|
||||
|
||||
Key.prototype.toString = function (format, options) {
|
||||
return (this.toBuffer(format, options).toString());
|
||||
};
|
||||
|
||||
Key.prototype.hash = function (algo) {
|
||||
assert.string(algo, 'algorithm');
|
||||
algo = algo.toLowerCase();
|
||||
if (algs.hashAlgs[algo] === undefined)
|
||||
throw (new InvalidAlgorithmError(algo));
|
||||
|
||||
if (this._hashCache[algo])
|
||||
return (this._hashCache[algo]);
|
||||
|
||||
var hash = crypto.createHash(algo).
|
||||
update(this.toBuffer('rfc4253')).digest();
|
||||
this._hashCache[algo] = hash;
|
||||
return (hash);
|
||||
};
|
||||
|
||||
Key.prototype.fingerprint = function (algo) {
|
||||
if (algo === undefined)
|
||||
algo = 'sha256';
|
||||
assert.string(algo, 'algorithm');
|
||||
var opts = {
|
||||
type: 'key',
|
||||
hash: this.hash(algo),
|
||||
algorithm: algo
|
||||
};
|
||||
return (new Fingerprint(opts));
|
||||
};
|
||||
|
||||
Key.prototype.defaultHashAlgorithm = function () {
|
||||
var hashAlgo = 'sha1';
|
||||
if (this.type === 'rsa')
|
||||
hashAlgo = 'sha256';
|
||||
if (this.type === 'dsa' && this.size > 1024)
|
||||
hashAlgo = 'sha256';
|
||||
if (this.type === 'ed25519')
|
||||
hashAlgo = 'sha512';
|
||||
if (this.type === 'ecdsa') {
|
||||
if (this.size <= 256)
|
||||
hashAlgo = 'sha256';
|
||||
else if (this.size <= 384)
|
||||
hashAlgo = 'sha384';
|
||||
else
|
||||
hashAlgo = 'sha512';
|
||||
}
|
||||
return (hashAlgo);
|
||||
};
|
||||
|
||||
Key.prototype.createVerify = function (hashAlgo) {
|
||||
if (hashAlgo === undefined)
|
||||
hashAlgo = this.defaultHashAlgorithm();
|
||||
assert.string(hashAlgo, 'hash algorithm');
|
||||
|
||||
/* ED25519 is not supported by OpenSSL, use a javascript impl. */
|
||||
if (this.type === 'ed25519' && edCompat !== undefined)
|
||||
return (new edCompat.Verifier(this, hashAlgo));
|
||||
if (this.type === 'curve25519')
|
||||
throw (new Error('Curve25519 keys are not suitable for ' +
|
||||
'signing or verification'));
|
||||
|
||||
var v, nm, err;
|
||||
try {
|
||||
nm = hashAlgo.toUpperCase();
|
||||
v = crypto.createVerify(nm);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
if (v === undefined || (err instanceof Error &&
|
||||
err.message.match(/Unknown message digest/))) {
|
||||
nm = 'RSA-';
|
||||
nm += hashAlgo.toUpperCase();
|
||||
v = crypto.createVerify(nm);
|
||||
}
|
||||
assert.ok(v, 'failed to create verifier');
|
||||
var oldVerify = v.verify.bind(v);
|
||||
var key = this.toBuffer('pkcs8');
|
||||
var curve = this.curve;
|
||||
var self = this;
|
||||
v.verify = function (signature, fmt) {
|
||||
if (Signature.isSignature(signature, [2, 0])) {
|
||||
if (signature.type !== self.type)
|
||||
return (false);
|
||||
if (signature.hashAlgorithm &&
|
||||
signature.hashAlgorithm !== hashAlgo)
|
||||
return (false);
|
||||
if (signature.curve && self.type === 'ecdsa' &&
|
||||
signature.curve !== curve)
|
||||
return (false);
|
||||
return (oldVerify(key, signature.toBuffer('asn1')));
|
||||
|
||||
} else if (typeof (signature) === 'string' ||
|
||||
Buffer.isBuffer(signature)) {
|
||||
return (oldVerify(key, signature, fmt));
|
||||
|
||||
/*
|
||||
* Avoid doing this on valid arguments, walking the prototype
|
||||
* chain can be quite slow.
|
||||
*/
|
||||
} else if (Signature.isSignature(signature, [1, 0])) {
|
||||
throw (new Error('signature was created by too old ' +
|
||||
'a version of sshpk and cannot be verified'));
|
||||
|
||||
} else {
|
||||
throw (new TypeError('signature must be a string, ' +
|
||||
'Buffer, or Signature object'));
|
||||
}
|
||||
};
|
||||
return (v);
|
||||
};
|
||||
|
||||
Key.prototype.createDiffieHellman = function () {
|
||||
if (this.type === 'rsa')
|
||||
throw (new Error('RSA keys do not support Diffie-Hellman'));
|
||||
|
||||
return (new DiffieHellman(this));
|
||||
};
|
||||
Key.prototype.createDH = Key.prototype.createDiffieHellman;
|
||||
|
||||
Key.parse = function (data, format, options) {
|
||||
if (typeof (data) !== 'string')
|
||||
assert.buffer(data, 'data');
|
||||
if (format === undefined)
|
||||
format = 'auto';
|
||||
assert.string(format, 'format');
|
||||
if (typeof (options) === 'string')
|
||||
options = { filename: options };
|
||||
assert.optionalObject(options, 'options');
|
||||
if (options === undefined)
|
||||
options = {};
|
||||
assert.optionalString(options.filename, 'options.filename');
|
||||
if (options.filename === undefined)
|
||||
options.filename = '(unnamed)';
|
||||
|
||||
assert.object(formats[format], 'formats[format]');
|
||||
|
||||
try {
|
||||
var k = formats[format].read(data, options);
|
||||
if (k instanceof PrivateKey)
|
||||
k = k.toPublic();
|
||||
if (!k.comment)
|
||||
k.comment = options.filename;
|
||||
return (k);
|
||||
} catch (e) {
|
||||
if (e.name === 'KeyEncryptedError')
|
||||
throw (e);
|
||||
throw (new KeyParseError(options.filename, format, e));
|
||||
}
|
||||
};
|
||||
|
||||
Key.isKey = function (obj, ver) {
|
||||
return (utils.isCompatible(obj, Key, ver));
|
||||
};
|
||||
|
||||
/*
|
||||
* API versions for Key:
|
||||
* [1,0] -- initial ver, may take Signature for createVerify or may not
|
||||
* [1,1] -- added pkcs1, pkcs8 formats
|
||||
* [1,2] -- added auto, ssh-private, openssh formats
|
||||
* [1,3] -- added defaultHashAlgorithm
|
||||
* [1,4] -- added ed support, createDH
|
||||
* [1,5] -- first explicitly tagged version
|
||||
*/
|
||||
Key.prototype._sshpkApiVersion = [1, 5];
|
||||
|
||||
Key._oldVersionDetect = function (obj) {
|
||||
assert.func(obj.toBuffer);
|
||||
assert.func(obj.fingerprint);
|
||||
if (obj.createDH)
|
||||
return ([1, 4]);
|
||||
if (obj.defaultHashAlgorithm)
|
||||
return ([1, 3]);
|
||||
if (obj.formats['auto'])
|
||||
return ([1, 2]);
|
||||
if (obj.formats['pkcs1'])
|
||||
return ([1, 1]);
|
||||
return ([1, 0]);
|
||||
};
|
255
node_modules/sshpk/lib/private-key.js
generated
vendored
Normal file
255
node_modules/sshpk/lib/private-key.js
generated
vendored
Normal file
@ -0,0 +1,255 @@
|
||||
// Copyright 2017 Joyent, Inc.
|
||||
|
||||
module.exports = PrivateKey;
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var algs = require('./algs');
|
||||
var crypto = require('crypto');
|
||||
var Fingerprint = require('./fingerprint');
|
||||
var Signature = require('./signature');
|
||||
var errs = require('./errors');
|
||||
var util = require('util');
|
||||
var utils = require('./utils');
|
||||
var dhe = require('./dhe');
|
||||
var generateECDSA = dhe.generateECDSA;
|
||||
var generateED25519 = dhe.generateED25519;
|
||||
var edCompat;
|
||||
var ed;
|
||||
|
||||
try {
|
||||
edCompat = require('./ed-compat');
|
||||
} catch (e) {
|
||||
/* Just continue through, and bail out if we try to use it. */
|
||||
}
|
||||
|
||||
var Key = require('./key');
|
||||
|
||||
var InvalidAlgorithmError = errs.InvalidAlgorithmError;
|
||||
var KeyParseError = errs.KeyParseError;
|
||||
var KeyEncryptedError = errs.KeyEncryptedError;
|
||||
|
||||
var formats = {};
|
||||
formats['auto'] = require('./formats/auto');
|
||||
formats['pem'] = require('./formats/pem');
|
||||
formats['pkcs1'] = require('./formats/pkcs1');
|
||||
formats['pkcs8'] = require('./formats/pkcs8');
|
||||
formats['rfc4253'] = require('./formats/rfc4253');
|
||||
formats['ssh-private'] = require('./formats/ssh-private');
|
||||
formats['openssh'] = formats['ssh-private'];
|
||||
formats['ssh'] = formats['ssh-private'];
|
||||
|
||||
function PrivateKey(opts) {
|
||||
assert.object(opts, 'options');
|
||||
Key.call(this, opts);
|
||||
|
||||
this._pubCache = undefined;
|
||||
}
|
||||
util.inherits(PrivateKey, Key);
|
||||
|
||||
PrivateKey.formats = formats;
|
||||
|
||||
PrivateKey.prototype.toBuffer = function (format, options) {
|
||||
if (format === undefined)
|
||||
format = 'pkcs1';
|
||||
assert.string(format, 'format');
|
||||
assert.object(formats[format], 'formats[format]');
|
||||
assert.optionalObject(options, 'options');
|
||||
|
||||
return (formats[format].write(this, options));
|
||||
};
|
||||
|
||||
PrivateKey.prototype.hash = function (algo) {
|
||||
return (this.toPublic().hash(algo));
|
||||
};
|
||||
|
||||
PrivateKey.prototype.toPublic = function () {
|
||||
if (this._pubCache)
|
||||
return (this._pubCache);
|
||||
|
||||
var algInfo = algs.info[this.type];
|
||||
var pubParts = [];
|
||||
for (var i = 0; i < algInfo.parts.length; ++i) {
|
||||
var p = algInfo.parts[i];
|
||||
pubParts.push(this.part[p]);
|
||||
}
|
||||
|
||||
this._pubCache = new Key({
|
||||
type: this.type,
|
||||
source: this,
|
||||
parts: pubParts
|
||||
});
|
||||
if (this.comment)
|
||||
this._pubCache.comment = this.comment;
|
||||
return (this._pubCache);
|
||||
};
|
||||
|
||||
PrivateKey.prototype.derive = function (newType, newSize) {
|
||||
assert.string(newType, 'type');
|
||||
assert.optionalNumber(newSize, 'size');
|
||||
var priv, pub;
|
||||
|
||||
if (this.type === 'ed25519' && newType === 'curve25519') {
|
||||
if (ed === undefined)
|
||||
ed = require('jodid25519');
|
||||
|
||||
priv = this.part.r.data;
|
||||
if (priv[0] === 0x00)
|
||||
priv = priv.slice(1);
|
||||
priv = priv.slice(0, 32);
|
||||
|
||||
pub = ed.dh.publicKey(priv);
|
||||
priv = utils.mpNormalize(Buffer.concat([priv, pub]));
|
||||
|
||||
return (new PrivateKey({
|
||||
type: 'curve25519',
|
||||
parts: [
|
||||
{ name: 'R', data: utils.mpNormalize(pub) },
|
||||
{ name: 'r', data: priv }
|
||||
]
|
||||
}));
|
||||
} else if (this.type === 'curve25519' && newType === 'ed25519') {
|
||||
if (ed === undefined)
|
||||
ed = require('jodid25519');
|
||||
|
||||
priv = this.part.r.data;
|
||||
if (priv[0] === 0x00)
|
||||
priv = priv.slice(1);
|
||||
priv = priv.slice(0, 32);
|
||||
|
||||
pub = ed.eddsa.publicKey(priv.toString('binary'));
|
||||
pub = new Buffer(pub, 'binary');
|
||||
|
||||
priv = utils.mpNormalize(Buffer.concat([priv, pub]));
|
||||
|
||||
return (new PrivateKey({
|
||||
type: 'ed25519',
|
||||
parts: [
|
||||
{ name: 'R', data: utils.mpNormalize(pub) },
|
||||
{ name: 'r', data: priv }
|
||||
]
|
||||
}));
|
||||
}
|
||||
throw (new Error('Key derivation not supported from ' + this.type +
|
||||
' to ' + newType));
|
||||
};
|
||||
|
||||
PrivateKey.prototype.createVerify = function (hashAlgo) {
|
||||
return (this.toPublic().createVerify(hashAlgo));
|
||||
};
|
||||
|
||||
PrivateKey.prototype.createSign = function (hashAlgo) {
|
||||
if (hashAlgo === undefined)
|
||||
hashAlgo = this.defaultHashAlgorithm();
|
||||
assert.string(hashAlgo, 'hash algorithm');
|
||||
|
||||
/* ED25519 is not supported by OpenSSL, use a javascript impl. */
|
||||
if (this.type === 'ed25519' && edCompat !== undefined)
|
||||
return (new edCompat.Signer(this, hashAlgo));
|
||||
if (this.type === 'curve25519')
|
||||
throw (new Error('Curve25519 keys are not suitable for ' +
|
||||
'signing or verification'));
|
||||
|
||||
var v, nm, err;
|
||||
try {
|
||||
nm = hashAlgo.toUpperCase();
|
||||
v = crypto.createSign(nm);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
if (v === undefined || (err instanceof Error &&
|
||||
err.message.match(/Unknown message digest/))) {
|
||||
nm = 'RSA-';
|
||||
nm += hashAlgo.toUpperCase();
|
||||
v = crypto.createSign(nm);
|
||||
}
|
||||
assert.ok(v, 'failed to create verifier');
|
||||
var oldSign = v.sign.bind(v);
|
||||
var key = this.toBuffer('pkcs1');
|
||||
var type = this.type;
|
||||
var curve = this.curve;
|
||||
v.sign = function () {
|
||||
var sig = oldSign(key);
|
||||
if (typeof (sig) === 'string')
|
||||
sig = new Buffer(sig, 'binary');
|
||||
sig = Signature.parse(sig, type, 'asn1');
|
||||
sig.hashAlgorithm = hashAlgo;
|
||||
sig.curve = curve;
|
||||
return (sig);
|
||||
};
|
||||
return (v);
|
||||
};
|
||||
|
||||
PrivateKey.parse = function (data, format, options) {
|
||||
if (typeof (data) !== 'string')
|
||||
assert.buffer(data, 'data');
|
||||
if (format === undefined)
|
||||
format = 'auto';
|
||||
assert.string(format, 'format');
|
||||
if (typeof (options) === 'string')
|
||||
options = { filename: options };
|
||||
assert.optionalObject(options, 'options');
|
||||
if (options === undefined)
|
||||
options = {};
|
||||
assert.optionalString(options.filename, 'options.filename');
|
||||
if (options.filename === undefined)
|
||||
options.filename = '(unnamed)';
|
||||
|
||||
assert.object(formats[format], 'formats[format]');
|
||||
|
||||
try {
|
||||
var k = formats[format].read(data, options);
|
||||
assert.ok(k instanceof PrivateKey, 'key is not a private key');
|
||||
if (!k.comment)
|
||||
k.comment = options.filename;
|
||||
return (k);
|
||||
} catch (e) {
|
||||
if (e.name === 'KeyEncryptedError')
|
||||
throw (e);
|
||||
throw (new KeyParseError(options.filename, format, e));
|
||||
}
|
||||
};
|
||||
|
||||
PrivateKey.isPrivateKey = function (obj, ver) {
|
||||
return (utils.isCompatible(obj, PrivateKey, ver));
|
||||
};
|
||||
|
||||
PrivateKey.generate = function (type, options) {
|
||||
if (options === undefined)
|
||||
options = {};
|
||||
assert.object(options, 'options');
|
||||
|
||||
switch (type) {
|
||||
case 'ecdsa':
|
||||
if (options.curve === undefined)
|
||||
options.curve = 'nistp256';
|
||||
assert.string(options.curve, 'options.curve');
|
||||
return (generateECDSA(options.curve));
|
||||
case 'ed25519':
|
||||
return (generateED25519());
|
||||
default:
|
||||
throw (new Error('Key generation not supported with key ' +
|
||||
'type "' + type + '"'));
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* API versions for PrivateKey:
|
||||
* [1,0] -- initial ver
|
||||
* [1,1] -- added auto, pkcs[18], openssh/ssh-private formats
|
||||
* [1,2] -- added defaultHashAlgorithm
|
||||
* [1,3] -- added derive, ed, createDH
|
||||
* [1,4] -- first tagged version
|
||||
*/
|
||||
PrivateKey.prototype._sshpkApiVersion = [1, 4];
|
||||
|
||||
PrivateKey._oldVersionDetect = function (obj) {
|
||||
assert.func(obj.toPublic);
|
||||
assert.func(obj.createSign);
|
||||
if (obj.derive)
|
||||
return ([1, 3]);
|
||||
if (obj.defaultHashAlgorithm)
|
||||
return ([1, 2]);
|
||||
if (obj.formats['auto'])
|
||||
return ([1, 1]);
|
||||
return ([1, 0]);
|
||||
};
|
313
node_modules/sshpk/lib/signature.js
generated
vendored
Normal file
313
node_modules/sshpk/lib/signature.js
generated
vendored
Normal file
@ -0,0 +1,313 @@
|
||||
// Copyright 2015 Joyent, Inc.
|
||||
|
||||
module.exports = Signature;
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var algs = require('./algs');
|
||||
var crypto = require('crypto');
|
||||
var errs = require('./errors');
|
||||
var utils = require('./utils');
|
||||
var asn1 = require('asn1');
|
||||
var SSHBuffer = require('./ssh-buffer');
|
||||
|
||||
var InvalidAlgorithmError = errs.InvalidAlgorithmError;
|
||||
var SignatureParseError = errs.SignatureParseError;
|
||||
|
||||
function Signature(opts) {
|
||||
assert.object(opts, 'options');
|
||||
assert.arrayOfObject(opts.parts, 'options.parts');
|
||||
assert.string(opts.type, 'options.type');
|
||||
|
||||
var partLookup = {};
|
||||
for (var i = 0; i < opts.parts.length; ++i) {
|
||||
var part = opts.parts[i];
|
||||
partLookup[part.name] = part;
|
||||
}
|
||||
|
||||
this.type = opts.type;
|
||||
this.hashAlgorithm = opts.hashAlgo;
|
||||
this.curve = opts.curve;
|
||||
this.parts = opts.parts;
|
||||
this.part = partLookup;
|
||||
}
|
||||
|
||||
Signature.prototype.toBuffer = function (format) {
|
||||
if (format === undefined)
|
||||
format = 'asn1';
|
||||
assert.string(format, 'format');
|
||||
|
||||
var buf;
|
||||
var stype = 'ssh-' + this.type;
|
||||
|
||||
switch (this.type) {
|
||||
case 'rsa':
|
||||
switch (this.hashAlgorithm) {
|
||||
case 'sha256':
|
||||
stype = 'rsa-sha2-256';
|
||||
break;
|
||||
case 'sha512':
|
||||
stype = 'rsa-sha2-512';
|
||||
break;
|
||||
case 'sha1':
|
||||
case undefined:
|
||||
break;
|
||||
default:
|
||||
throw (new Error('SSH signature ' +
|
||||
'format does not support hash ' +
|
||||
'algorithm ' + this.hashAlgorithm));
|
||||
}
|
||||
if (format === 'ssh') {
|
||||
buf = new SSHBuffer({});
|
||||
buf.writeString(stype);
|
||||
buf.writePart(this.part.sig);
|
||||
return (buf.toBuffer());
|
||||
} else {
|
||||
return (this.part.sig.data);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ed25519':
|
||||
if (format === 'ssh') {
|
||||
buf = new SSHBuffer({});
|
||||
buf.writeString(stype);
|
||||
buf.writePart(this.part.sig);
|
||||
return (buf.toBuffer());
|
||||
} else {
|
||||
return (this.part.sig.data);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'dsa':
|
||||
case 'ecdsa':
|
||||
var r, s;
|
||||
if (format === 'asn1') {
|
||||
var der = new asn1.BerWriter();
|
||||
der.startSequence();
|
||||
r = utils.mpNormalize(this.part.r.data);
|
||||
s = utils.mpNormalize(this.part.s.data);
|
||||
der.writeBuffer(r, asn1.Ber.Integer);
|
||||
der.writeBuffer(s, asn1.Ber.Integer);
|
||||
der.endSequence();
|
||||
return (der.buffer);
|
||||
} else if (format === 'ssh' && this.type === 'dsa') {
|
||||
buf = new SSHBuffer({});
|
||||
buf.writeString('ssh-dss');
|
||||
r = this.part.r.data;
|
||||
if (r.length > 20 && r[0] === 0x00)
|
||||
r = r.slice(1);
|
||||
s = this.part.s.data;
|
||||
if (s.length > 20 && s[0] === 0x00)
|
||||
s = s.slice(1);
|
||||
if ((this.hashAlgorithm &&
|
||||
this.hashAlgorithm !== 'sha1') ||
|
||||
r.length + s.length !== 40) {
|
||||
throw (new Error('OpenSSH only supports ' +
|
||||
'DSA signatures with SHA1 hash'));
|
||||
}
|
||||
buf.writeBuffer(Buffer.concat([r, s]));
|
||||
return (buf.toBuffer());
|
||||
} else if (format === 'ssh' && this.type === 'ecdsa') {
|
||||
var inner = new SSHBuffer({});
|
||||
r = this.part.r.data;
|
||||
inner.writeBuffer(r);
|
||||
inner.writePart(this.part.s);
|
||||
|
||||
buf = new SSHBuffer({});
|
||||
/* XXX: find a more proper way to do this? */
|
||||
var curve;
|
||||
if (r[0] === 0x00)
|
||||
r = r.slice(1);
|
||||
var sz = r.length * 8;
|
||||
if (sz === 256)
|
||||
curve = 'nistp256';
|
||||
else if (sz === 384)
|
||||
curve = 'nistp384';
|
||||
else if (sz === 528)
|
||||
curve = 'nistp521';
|
||||
buf.writeString('ecdsa-sha2-' + curve);
|
||||
buf.writeBuffer(inner.toBuffer());
|
||||
return (buf.toBuffer());
|
||||
}
|
||||
throw (new Error('Invalid signature format'));
|
||||
default:
|
||||
throw (new Error('Invalid signature data'));
|
||||
}
|
||||
};
|
||||
|
||||
Signature.prototype.toString = function (format) {
|
||||
assert.optionalString(format, 'format');
|
||||
return (this.toBuffer(format).toString('base64'));
|
||||
};
|
||||
|
||||
Signature.parse = function (data, type, format) {
|
||||
if (typeof (data) === 'string')
|
||||
data = new Buffer(data, 'base64');
|
||||
assert.buffer(data, 'data');
|
||||
assert.string(format, 'format');
|
||||
assert.string(type, 'type');
|
||||
|
||||
var opts = {};
|
||||
opts.type = type.toLowerCase();
|
||||
opts.parts = [];
|
||||
|
||||
try {
|
||||
assert.ok(data.length > 0, 'signature must not be empty');
|
||||
switch (opts.type) {
|
||||
case 'rsa':
|
||||
return (parseOneNum(data, type, format, opts));
|
||||
case 'ed25519':
|
||||
return (parseOneNum(data, type, format, opts));
|
||||
|
||||
case 'dsa':
|
||||
case 'ecdsa':
|
||||
if (format === 'asn1')
|
||||
return (parseDSAasn1(data, type, format, opts));
|
||||
else if (opts.type === 'dsa')
|
||||
return (parseDSA(data, type, format, opts));
|
||||
else
|
||||
return (parseECDSA(data, type, format, opts));
|
||||
|
||||
default:
|
||||
throw (new InvalidAlgorithmError(type));
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
if (e instanceof InvalidAlgorithmError)
|
||||
throw (e);
|
||||
throw (new SignatureParseError(type, format, e));
|
||||
}
|
||||
};
|
||||
|
||||
function parseOneNum(data, type, format, opts) {
|
||||
if (format === 'ssh') {
|
||||
try {
|
||||
var buf = new SSHBuffer({buffer: data});
|
||||
var head = buf.readString();
|
||||
} catch (e) {
|
||||
/* fall through */
|
||||
}
|
||||
if (buf !== undefined) {
|
||||
var msg = 'SSH signature does not match expected ' +
|
||||
'type (expected ' + type + ', got ' + head + ')';
|
||||
switch (head) {
|
||||
case 'ssh-rsa':
|
||||
assert.strictEqual(type, 'rsa', msg);
|
||||
opts.hashAlgo = 'sha1';
|
||||
break;
|
||||
case 'rsa-sha2-256':
|
||||
assert.strictEqual(type, 'rsa', msg);
|
||||
opts.hashAlgo = 'sha256';
|
||||
break;
|
||||
case 'rsa-sha2-512':
|
||||
assert.strictEqual(type, 'rsa', msg);
|
||||
opts.hashAlgo = 'sha512';
|
||||
break;
|
||||
case 'ssh-ed25519':
|
||||
assert.strictEqual(type, 'ed25519', msg);
|
||||
opts.hashAlgo = 'sha512';
|
||||
break;
|
||||
default:
|
||||
throw (new Error('Unknown SSH signature ' +
|
||||
'type: ' + head));
|
||||
}
|
||||
var sig = buf.readPart();
|
||||
assert.ok(buf.atEnd(), 'extra trailing bytes');
|
||||
sig.name = 'sig';
|
||||
opts.parts.push(sig);
|
||||
return (new Signature(opts));
|
||||
}
|
||||
}
|
||||
opts.parts.push({name: 'sig', data: data});
|
||||
return (new Signature(opts));
|
||||
}
|
||||
|
||||
function parseDSAasn1(data, type, format, opts) {
|
||||
var der = new asn1.BerReader(data);
|
||||
der.readSequence();
|
||||
var r = der.readString(asn1.Ber.Integer, true);
|
||||
var s = der.readString(asn1.Ber.Integer, true);
|
||||
|
||||
opts.parts.push({name: 'r', data: utils.mpNormalize(r)});
|
||||
opts.parts.push({name: 's', data: utils.mpNormalize(s)});
|
||||
|
||||
return (new Signature(opts));
|
||||
}
|
||||
|
||||
function parseDSA(data, type, format, opts) {
|
||||
if (data.length != 40) {
|
||||
var buf = new SSHBuffer({buffer: data});
|
||||
var d = buf.readBuffer();
|
||||
if (d.toString('ascii') === 'ssh-dss')
|
||||
d = buf.readBuffer();
|
||||
assert.ok(buf.atEnd(), 'extra trailing bytes');
|
||||
assert.strictEqual(d.length, 40, 'invalid inner length');
|
||||
data = d;
|
||||
}
|
||||
opts.parts.push({name: 'r', data: data.slice(0, 20)});
|
||||
opts.parts.push({name: 's', data: data.slice(20, 40)});
|
||||
return (new Signature(opts));
|
||||
}
|
||||
|
||||
function parseECDSA(data, type, format, opts) {
|
||||
var buf = new SSHBuffer({buffer: data});
|
||||
|
||||
var r, s;
|
||||
var inner = buf.readBuffer();
|
||||
var stype = inner.toString('ascii');
|
||||
if (stype.slice(0, 6) === 'ecdsa-') {
|
||||
var parts = stype.split('-');
|
||||
assert.strictEqual(parts[0], 'ecdsa');
|
||||
assert.strictEqual(parts[1], 'sha2');
|
||||
opts.curve = parts[2];
|
||||
switch (opts.curve) {
|
||||
case 'nistp256':
|
||||
opts.hashAlgo = 'sha256';
|
||||
break;
|
||||
case 'nistp384':
|
||||
opts.hashAlgo = 'sha384';
|
||||
break;
|
||||
case 'nistp521':
|
||||
opts.hashAlgo = 'sha512';
|
||||
break;
|
||||
default:
|
||||
throw (new Error('Unsupported ECDSA curve: ' +
|
||||
opts.curve));
|
||||
}
|
||||
inner = buf.readBuffer();
|
||||
assert.ok(buf.atEnd(), 'extra trailing bytes on outer');
|
||||
buf = new SSHBuffer({buffer: inner});
|
||||
r = buf.readPart();
|
||||
} else {
|
||||
r = {data: inner};
|
||||
}
|
||||
|
||||
s = buf.readPart();
|
||||
assert.ok(buf.atEnd(), 'extra trailing bytes');
|
||||
|
||||
r.name = 'r';
|
||||
s.name = 's';
|
||||
|
||||
opts.parts.push(r);
|
||||
opts.parts.push(s);
|
||||
return (new Signature(opts));
|
||||
}
|
||||
|
||||
Signature.isSignature = function (obj, ver) {
|
||||
return (utils.isCompatible(obj, Signature, ver));
|
||||
};
|
||||
|
||||
/*
|
||||
* API versions for Signature:
|
||||
* [1,0] -- initial ver
|
||||
* [2,0] -- support for rsa in full ssh format, compat with sshpk-agent
|
||||
* hashAlgorithm property
|
||||
* [2,1] -- first tagged version
|
||||
*/
|
||||
Signature.prototype._sshpkApiVersion = [2, 1];
|
||||
|
||||
Signature._oldVersionDetect = function (obj) {
|
||||
assert.func(obj.toBuffer);
|
||||
if (obj.hasOwnProperty('hashAlgorithm'))
|
||||
return ([2, 0]);
|
||||
return ([1, 0]);
|
||||
};
|
148
node_modules/sshpk/lib/ssh-buffer.js
generated
vendored
Normal file
148
node_modules/sshpk/lib/ssh-buffer.js
generated
vendored
Normal file
@ -0,0 +1,148 @@
|
||||
// Copyright 2015 Joyent, Inc.
|
||||
|
||||
module.exports = SSHBuffer;
|
||||
|
||||
var assert = require('assert-plus');
|
||||
|
||||
function SSHBuffer(opts) {
|
||||
assert.object(opts, 'options');
|
||||
if (opts.buffer !== undefined)
|
||||
assert.buffer(opts.buffer, 'options.buffer');
|
||||
|
||||
this._size = opts.buffer ? opts.buffer.length : 1024;
|
||||
this._buffer = opts.buffer || (new Buffer(this._size));
|
||||
this._offset = 0;
|
||||
}
|
||||
|
||||
SSHBuffer.prototype.toBuffer = function () {
|
||||
return (this._buffer.slice(0, this._offset));
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.atEnd = function () {
|
||||
return (this._offset >= this._buffer.length);
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.remainder = function () {
|
||||
return (this._buffer.slice(this._offset));
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.skip = function (n) {
|
||||
this._offset += n;
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.expand = function () {
|
||||
this._size *= 2;
|
||||
var buf = new Buffer(this._size);
|
||||
this._buffer.copy(buf, 0);
|
||||
this._buffer = buf;
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.readPart = function () {
|
||||
return ({data: this.readBuffer()});
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.readBuffer = function () {
|
||||
var len = this._buffer.readUInt32BE(this._offset);
|
||||
this._offset += 4;
|
||||
assert.ok(this._offset + len <= this._buffer.length,
|
||||
'length out of bounds at +0x' + this._offset.toString(16) +
|
||||
' (data truncated?)');
|
||||
var buf = this._buffer.slice(this._offset, this._offset + len);
|
||||
this._offset += len;
|
||||
return (buf);
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.readString = function () {
|
||||
return (this.readBuffer().toString());
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.readCString = function () {
|
||||
var offset = this._offset;
|
||||
while (offset < this._buffer.length &&
|
||||
this._buffer[offset] !== 0x00)
|
||||
offset++;
|
||||
assert.ok(offset < this._buffer.length, 'c string does not terminate');
|
||||
var str = this._buffer.slice(this._offset, offset).toString();
|
||||
this._offset = offset + 1;
|
||||
return (str);
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.readInt = function () {
|
||||
var v = this._buffer.readUInt32BE(this._offset);
|
||||
this._offset += 4;
|
||||
return (v);
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.readInt64 = function () {
|
||||
assert.ok(this._offset + 8 < this._buffer.length,
|
||||
'buffer not long enough to read Int64');
|
||||
var v = this._buffer.slice(this._offset, this._offset + 8);
|
||||
this._offset += 8;
|
||||
return (v);
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.readChar = function () {
|
||||
var v = this._buffer[this._offset++];
|
||||
return (v);
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.writeBuffer = function (buf) {
|
||||
while (this._offset + 4 + buf.length > this._size)
|
||||
this.expand();
|
||||
this._buffer.writeUInt32BE(buf.length, this._offset);
|
||||
this._offset += 4;
|
||||
buf.copy(this._buffer, this._offset);
|
||||
this._offset += buf.length;
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.writeString = function (str) {
|
||||
this.writeBuffer(new Buffer(str, 'utf8'));
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.writeCString = function (str) {
|
||||
while (this._offset + 1 + str.length > this._size)
|
||||
this.expand();
|
||||
this._buffer.write(str, this._offset);
|
||||
this._offset += str.length;
|
||||
this._buffer[this._offset++] = 0;
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.writeInt = function (v) {
|
||||
while (this._offset + 4 > this._size)
|
||||
this.expand();
|
||||
this._buffer.writeUInt32BE(v, this._offset);
|
||||
this._offset += 4;
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.writeInt64 = function (v) {
|
||||
assert.buffer(v, 'value');
|
||||
if (v.length > 8) {
|
||||
var lead = v.slice(0, v.length - 8);
|
||||
for (var i = 0; i < lead.length; ++i) {
|
||||
assert.strictEqual(lead[i], 0,
|
||||
'must fit in 64 bits of precision');
|
||||
}
|
||||
v = v.slice(v.length - 8, v.length);
|
||||
}
|
||||
while (this._offset + 8 > this._size)
|
||||
this.expand();
|
||||
v.copy(this._buffer, this._offset);
|
||||
this._offset += 8;
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.writeChar = function (v) {
|
||||
while (this._offset + 1 > this._size)
|
||||
this.expand();
|
||||
this._buffer[this._offset++] = v;
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.writePart = function (p) {
|
||||
this.writeBuffer(p.data);
|
||||
};
|
||||
|
||||
SSHBuffer.prototype.write = function (buf) {
|
||||
while (this._offset + buf.length > this._size)
|
||||
this.expand();
|
||||
buf.copy(this._buffer, this._offset);
|
||||
this._offset += buf.length;
|
||||
};
|
288
node_modules/sshpk/lib/utils.js
generated
vendored
Normal file
288
node_modules/sshpk/lib/utils.js
generated
vendored
Normal file
@ -0,0 +1,288 @@
|
||||
// Copyright 2015 Joyent, Inc.
|
||||
|
||||
module.exports = {
|
||||
bufferSplit: bufferSplit,
|
||||
addRSAMissing: addRSAMissing,
|
||||
calculateDSAPublic: calculateDSAPublic,
|
||||
mpNormalize: mpNormalize,
|
||||
ecNormalize: ecNormalize,
|
||||
countZeros: countZeros,
|
||||
assertCompatible: assertCompatible,
|
||||
isCompatible: isCompatible,
|
||||
opensslKeyDeriv: opensslKeyDeriv,
|
||||
opensshCipherInfo: opensshCipherInfo
|
||||
};
|
||||
|
||||
var assert = require('assert-plus');
|
||||
var PrivateKey = require('./private-key');
|
||||
var crypto = require('crypto');
|
||||
|
||||
var MAX_CLASS_DEPTH = 3;
|
||||
|
||||
function isCompatible(obj, klass, needVer) {
|
||||
if (obj === null || typeof (obj) !== 'object')
|
||||
return (false);
|
||||
if (needVer === undefined)
|
||||
needVer = klass.prototype._sshpkApiVersion;
|
||||
if (obj instanceof klass &&
|
||||
klass.prototype._sshpkApiVersion[0] == needVer[0])
|
||||
return (true);
|
||||
var proto = Object.getPrototypeOf(obj);
|
||||
var depth = 0;
|
||||
while (proto.constructor.name !== klass.name) {
|
||||
proto = Object.getPrototypeOf(proto);
|
||||
if (!proto || ++depth > MAX_CLASS_DEPTH)
|
||||
return (false);
|
||||
}
|
||||
if (proto.constructor.name !== klass.name)
|
||||
return (false);
|
||||
var ver = proto._sshpkApiVersion;
|
||||
if (ver === undefined)
|
||||
ver = klass._oldVersionDetect(obj);
|
||||
if (ver[0] != needVer[0] || ver[1] < needVer[1])
|
||||
return (false);
|
||||
return (true);
|
||||
}
|
||||
|
||||
function assertCompatible(obj, klass, needVer, name) {
|
||||
if (name === undefined)
|
||||
name = 'object';
|
||||
assert.ok(obj, name + ' must not be null');
|
||||
assert.object(obj, name + ' must be an object');
|
||||
if (needVer === undefined)
|
||||
needVer = klass.prototype._sshpkApiVersion;
|
||||
if (obj instanceof klass &&
|
||||
klass.prototype._sshpkApiVersion[0] == needVer[0])
|
||||
return;
|
||||
var proto = Object.getPrototypeOf(obj);
|
||||
var depth = 0;
|
||||
while (proto.constructor.name !== klass.name) {
|
||||
proto = Object.getPrototypeOf(proto);
|
||||
assert.ok(proto && ++depth <= MAX_CLASS_DEPTH,
|
||||
name + ' must be a ' + klass.name + ' instance');
|
||||
}
|
||||
assert.strictEqual(proto.constructor.name, klass.name,
|
||||
name + ' must be a ' + klass.name + ' instance');
|
||||
var ver = proto._sshpkApiVersion;
|
||||
if (ver === undefined)
|
||||
ver = klass._oldVersionDetect(obj);
|
||||
assert.ok(ver[0] == needVer[0] && ver[1] >= needVer[1],
|
||||
name + ' must be compatible with ' + klass.name + ' klass ' +
|
||||
'version ' + needVer[0] + '.' + needVer[1]);
|
||||
}
|
||||
|
||||
var CIPHER_LEN = {
|
||||
'des-ede3-cbc': { key: 7, iv: 8 },
|
||||
'aes-128-cbc': { key: 16, iv: 16 }
|
||||
};
|
||||
var PKCS5_SALT_LEN = 8;
|
||||
|
||||
function opensslKeyDeriv(cipher, salt, passphrase, count) {
|
||||
assert.buffer(salt, 'salt');
|
||||
assert.buffer(passphrase, 'passphrase');
|
||||
assert.number(count, 'iteration count');
|
||||
|
||||
var clen = CIPHER_LEN[cipher];
|
||||
assert.object(clen, 'supported cipher');
|
||||
|
||||
salt = salt.slice(0, PKCS5_SALT_LEN);
|
||||
|
||||
var D, D_prev, bufs;
|
||||
var material = new Buffer(0);
|
||||
while (material.length < clen.key + clen.iv) {
|
||||
bufs = [];
|
||||
if (D_prev)
|
||||
bufs.push(D_prev);
|
||||
bufs.push(passphrase);
|
||||
bufs.push(salt);
|
||||
D = Buffer.concat(bufs);
|
||||
for (var j = 0; j < count; ++j)
|
||||
D = crypto.createHash('md5').update(D).digest();
|
||||
material = Buffer.concat([material, D]);
|
||||
D_prev = D;
|
||||
}
|
||||
|
||||
return ({
|
||||
key: material.slice(0, clen.key),
|
||||
iv: material.slice(clen.key, clen.key + clen.iv)
|
||||
});
|
||||
}
|
||||
|
||||
/* Count leading zero bits on a buffer */
|
||||
function countZeros(buf) {
|
||||
var o = 0, obit = 8;
|
||||
while (o < buf.length) {
|
||||
var mask = (1 << obit);
|
||||
if ((buf[o] & mask) === mask)
|
||||
break;
|
||||
obit--;
|
||||
if (obit < 0) {
|
||||
o++;
|
||||
obit = 8;
|
||||
}
|
||||
}
|
||||
return (o*8 + (8 - obit) - 1);
|
||||
}
|
||||
|
||||
function bufferSplit(buf, chr) {
|
||||
assert.buffer(buf);
|
||||
assert.string(chr);
|
||||
|
||||
var parts = [];
|
||||
var lastPart = 0;
|
||||
var matches = 0;
|
||||
for (var i = 0; i < buf.length; ++i) {
|
||||
if (buf[i] === chr.charCodeAt(matches))
|
||||
++matches;
|
||||
else if (buf[i] === chr.charCodeAt(0))
|
||||
matches = 1;
|
||||
else
|
||||
matches = 0;
|
||||
|
||||
if (matches >= chr.length) {
|
||||
var newPart = i + 1;
|
||||
parts.push(buf.slice(lastPart, newPart - matches));
|
||||
lastPart = newPart;
|
||||
matches = 0;
|
||||
}
|
||||
}
|
||||
if (lastPart <= buf.length)
|
||||
parts.push(buf.slice(lastPart, buf.length));
|
||||
|
||||
return (parts);
|
||||
}
|
||||
|
||||
function ecNormalize(buf, addZero) {
|
||||
assert.buffer(buf);
|
||||
if (buf[0] === 0x00 && buf[1] === 0x04) {
|
||||
if (addZero)
|
||||
return (buf);
|
||||
return (buf.slice(1));
|
||||
} else if (buf[0] === 0x04) {
|
||||
if (!addZero)
|
||||
return (buf);
|
||||
} else {
|
||||
while (buf[0] === 0x00)
|
||||
buf = buf.slice(1);
|
||||
if (buf[0] === 0x02 || buf[0] === 0x03)
|
||||
throw (new Error('Compressed elliptic curve points ' +
|
||||
'are not supported'));
|
||||
if (buf[0] !== 0x04)
|
||||
throw (new Error('Not a valid elliptic curve point'));
|
||||
if (!addZero)
|
||||
return (buf);
|
||||
}
|
||||
var b = new Buffer(buf.length + 1);
|
||||
b[0] = 0x0;
|
||||
buf.copy(b, 1);
|
||||
return (b);
|
||||
}
|
||||
|
||||
function mpNormalize(buf) {
|
||||
assert.buffer(buf);
|
||||
while (buf.length > 1 && buf[0] === 0x00 && (buf[1] & 0x80) === 0x00)
|
||||
buf = buf.slice(1);
|
||||
if ((buf[0] & 0x80) === 0x80) {
|
||||
var b = new Buffer(buf.length + 1);
|
||||
b[0] = 0x00;
|
||||
buf.copy(b, 1);
|
||||
buf = b;
|
||||
}
|
||||
return (buf);
|
||||
}
|
||||
|
||||
function bigintToMpBuf(bigint) {
|
||||
var buf = new Buffer(bigint.toByteArray());
|
||||
buf = mpNormalize(buf);
|
||||
return (buf);
|
||||
}
|
||||
|
||||
function calculateDSAPublic(g, p, x) {
|
||||
assert.buffer(g);
|
||||
assert.buffer(p);
|
||||
assert.buffer(x);
|
||||
try {
|
||||
var bigInt = require('jsbn').BigInteger;
|
||||
} catch (e) {
|
||||
throw (new Error('To load a PKCS#8 format DSA private key, ' +
|
||||
'the node jsbn library is required.'));
|
||||
}
|
||||
g = new bigInt(g);
|
||||
p = new bigInt(p);
|
||||
x = new bigInt(x);
|
||||
var y = g.modPow(x, p);
|
||||
var ybuf = bigintToMpBuf(y);
|
||||
return (ybuf);
|
||||
}
|
||||
|
||||
function addRSAMissing(key) {
|
||||
assert.object(key);
|
||||
assertCompatible(key, PrivateKey, [1, 1]);
|
||||
try {
|
||||
var bigInt = require('jsbn').BigInteger;
|
||||
} catch (e) {
|
||||
throw (new Error('To write a PEM private key from ' +
|
||||
'this source, the node jsbn lib is required.'));
|
||||
}
|
||||
|
||||
var d = new bigInt(key.part.d.data);
|
||||
var buf;
|
||||
|
||||
if (!key.part.dmodp) {
|
||||
var p = new bigInt(key.part.p.data);
|
||||
var dmodp = d.mod(p.subtract(1));
|
||||
|
||||
buf = bigintToMpBuf(dmodp);
|
||||
key.part.dmodp = {name: 'dmodp', data: buf};
|
||||
key.parts.push(key.part.dmodp);
|
||||
}
|
||||
if (!key.part.dmodq) {
|
||||
var q = new bigInt(key.part.q.data);
|
||||
var dmodq = d.mod(q.subtract(1));
|
||||
|
||||
buf = bigintToMpBuf(dmodq);
|
||||
key.part.dmodq = {name: 'dmodq', data: buf};
|
||||
key.parts.push(key.part.dmodq);
|
||||
}
|
||||
}
|
||||
|
||||
function opensshCipherInfo(cipher) {
|
||||
var inf = {};
|
||||
switch (cipher) {
|
||||
case '3des-cbc':
|
||||
inf.keySize = 24;
|
||||
inf.blockSize = 8;
|
||||
inf.opensslName = 'des-ede3-cbc';
|
||||
break;
|
||||
case 'blowfish-cbc':
|
||||
inf.keySize = 16;
|
||||
inf.blockSize = 8;
|
||||
inf.opensslName = 'bf-cbc';
|
||||
break;
|
||||
case 'aes128-cbc':
|
||||
case 'aes128-ctr':
|
||||
case 'aes128-gcm@openssh.com':
|
||||
inf.keySize = 16;
|
||||
inf.blockSize = 16;
|
||||
inf.opensslName = 'aes-128-' + cipher.slice(7, 10);
|
||||
break;
|
||||
case 'aes192-cbc':
|
||||
case 'aes192-ctr':
|
||||
case 'aes192-gcm@openssh.com':
|
||||
inf.keySize = 24;
|
||||
inf.blockSize = 16;
|
||||
inf.opensslName = 'aes-192-' + cipher.slice(7, 10);
|
||||
break;
|
||||
case 'aes256-cbc':
|
||||
case 'aes256-ctr':
|
||||
case 'aes256-gcm@openssh.com':
|
||||
inf.keySize = 32;
|
||||
inf.blockSize = 16;
|
||||
inf.opensslName = 'aes-256-' + cipher.slice(7, 10);
|
||||
break;
|
||||
default:
|
||||
throw (new Error(
|
||||
'Unsupported openssl cipher "' + cipher + '"'));
|
||||
}
|
||||
return (inf);
|
||||
}
|
135
node_modules/sshpk/man/man1/sshpk-conv.1
generated
vendored
Normal file
135
node_modules/sshpk/man/man1/sshpk-conv.1
generated
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
.TH sshpk\-conv 1 "Jan 2016" sshpk "sshpk Commands"
|
||||
.SH NAME
|
||||
.PP
|
||||
sshpk\-conv \- convert between key formats
|
||||
.SH SYNOPSYS
|
||||
.PP
|
||||
\fB\fCsshpk\-conv\fR \-t FORMAT [FILENAME] [OPTIONS...]
|
||||
.PP
|
||||
\fB\fCsshpk\-conv\fR \-i [FILENAME] [OPTIONS...]
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Reads in a public or private key and converts it between different formats,
|
||||
particularly formats used in the SSH protocol and the well\-known PEM PKCS#1/7
|
||||
formats.
|
||||
.PP
|
||||
In the second form, with the \fB\fC\-i\fR option given, identifies a key and prints to
|
||||
stderr information about its nature, size and fingerprint.
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
Assume the following SSH\-format public key in \fB\fCid_ecdsa.pub\fR:
|
||||
.PP
|
||||
.RS
|
||||
.nf
|
||||
ecdsa\-sha2\-nistp256 AAAAE2VjZHNhLXNoYTI...9M/4c4= user@host
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
Identify it with \fB\fC\-i\fR:
|
||||
.PP
|
||||
.RS
|
||||
.nf
|
||||
$ sshpk\-conv \-i id_ecdsa.pub
|
||||
id_ecdsa: a 256 bit ECDSA public key
|
||||
ECDSA curve: nistp256
|
||||
Comment: user@host
|
||||
Fingerprint:
|
||||
SHA256:vCNX7eUkdvqqW0m4PoxQAZRv+CM4P4fS8+CbliAvS4k
|
||||
81:ad:d5:57:e5:6f:7d:a2:93:79:56:af:d7:c0:38:51
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
Convert it to \fB\fCpkcs8\fR format, for use with e.g. OpenSSL:
|
||||
.PP
|
||||
.RS
|
||||
.nf
|
||||
$ sshpk\-conv \-t pkcs8 id_ecdsa
|
||||
\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-
|
||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAsA4R6N6AS3gzaPBeLjG2ObSgUsR
|
||||
zOt+kWJoijLnw3ZMYUKmAx+lD0I5XUxdrPcs1vH5f3cn9TvRvO9L0z/hzg==
|
||||
\-\-\-\-\-END PUBLIC KEY\-\-\-\-\-
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
Retrieve the public half of a private key:
|
||||
.PP
|
||||
.RS
|
||||
.nf
|
||||
$ openssl genrsa 2048 | sshpk\-conv \-t ssh \-c foo@bar
|
||||
ssh\-rsa AAAAB3NzaC1yc2EAAA...koK7 foo@bar
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
Convert a private key to PKCS#1 (OpenSSL) format from a new\-style OpenSSH key
|
||||
format (the \fB\fCssh\-keygen \-o\fR format):
|
||||
.PP
|
||||
.RS
|
||||
.nf
|
||||
$ ssh\-keygen \-o \-f foobar
|
||||
\&...
|
||||
$ sshpk\-conv \-p \-t pkcs1 foobar
|
||||
\-\-\-\-\-BEGIN RSA PRIVATE KEY\-\-\-\-\-
|
||||
MIIDpAIBAAKCAQEA6T/GYJndb1TRH3+NL....
|
||||
\-\-\-\-\-END RSA PRIVATE KEY\-\-\-\-\-
|
||||
.fi
|
||||
.RE
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\fC\-i, \-\-identify\fR
|
||||
Instead of converting the key, output identifying information about it to
|
||||
stderr, including its type, size and fingerprints.
|
||||
.TP
|
||||
\fB\fC\-p, \-\-private\fR
|
||||
Treat the key as a private key instead of a public key (the default). If you
|
||||
supply \fB\fCsshpk\-conv\fR with a private key and do not give this option, it will
|
||||
extract only the public half of the key from it and work with that.
|
||||
.TP
|
||||
\fB\fC\-f PATH, \-\-file=PATH\fR
|
||||
Input file to take the key from instead of stdin. If a filename is supplied
|
||||
as a positional argument, it is equivalent to using this option.
|
||||
.TP
|
||||
\fB\fC\-o PATH, \-\-out=PATH\fR
|
||||
Output file name to use instead of stdout.
|
||||
.PP
|
||||
\fB\fC\-T FORMAT, \-\-informat=FORMAT\fR
|
||||
.TP
|
||||
\fB\fC\-t FORMAT, \-\-outformat=FORMAT\fR
|
||||
Selects the input and output formats to be used (see FORMATS, below).
|
||||
.TP
|
||||
\fB\fC\-c TEXT, \-\-comment=TEXT\fR
|
||||
Sets the key comment for the output file, if supported.
|
||||
.SH FORMATS
|
||||
.PP
|
||||
Currently supported formats:
|
||||
.TP
|
||||
\fB\fCpem, pkcs1\fR
|
||||
The standard PEM format used by older OpenSSH and most TLS libraries such as
|
||||
OpenSSL. The classic \fB\fCid_rsa\fR file is usually in this format. It is an ASN.1
|
||||
encoded structure, base64\-encoded and placed between PEM headers.
|
||||
.TP
|
||||
\fB\fCssh\fR
|
||||
The SSH public key text format (the format of an \fB\fCid_rsa.pub\fR file). A single
|
||||
line, containing 3 space separated parts: the key type, key body and optional
|
||||
key comment.
|
||||
.TP
|
||||
\fB\fCpkcs8\fR
|
||||
A newer PEM format, usually used only for public keys by TLS libraries such
|
||||
as OpenSSL. The ASN.1 structure is more generic than that of \fB\fCpkcs1\fR\&.
|
||||
.TP
|
||||
\fB\fCopenssh\fR
|
||||
The new \fB\fCssh\-keygen \-o\fR format from OpenSSH. This can be mistaken for a PEM
|
||||
encoding but is actually an OpenSSH internal format.
|
||||
.TP
|
||||
\fB\fCrfc4253\fR
|
||||
The internal binary format of keys when sent over the wire in the SSH
|
||||
protocol. This is also the format that the \fB\fCssh\-agent\fR uses in its protocol.
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
.BR ssh-keygen (1),
|
||||
.BR openssl (1)
|
||||
.SH BUGS
|
||||
.PP
|
||||
Encrypted (password\-protected) keys are not supported.
|
||||
.PP
|
||||
Report bugs at Github
|
||||
\[la]https://github.com/arekinath/node-sshpk/issues\[ra]
|
81
node_modules/sshpk/man/man1/sshpk-sign.1
generated
vendored
Normal file
81
node_modules/sshpk/man/man1/sshpk-sign.1
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
.TH sshpk\-sign 1 "Jan 2016" sshpk "sshpk Commands"
|
||||
.SH NAME
|
||||
.PP
|
||||
sshpk\-sign \- sign data using an SSH key
|
||||
.SH SYNOPSYS
|
||||
.PP
|
||||
\fB\fCsshpk\-sign\fR \-i KEYPATH [OPTION...]
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Takes in arbitrary bytes, and signs them using an SSH private key. The key can
|
||||
be of any type or format supported by the \fB\fCsshpk\fR library, including the
|
||||
standard OpenSSH formats, as well as PEM PKCS#1 and PKCS#8.
|
||||
.PP
|
||||
The signature is printed out in Base64 encoding, unless the \fB\fC\-\-binary\fR or \fB\fC\-b\fR
|
||||
option is given.
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
Signing with default settings:
|
||||
.PP
|
||||
.RS
|
||||
.nf
|
||||
$ printf 'foo' | sshpk\-sign \-i ~/.ssh/id_ecdsa
|
||||
MEUCIAMdLS/vXrrtWFepwe...
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
Signing in SSH (RFC 4253) format (rather than the default ASN.1):
|
||||
.PP
|
||||
.RS
|
||||
.nf
|
||||
$ printf 'foo' | sshpk\-sign \-i ~/.ssh/id_ecdsa \-t ssh
|
||||
AAAAFGVjZHNhLXNoYTIt...
|
||||
.fi
|
||||
.RE
|
||||
.PP
|
||||
Saving the binary signature to a file:
|
||||
.PP
|
||||
.RS
|
||||
.nf
|
||||
$ printf 'foo' | sshpk\-sign \-i ~/.ssh/id_ecdsa \\
|
||||
\-o signature.bin \-b
|
||||
$ cat signature.bin | base64
|
||||
MEUCIAMdLS/vXrrtWFepwe...
|
||||
.fi
|
||||
.RE
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\fC\-v, \-\-verbose\fR
|
||||
Print extra information about the key and signature to stderr when signing.
|
||||
.TP
|
||||
\fB\fC\-b, \-\-binary\fR
|
||||
Don't base64\-encode the signature before outputting it.
|
||||
.TP
|
||||
\fB\fC\-i KEY, \-\-identity=KEY\fR
|
||||
Select the key to be used for signing. \fB\fCKEY\fR must be a relative or absolute
|
||||
filesystem path to the key file. Any format supported by the \fB\fCsshpk\fR library
|
||||
is supported, including OpenSSH formats and standard PEM PKCS.
|
||||
.TP
|
||||
\fB\fC\-f PATH, \-\-file=PATH\fR
|
||||
Input file to sign instead of stdin.
|
||||
.TP
|
||||
\fB\fC\-o PATH, \-\-out=PATH\fR
|
||||
Output file to save signature in instead of stdout.
|
||||
.TP
|
||||
\fB\fC\-H HASH, \-\-hash=HASH\fR
|
||||
Set the hash algorithm to be used for signing. This should be one of \fB\fCsha1\fR,
|
||||
\fB\fCsha256\fR or \fB\fCsha512\fR\&. Some key types may place restrictions on which hash
|
||||
algorithms may be used (e.g. ED25519 keys can only use SHA\-512).
|
||||
.TP
|
||||
\fB\fC\-t FORMAT, \-\-format=FORMAT\fR
|
||||
Choose the signature format to use, from \fB\fCasn1\fR, \fB\fCssh\fR or \fB\fCraw\fR (only for
|
||||
ED25519 signatures). The \fB\fCasn1\fR format is the default, as it is the format
|
||||
used with TLS and typically the standard in most non\-SSH libraries (e.g.
|
||||
OpenSSL). The \fB\fCssh\fR format is used in the SSH protocol and by the ssh\-agent.
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
.BR sshpk-verify (1)
|
||||
.SH BUGS
|
||||
.PP
|
||||
Report bugs at Github
|
||||
\[la]https://github.com/arekinath/node-sshpk/issues\[ra]
|
68
node_modules/sshpk/man/man1/sshpk-verify.1
generated
vendored
Normal file
68
node_modules/sshpk/man/man1/sshpk-verify.1
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
.TH sshpk\-verify 1 "Jan 2016" sshpk "sshpk Commands"
|
||||
.SH NAME
|
||||
.PP
|
||||
sshpk\-verify \- verify a signature on data using an SSH key
|
||||
.SH SYNOPSYS
|
||||
.PP
|
||||
\fB\fCsshpk\-verify\fR \-i KEYPATH \-s SIGNATURE [OPTION...]
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Takes in arbitrary bytes and a Base64\-encoded signature, and verifies that the
|
||||
signature was produced by the private half of the given SSH public key.
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
.RS
|
||||
.nf
|
||||
$ printf 'foo' | sshpk\-verify \-i ~/.ssh/id_ecdsa \-s MEUCIQCYp...
|
||||
OK
|
||||
$ printf 'foo' | sshpk\-verify \-i ~/.ssh/id_ecdsa \-s GARBAGE...
|
||||
NOT OK
|
||||
.fi
|
||||
.RE
|
||||
.SH EXIT STATUS
|
||||
.TP
|
||||
\fB\fC0\fR
|
||||
Signature validates and matches the key.
|
||||
.TP
|
||||
\fB\fC1\fR
|
||||
Signature is parseable and the correct length but does not match the key or
|
||||
otherwise is invalid.
|
||||
.TP
|
||||
\fB\fC2\fR
|
||||
The signature or key could not be parsed.
|
||||
.TP
|
||||
\fB\fC3\fR
|
||||
Invalid commandline options were supplied.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\fC\-v, \-\-verbose\fR
|
||||
Print extra information about the key and signature to stderr when verifying.
|
||||
.TP
|
||||
\fB\fC\-i KEY, \-\-identity=KEY\fR
|
||||
Select the key to be used for verification. \fB\fCKEY\fR must be a relative or
|
||||
absolute filesystem path to the key file. Any format supported by the \fB\fCsshpk\fR
|
||||
library is supported, including OpenSSH formats and standard PEM PKCS.
|
||||
.TP
|
||||
\fB\fC\-s BASE64, \-\-signature=BASE64\fR
|
||||
Supplies the base64\-encoded signature to be verified.
|
||||
.TP
|
||||
\fB\fC\-f PATH, \-\-file=PATH\fR
|
||||
Input file to verify instead of stdin.
|
||||
.TP
|
||||
\fB\fC\-H HASH, \-\-hash=HASH\fR
|
||||
Set the hash algorithm to be used for signing. This should be one of \fB\fCsha1\fR,
|
||||
\fB\fCsha256\fR or \fB\fCsha512\fR\&. Some key types may place restrictions on which hash
|
||||
algorithms may be used (e.g. ED25519 keys can only use SHA\-512).
|
||||
.TP
|
||||
\fB\fC\-t FORMAT, \-\-format=FORMAT\fR
|
||||
Choose the signature format to use, from \fB\fCasn1\fR, \fB\fCssh\fR or \fB\fCraw\fR (only for
|
||||
ED25519 signatures). The \fB\fCasn1\fR format is the default, as it is the format
|
||||
used with TLS and typically the standard in most non\-SSH libraries (e.g.
|
||||
OpenSSL). The \fB\fCssh\fR format is used in the SSH protocol and by the ssh\-agent.
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
.BR sshpk-sign (1)
|
||||
.SH BUGS
|
||||
.PP
|
||||
Report bugs at Github
|
||||
\[la]https://github.com/arekinath/node-sshpk/issues\[ra]
|
6
node_modules/sshpk/node_modules/assert-plus/AUTHORS
generated
vendored
Normal file
6
node_modules/sshpk/node_modules/assert-plus/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
Dave Eddy <dave@daveeddy.com>
|
||||
Fred Kuo <fred.kuo@joyent.com>
|
||||
Lars-Magnus Skog <ralphtheninja@riseup.net>
|
||||
Mark Cavage <mcavage@gmail.com>
|
||||
Patrick Mooney <pmooney@pfmooney.com>
|
||||
Rob Gulewich <robert.gulewich@joyent.com>
|
14
node_modules/sshpk/node_modules/assert-plus/CHANGES.md
generated
vendored
Normal file
14
node_modules/sshpk/node_modules/assert-plus/CHANGES.md
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
# assert-plus Changelog
|
||||
|
||||
## 1.0.0
|
||||
|
||||
- *BREAKING* assert.number (and derivatives) now accept Infinity as valid input
|
||||
- Add assert.finite check. Previous assert.number callers should use this if
|
||||
they expect Infinity inputs to throw.
|
||||
|
||||
## 0.2.0
|
||||
|
||||
- Fix `assert.object(null)` so it throws
|
||||
- Fix optional/arrayOf exports for non-type-of asserts
|
||||
- Add optiona/arrayOf exports for Stream/Date/Regex/uuid
|
||||
- Add basic unit test coverage
|
162
node_modules/sshpk/node_modules/assert-plus/README.md
generated
vendored
Normal file
162
node_modules/sshpk/node_modules/assert-plus/README.md
generated
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
# assert-plus
|
||||
|
||||
This library is a super small wrapper over node's assert module that has two
|
||||
things: (1) the ability to disable assertions with the environment variable
|
||||
NODE\_NDEBUG, and (2) some API wrappers for argument testing. Like
|
||||
`assert.string(myArg, 'myArg')`. As a simple example, most of my code looks
|
||||
like this:
|
||||
|
||||
```javascript
|
||||
var assert = require('assert-plus');
|
||||
|
||||
function fooAccount(options, callback) {
|
||||
assert.object(options, 'options');
|
||||
assert.number(options.id, 'options.id');
|
||||
assert.bool(options.isManager, 'options.isManager');
|
||||
assert.string(options.name, 'options.name');
|
||||
assert.arrayOfString(options.email, 'options.email');
|
||||
assert.func(callback, 'callback');
|
||||
|
||||
// Do stuff
|
||||
callback(null, {});
|
||||
}
|
||||
```
|
||||
|
||||
# API
|
||||
|
||||
All methods that *aren't* part of node's core assert API are simply assumed to
|
||||
take an argument, and then a string 'name' that's not a message; `AssertionError`
|
||||
will be thrown if the assertion fails with a message like:
|
||||
|
||||
AssertionError: foo (string) is required
|
||||
at test (/home/mark/work/foo/foo.js:3:9)
|
||||
at Object.<anonymous> (/home/mark/work/foo/foo.js:15:1)
|
||||
at Module._compile (module.js:446:26)
|
||||
at Object..js (module.js:464:10)
|
||||
at Module.load (module.js:353:31)
|
||||
at Function._load (module.js:311:12)
|
||||
at Array.0 (module.js:484:10)
|
||||
at EventEmitter._tickCallback (node.js:190:38)
|
||||
|
||||
from:
|
||||
|
||||
```javascript
|
||||
function test(foo) {
|
||||
assert.string(foo, 'foo');
|
||||
}
|
||||
```
|
||||
|
||||
There you go. You can check that arrays are of a homogeneous type with `Arrayof$Type`:
|
||||
|
||||
```javascript
|
||||
function test(foo) {
|
||||
assert.arrayOfString(foo, 'foo');
|
||||
}
|
||||
```
|
||||
|
||||
You can assert IFF an argument is not `undefined` (i.e., an optional arg):
|
||||
|
||||
```javascript
|
||||
assert.optionalString(foo, 'foo');
|
||||
```
|
||||
|
||||
Lastly, you can opt-out of assertion checking altogether by setting the
|
||||
environment variable `NODE_NDEBUG=1`. This is pseudo-useful if you have
|
||||
lots of assertions, and don't want to pay `typeof ()` taxes to v8 in
|
||||
production. Be advised: The standard functions re-exported from `assert` are
|
||||
also disabled in assert-plus if NDEBUG is specified. Using them directly from
|
||||
the `assert` module avoids this behavior.
|
||||
|
||||
The complete list of APIs is:
|
||||
|
||||
* assert.array
|
||||
* assert.bool
|
||||
* assert.buffer
|
||||
* assert.func
|
||||
* assert.number
|
||||
* assert.finite
|
||||
* assert.object
|
||||
* assert.string
|
||||
* assert.stream
|
||||
* assert.date
|
||||
* assert.regexp
|
||||
* assert.uuid
|
||||
* assert.arrayOfArray
|
||||
* assert.arrayOfBool
|
||||
* assert.arrayOfBuffer
|
||||
* assert.arrayOfFunc
|
||||
* assert.arrayOfNumber
|
||||
* assert.arrayOfFinite
|
||||
* assert.arrayOfObject
|
||||
* assert.arrayOfString
|
||||
* assert.arrayOfStream
|
||||
* assert.arrayOfDate
|
||||
* assert.arrayOfRegexp
|
||||
* assert.arrayOfUuid
|
||||
* assert.optionalArray
|
||||
* assert.optionalBool
|
||||
* assert.optionalBuffer
|
||||
* assert.optionalFunc
|
||||
* assert.optionalNumber
|
||||
* assert.optionalFinite
|
||||
* assert.optionalObject
|
||||
* assert.optionalString
|
||||
* assert.optionalStream
|
||||
* assert.optionalDate
|
||||
* assert.optionalRegexp
|
||||
* assert.optionalUuid
|
||||
* assert.optionalArrayOfArray
|
||||
* assert.optionalArrayOfBool
|
||||
* assert.optionalArrayOfBuffer
|
||||
* assert.optionalArrayOfFunc
|
||||
* assert.optionalArrayOfNumber
|
||||
* assert.optionalArrayOfFinite
|
||||
* assert.optionalArrayOfObject
|
||||
* assert.optionalArrayOfString
|
||||
* assert.optionalArrayOfStream
|
||||
* assert.optionalArrayOfDate
|
||||
* assert.optionalArrayOfRegexp
|
||||
* assert.optionalArrayOfUuid
|
||||
* assert.AssertionError
|
||||
* assert.fail
|
||||
* assert.ok
|
||||
* assert.equal
|
||||
* assert.notEqual
|
||||
* assert.deepEqual
|
||||
* assert.notDeepEqual
|
||||
* assert.strictEqual
|
||||
* assert.notStrictEqual
|
||||
* assert.throws
|
||||
* assert.doesNotThrow
|
||||
* assert.ifError
|
||||
|
||||
# Installation
|
||||
|
||||
npm install assert-plus
|
||||
|
||||
## License
|
||||
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2012 Mark Cavage
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
## Bugs
|
||||
|
||||
See <https://github.com/mcavage/node-assert-plus/issues>.
|
211
node_modules/sshpk/node_modules/assert-plus/assert.js
generated
vendored
Normal file
211
node_modules/sshpk/node_modules/assert-plus/assert.js
generated
vendored
Normal file
@ -0,0 +1,211 @@
|
||||
// Copyright (c) 2012, Mark Cavage. All rights reserved.
|
||||
// Copyright 2015 Joyent, Inc.
|
||||
|
||||
var assert = require('assert');
|
||||
var Stream = require('stream').Stream;
|
||||
var util = require('util');
|
||||
|
||||
|
||||
///--- Globals
|
||||
|
||||
/* JSSTYLED */
|
||||
var UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/;
|
||||
|
||||
|
||||
///--- Internal
|
||||
|
||||
function _capitalize(str) {
|
||||
return (str.charAt(0).toUpperCase() + str.slice(1));
|
||||
}
|
||||
|
||||
function _toss(name, expected, oper, arg, actual) {
|
||||
throw new assert.AssertionError({
|
||||
message: util.format('%s (%s) is required', name, expected),
|
||||
actual: (actual === undefined) ? typeof (arg) : actual(arg),
|
||||
expected: expected,
|
||||
operator: oper || '===',
|
||||
stackStartFunction: _toss.caller
|
||||
});
|
||||
}
|
||||
|
||||
function _getClass(arg) {
|
||||
return (Object.prototype.toString.call(arg).slice(8, -1));
|
||||
}
|
||||
|
||||
function noop() {
|
||||
// Why even bother with asserts?
|
||||
}
|
||||
|
||||
|
||||
///--- Exports
|
||||
|
||||
var types = {
|
||||
bool: {
|
||||
check: function (arg) { return typeof (arg) === 'boolean'; }
|
||||
},
|
||||
func: {
|
||||
check: function (arg) { return typeof (arg) === 'function'; }
|
||||
},
|
||||
string: {
|
||||
check: function (arg) { return typeof (arg) === 'string'; }
|
||||
},
|
||||
object: {
|
||||
check: function (arg) {
|
||||
return typeof (arg) === 'object' && arg !== null;
|
||||
}
|
||||
},
|
||||
number: {
|
||||
check: function (arg) {
|
||||
return typeof (arg) === 'number' && !isNaN(arg);
|
||||
}
|
||||
},
|
||||
finite: {
|
||||
check: function (arg) {
|
||||
return typeof (arg) === 'number' && !isNaN(arg) && isFinite(arg);
|
||||
}
|
||||
},
|
||||
buffer: {
|
||||
check: function (arg) { return Buffer.isBuffer(arg); },
|
||||
operator: 'Buffer.isBuffer'
|
||||
},
|
||||
array: {
|
||||
check: function (arg) { return Array.isArray(arg); },
|
||||
operator: 'Array.isArray'
|
||||
},
|
||||
stream: {
|
||||
check: function (arg) { return arg instanceof Stream; },
|
||||
operator: 'instanceof',
|
||||
actual: _getClass
|
||||
},
|
||||
date: {
|
||||
check: function (arg) { return arg instanceof Date; },
|
||||
operator: 'instanceof',
|
||||
actual: _getClass
|
||||
},
|
||||
regexp: {
|
||||
check: function (arg) { return arg instanceof RegExp; },
|
||||
operator: 'instanceof',
|
||||
actual: _getClass
|
||||
},
|
||||
uuid: {
|
||||
check: function (arg) {
|
||||
return typeof (arg) === 'string' && UUID_REGEXP.test(arg);
|
||||
},
|
||||
operator: 'isUUID'
|
||||
}
|
||||
};
|
||||
|
||||
function _setExports(ndebug) {
|
||||
var keys = Object.keys(types);
|
||||
var out;
|
||||
|
||||
/* re-export standard assert */
|
||||
if (process.env.NODE_NDEBUG) {
|
||||
out = noop;
|
||||
} else {
|
||||
out = function (arg, msg) {
|
||||
if (!arg) {
|
||||
_toss(msg, 'true', arg);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* standard checks */
|
||||
keys.forEach(function (k) {
|
||||
if (ndebug) {
|
||||
out[k] = noop;
|
||||
return;
|
||||
}
|
||||
var type = types[k];
|
||||
out[k] = function (arg, msg) {
|
||||
if (!type.check(arg)) {
|
||||
_toss(msg, k, type.operator, arg, type.actual);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/* optional checks */
|
||||
keys.forEach(function (k) {
|
||||
var name = 'optional' + _capitalize(k);
|
||||
if (ndebug) {
|
||||
out[name] = noop;
|
||||
return;
|
||||
}
|
||||
var type = types[k];
|
||||
out[name] = function (arg, msg) {
|
||||
if (arg === undefined || arg === null) {
|
||||
return;
|
||||
}
|
||||
if (!type.check(arg)) {
|
||||
_toss(msg, k, type.operator, arg, type.actual);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/* arrayOf checks */
|
||||
keys.forEach(function (k) {
|
||||
var name = 'arrayOf' + _capitalize(k);
|
||||
if (ndebug) {
|
||||
out[name] = noop;
|
||||
return;
|
||||
}
|
||||
var type = types[k];
|
||||
var expected = '[' + k + ']';
|
||||
out[name] = function (arg, msg) {
|
||||
if (!Array.isArray(arg)) {
|
||||
_toss(msg, expected, type.operator, arg, type.actual);
|
||||
}
|
||||
var i;
|
||||
for (i = 0; i < arg.length; i++) {
|
||||
if (!type.check(arg[i])) {
|
||||
_toss(msg, expected, type.operator, arg, type.actual);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/* optionalArrayOf checks */
|
||||
keys.forEach(function (k) {
|
||||
var name = 'optionalArrayOf' + _capitalize(k);
|
||||
if (ndebug) {
|
||||
out[name] = noop;
|
||||
return;
|
||||
}
|
||||
var type = types[k];
|
||||
var expected = '[' + k + ']';
|
||||
out[name] = function (arg, msg) {
|
||||
if (arg === undefined || arg === null) {
|
||||
return;
|
||||
}
|
||||
if (!Array.isArray(arg)) {
|
||||
_toss(msg, expected, type.operator, arg, type.actual);
|
||||
}
|
||||
var i;
|
||||
for (i = 0; i < arg.length; i++) {
|
||||
if (!type.check(arg[i])) {
|
||||
_toss(msg, expected, type.operator, arg, type.actual);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/* re-export built-in assertions */
|
||||
Object.keys(assert).forEach(function (k) {
|
||||
if (k === 'AssertionError') {
|
||||
out[k] = assert[k];
|
||||
return;
|
||||
}
|
||||
if (ndebug) {
|
||||
out[k] = noop;
|
||||
return;
|
||||
}
|
||||
out[k] = assert[k];
|
||||
});
|
||||
|
||||
/* export ourselves (for unit tests _only_) */
|
||||
out._setExports = _setExports;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
module.exports = _setExports(process.env.NODE_NDEBUG);
|
106
node_modules/sshpk/node_modules/assert-plus/package.json
generated
vendored
Normal file
106
node_modules/sshpk/node_modules/assert-plus/package.json
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"assert-plus@^1.0.0",
|
||||
"C:\\Users\\x2mjbyrn\\Source\\Repos\\Skeleton\\node_modules\\sshpk"
|
||||
]
|
||||
],
|
||||
"_from": "assert-plus@>=1.0.0-0 <2.0.0-0",
|
||||
"_id": "assert-plus@1.0.0",
|
||||
"_inCache": true,
|
||||
"_location": "/sshpk/assert-plus",
|
||||
"_nodeVersion": "0.10.40",
|
||||
"_npmUser": {
|
||||
"email": "patrick.f.mooney@gmail.com",
|
||||
"name": "pfmooney"
|
||||
},
|
||||
"_npmVersion": "3.3.9",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"name": "assert-plus",
|
||||
"raw": "assert-plus@^1.0.0",
|
||||
"rawSpec": "^1.0.0",
|
||||
"scope": null,
|
||||
"spec": ">=1.0.0-0 <2.0.0-0",
|
||||
"type": "range"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/sshpk"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"_shasum": "f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525",
|
||||
"_shrinkwrap": null,
|
||||
"_spec": "assert-plus@^1.0.0",
|
||||
"_where": "C:\\Users\\x2mjbyrn\\Source\\Repos\\Skeleton\\node_modules\\sshpk",
|
||||
"author": {
|
||||
"email": "mcavage@gmail.com",
|
||||
"name": "Mark Cavage"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/mcavage/node-assert-plus/issues"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Dave Eddy",
|
||||
"email": "dave@daveeddy.com"
|
||||
},
|
||||
{
|
||||
"name": "Fred Kuo",
|
||||
"email": "fred.kuo@joyent.com"
|
||||
},
|
||||
{
|
||||
"name": "Lars-Magnus Skog",
|
||||
"email": "ralphtheninja@riseup.net"
|
||||
},
|
||||
{
|
||||
"name": "Mark Cavage",
|
||||
"email": "mcavage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Patrick Mooney",
|
||||
"email": "pmooney@pfmooney.com"
|
||||
},
|
||||
{
|
||||
"name": "Rob Gulewich",
|
||||
"email": "robert.gulewich@joyent.com"
|
||||
}
|
||||
],
|
||||
"dependencies": {},
|
||||
"description": "Extra assertions on top of node's assert module",
|
||||
"devDependencies": {
|
||||
"faucet": "0.0.1",
|
||||
"tape": "4.2.2"
|
||||
},
|
||||
"directories": {},
|
||||
"dist": {
|
||||
"shasum": "f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525",
|
||||
"tarball": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
},
|
||||
"homepage": "https://github.com/mcavage/node-assert-plus#readme",
|
||||
"installable": true,
|
||||
"license": "MIT",
|
||||
"main": "./assert.js",
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "mcavage",
|
||||
"email": "mcavage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "pfmooney",
|
||||
"email": "patrick.f.mooney@gmail.com"
|
||||
}
|
||||
],
|
||||
"name": "assert-plus",
|
||||
"optionalDependencies": {},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/mcavage/node-assert-plus.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "tape tests/*.js | ./node_modules/.bin/faucet"
|
||||
},
|
||||
"version": "1.0.0"
|
||||
}
|
126
node_modules/sshpk/package.json
generated
vendored
Normal file
126
node_modules/sshpk/package.json
generated
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"sshpk@^1.7.0",
|
||||
"C:\\Users\\x2mjbyrn\\Source\\Repos\\Skeleton\\node_modules\\http-signature"
|
||||
]
|
||||
],
|
||||
"_from": "sshpk@>=1.7.0-0 <2.0.0-0",
|
||||
"_id": "sshpk@1.13.0",
|
||||
"_inCache": true,
|
||||
"_location": "/sshpk",
|
||||
"_nodeVersion": "0.12.15",
|
||||
"_npmOperationalInternal": {
|
||||
"host": "packages-12-west.internal.npmjs.com",
|
||||
"tmp": "tmp/sshpk-1.13.0.tgz_1492046338097_0.9430976777803153"
|
||||
},
|
||||
"_npmUser": {
|
||||
"email": "alex@cooperi.net",
|
||||
"name": "arekinath"
|
||||
},
|
||||
"_npmVersion": "3.10.10",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"name": "sshpk",
|
||||
"raw": "sshpk@^1.7.0",
|
||||
"rawSpec": "^1.7.0",
|
||||
"scope": null,
|
||||
"spec": ">=1.7.0-0 <2.0.0-0",
|
||||
"type": "range"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/http-signature"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.0.tgz",
|
||||
"_shasum": "ff2a3e4fd04497555fed97b39a0fd82fafb3a33c",
|
||||
"_shrinkwrap": null,
|
||||
"_spec": "sshpk@^1.7.0",
|
||||
"_where": "C:\\Users\\x2mjbyrn\\Source\\Repos\\Skeleton\\node_modules\\http-signature",
|
||||
"author": {
|
||||
"name": "Joyent, Inc"
|
||||
},
|
||||
"bin": {
|
||||
"sshpk-conv": "bin/sshpk-conv",
|
||||
"sshpk-sign": "bin/sshpk-sign",
|
||||
"sshpk-verify": "bin/sshpk-verify"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/arekinath/node-sshpk/issues"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Dave Eddy",
|
||||
"email": "dave@daveeddy.com"
|
||||
},
|
||||
{
|
||||
"name": "Mark Cavage",
|
||||
"email": "mcavage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Alex Wilson",
|
||||
"email": "alex@cooperi.net"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"asn1": "~0.2.3",
|
||||
"assert-plus": "^1.0.0",
|
||||
"bcrypt-pbkdf": "^1.0.0",
|
||||
"dashdash": "^1.12.0",
|
||||
"ecc-jsbn": "~0.1.1",
|
||||
"getpass": "^0.1.1",
|
||||
"jodid25519": "^1.0.0",
|
||||
"jsbn": "~0.1.0",
|
||||
"tweetnacl": "~0.14.0"
|
||||
},
|
||||
"description": "A library for finding and using SSH public keys",
|
||||
"devDependencies": {
|
||||
"benchmark": "^1.0.0",
|
||||
"sinon": "^1.17.2",
|
||||
"tape": "^3.5.0",
|
||||
"temp": "^0.8.2"
|
||||
},
|
||||
"directories": {
|
||||
"bin": "./bin",
|
||||
"lib": "./lib",
|
||||
"man": "./man/man1"
|
||||
},
|
||||
"dist": {
|
||||
"shasum": "ff2a3e4fd04497555fed97b39a0fd82fafb3a33c",
|
||||
"tarball": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.0.tgz"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"gitHead": "61aa61683a0c8211641423843018aae1b3691bb7",
|
||||
"homepage": "https://github.com/arekinath/node-sshpk#readme",
|
||||
"installable": true,
|
||||
"license": "MIT",
|
||||
"main": "lib/index.js",
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "arekinath",
|
||||
"email": "alex@cooperi.net"
|
||||
}
|
||||
],
|
||||
"man": [
|
||||
"/Users/alex.wilson/dev/sshpk/man/man1/sshpk-conv.1",
|
||||
"/Users/alex.wilson/dev/sshpk/man/man1/sshpk-sign.1",
|
||||
"/Users/alex.wilson/dev/sshpk/man/man1/sshpk-verify.1"
|
||||
],
|
||||
"name": "sshpk",
|
||||
"optionalDependencies": {
|
||||
"bcrypt-pbkdf": "^1.0.0",
|
||||
"ecc-jsbn": "~0.1.1",
|
||||
"jodid25519": "^1.0.0",
|
||||
"jsbn": "~0.1.0",
|
||||
"tweetnacl": "~0.14.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/arekinath/node-sshpk.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "tape test/*.js"
|
||||
},
|
||||
"version": "1.13.0"
|
||||
}
|
Reference in New Issue
Block a user