node-sshpk-1.16.1/000077500000000000000000000000001342215657600136665ustar00rootroot00000000000000node-sshpk-1.16.1/.gitignore000066400000000000000000000000151342215657600156520ustar00rootroot00000000000000node_modules node-sshpk-1.16.1/.gitmodules000066400000000000000000000003211342215657600160370ustar00rootroot00000000000000[submodule "deps/javascriptlint"] path = deps/javascriptlint url = https://github.com/davepacheco/javascriptlint [submodule "deps/jsstyle"] path = deps/jsstyle url = https://github.com/davepacheco/jsstyle node-sshpk-1.16.1/.npmignore000066400000000000000000000001101342215657600156550ustar00rootroot00000000000000.gitmodules deps docs Makefile node_modules test tools coverage man/src node-sshpk-1.16.1/.travis.yml000066400000000000000000000002751342215657600160030ustar00rootroot00000000000000language: 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' node-sshpk-1.16.1/LICENSE000066400000000000000000000020531342215657600146730ustar00rootroot00000000000000Copyright 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. node-sshpk-1.16.1/Makefile000066400000000000000000000035721342215657600153350ustar00rootroot00000000000000# # Copyright (c) 2012, Joyent, Inc. All rights reserved. # # Makefile: basic Makefile for template API service # # This Makefile is a template for new repos. It contains only repo-specific # logic and uses included makefiles to supply common targets (javascriptlint, # jsstyle, restdown, etc.), which are used by other repos as well. You may well # need to rewrite most of this file, but you shouldn't need to touch the # included makefiles. # # If you find yourself adding support for new targets that could be useful for # other projects too, you should add these to the original versions of the # included Makefiles (in eng.git) so that other teams can use them too. # # # Tools # # Get md2man-roff from MD2MAN := md2man-roff NPM_EXEC := npm TAP := ./node_modules/.bin/tape # # Files # JS_FILES := $(shell find lib -name '*.js') JSL_CONF_NODE = tools/jsl.node.conf JSL_FILES_NODE = $(JS_FILES) JSSTYLE_FILES = $(JS_FILES) JSSTYLE_FLAGS = -f tools/jsstyle.conf MAN_PAGES := $(shell ls man/src) MAN_OUTDIR := man/man1 MAN_OUTPAGES=$(MAN_PAGES:%.md=$(MAN_OUTDIR)/%.1) MAN_ROOT := man/src include ./tools/mk/Makefile.defs include ./tools/mk/Makefile.node_deps.defs # # Repo-specific targets # .PHONY: all all: $(REPO_DEPS) $(NPM_EXEC) install CLEAN_FILES += $(TAP) ./node_modules/tap .PHONY: test test: all TAP=1 $(TAP) test/*.js .PHONY: coverage coverage: all $(NPM_EXEC) install istanbul && \ ./node_modules/.bin/istanbul cover \ $(TAP) test/*.js .PHONY: codecovio codecovio: coverage $(NPM_EXEC) install codecov.io && \ ./node_modules/.bin/codecov < coverage/lcov.info $(MAN_OUTDIR): mkdir -p $@ $(MAN_OUTDIR)/%.1: $(MAN_ROOT)/%.md | $(MAN_OUTDIR) $(MD2MAN) $^ > $@ .PHONY: manpages manpages: $(MAN_OUTPAGES) include ./tools/mk/Makefile.deps include ./tools/mk/Makefile.node_deps.targ include ./tools/mk/Makefile.targ node-sshpk-1.16.1/README.md000066400000000000000000000601031342215657600151450ustar00rootroot00000000000000sshpk ========= 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` - `dnssec`: `.key` file format output by `dnssec-keygen` etc - `putty`: the PuTTY `.ppk` file format (supports truncated variant without all the lines from `Private-Lines:` onwards) - `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'[, hashType = 'ssh']])` 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` - `hashType` -- String name of fingerprint hash type to use, valid options are `ssh` (the type of fingerprint used by OpenSSH, e.g. in `ssh-keygen`), `spki` (used by HPKP, some OpenSSL applications) ### `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 - `dnssec`: `.private` format output by `dnssec-keygen` etc. - `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[, options])` 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 - `options` -- Optional Object, with properties: - `algorithms` -- Array of strings, names of hash algorithms to limit support to. If `fingerprint` uses a hash algorithm not on this list, throws `InvalidAlgorithmError`. - `hashType` -- String, the type of hash the fingerprint uses, either `ssh` or `spki` (normally auto-detected based on the format, but can be overridden) - `type` -- String, the entity this fingerprint identifies, either `key` or `certificate` ### `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(keyOrCertificate)` Verifies whether or not this `Fingerprint` matches a given `Key` or `Certificate`. This function uses double-hashing to avoid leaking timing information. Returns a boolean. Note that a `Key`-type Fingerprint will always return `false` if asked to match a `Certificate` and vice versa. Parameters - `keyOrCertificate` -- a `Key` object or `Certificate` object, the entity 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#getExtension(nameOrOid)` Retrieves information about a certificate extension, if present, or returns `undefined` if not. The string argument `nameOrOid` should be either the OID (for X509 extensions) or the name (for OpenSSH extensions) of the extension to retrieve. The object returned will have the following properties: * `format` -- String, set to either `'x509'` or `'openssh'` * `name` or `oid` -- String, only one set based on value of `format` * `data` -- Buffer, the raw data inside the extension ### `Certificate#getExtensions()` Returns an Array of all present certificate extensions, in the same manner and format as `getExtension()`. ### `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. ### `identityFromArray(arr)` Constructs an Identity from an array of DN components (see `Identity#toArray()` for the format). Parameters - `arr` -- an Array of Objects, DN components with `name` and `value` Returns an Identity instance. Supported attributes in DNs: | Attribute name | OID | | -------------- | --- | | `cn` | `2.5.4.3` | | `o` | `2.5.4.10` | | `ou` | `2.5.4.11` | | `l` | `2.5.4.7` | | `s` | `2.5.4.8` | | `c` | `2.5.4.6` | | `sn` | `2.5.4.4` | | `postalCode` | `2.5.4.17` | | `serialNumber` | `2.5.4.5` | | `street` | `2.5.4.9` | | `x500UniqueIdentifier` | `2.5.4.45` | | `role` | `2.5.4.72` | | `telephoneNumber` | `2.5.4.20` | | `description` | `2.5.4.13` | | `dc` | `0.9.2342.19200300.100.1.25` | | `uid` | `0.9.2342.19200300.100.1.1` | | `mail` | `0.9.2342.19200300.100.1.3` | | `title` | `2.5.4.12` | | `gn` | `2.5.4.42` | | `initials` | `2.5.4.43` | | `pseudonym` | `2.5.4.65` | ### `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. It's probably better to use the `#get()` method instead of this property. ### `Identity#get(name[, asArray])` Returns the value of a named attribute in the Identity DN. If there is no attribute of the given name, returns `undefined`. If multiple components of the DN contain an attribute of this name, an exception is thrown unless the `asArray` argument is given as `true` -- then they will be returned as an Array in the same order they appear in the DN. Parameters - `name` -- a String - `asArray` -- an optional Boolean ### `Identity#toArray()` Returns the Identity as an Array of DN component objects. This looks like: ```js [ { "name": "cn", "value": "Joe Bloggs" }, { "name": "o", "value": "Organisation Ltd" } ] ``` Each object has a `name` and a `value` property. The returned objects may be safely modified. 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` node-sshpk-1.16.1/bin/000077500000000000000000000000001342215657600144365ustar00rootroot00000000000000node-sshpk-1.16.1/bin/sshpk-conv000077500000000000000000000131521342215657600164610ustar00rootroot00000000000000#!/usr/bin/env node // -*- mode: js -*- // vim: set filetype=javascript : // Copyright 2018 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: ['fingerprint', 'F'], type: 'bool', help: 'Output key fingerprint' }, { names: ['hash', 'H'], type: 'string', help: 'Hash function to use for key fingeprint with -F' }, { names: ['spki', 's'], type: 'bool', help: 'With -F, generates an SPKI fingerprint instead of SSH' }, { 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 key 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'); console.error(' - dnssec dnssec-keygen format'); console.error(' - putty PuTTY ppk format'); console.error('\navailable fingerprint formats:'); console.error(' - hex colon-separated hex for SSH'); console.error(' straight hex for SPKI'); console.error(' - base64 SHA256:* format from OpenSSH'); 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) { ifError(e, 'error opening input file'); } 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) { ifError(e, 'error opening output file'); } 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) ifError(err); parseOpts.passphrase = pw; processKey(); }); return; } ifError(e); } if (opts.derive) key = key.derive(opts.derive); if (opts.comment) key.comment = opts.comment; if (opts.identify) { 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('SHA256 fingerprint: ' + key.fingerprint('sha256').toString()); console.log('MD5 fingerprint: ' + key.fingerprint('md5').toString()); console.log('SPKI-SHA256 fingerprint: ' + key.fingerprint('sha256', 'spki').toString()); process.exit(0); return; } if (opts.fingerprint) { var hash = opts.hash; var type = opts.spki ? 'spki' : 'ssh'; var format = opts.outformat; var fp = key.fingerprint(hash, type).toString(format); outFile.write(fp); outFile.write('\n'); outFile.once('drain', function () { process.exit(0); }); return; } 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); }); }); } function ifError(e, txt) { if (txt) txt = txt + ': '; else txt = ''; console.error('sshpk-conv: ' + txt + e.name + ': ' + e.message); if (process.env['DEBUG'] || process.env['V']) { console.error(e.stack); if (e.innerErr) console.error(e.innerErr.stack); } process.exit(1); } node-sshpk-1.16.1/bin/sshpk-sign000077500000000000000000000076531342215657600164650ustar00rootroot00000000000000#!/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); }); }); } node-sshpk-1.16.1/bin/sshpk-verify000077500000000000000000000067411342215657600170260ustar00rootroot00000000000000#!/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 Buffer = require('safer-buffer').Buffer; 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 = Buffer.from(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); }); } node-sshpk-1.16.1/deps/000077500000000000000000000000001342215657600146215ustar00rootroot00000000000000node-sshpk-1.16.1/deps/javascriptlint/000077500000000000000000000000001342215657600176565ustar00rootroot00000000000000node-sshpk-1.16.1/deps/jsstyle/000077500000000000000000000000001342215657600163165ustar00rootroot00000000000000node-sshpk-1.16.1/lib/000077500000000000000000000000001342215657600144345ustar00rootroot00000000000000node-sshpk-1.16.1/lib/algs.js000066400000000000000000000114021342215657600157160ustar00rootroot00000000000000// Copyright 2015 Joyent, Inc. var Buffer = require('safer-buffer').Buffer; var algInfo = { 'dsa': { parts: ['p', 'q', 'g', 'y'], sizePart: 'p' }, 'rsa': { parts: ['e', 'n'], sizePart: 'n' }, 'ecdsa': { parts: ['curve', 'Q'], sizePart: 'Q' }, 'ed25519': { parts: ['A'], sizePart: 'A' } }; 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: ['A', 'k'] } }; 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: Buffer.from(('00' + 'ffffffff 00000001 00000000 00000000' + '00000000 ffffffff ffffffff ffffffff'). replace(/ /g, ''), 'hex'), a: Buffer.from(('00' + 'FFFFFFFF 00000001 00000000 00000000' + '00000000 FFFFFFFF FFFFFFFF FFFFFFFC'). replace(/ /g, ''), 'hex'), b: Buffer.from(( '5ac635d8 aa3a93e7 b3ebbd55 769886bc' + '651d06b0 cc53b0f6 3bce3c3e 27d2604b'). replace(/ /g, ''), 'hex'), s: Buffer.from(('00' + 'c49d3608 86e70493 6a6678e1 139d26b7' + '819f7e90'). replace(/ /g, ''), 'hex'), n: Buffer.from(('00' + 'ffffffff 00000000 ffffffff ffffffff' + 'bce6faad a7179e84 f3b9cac2 fc632551'). replace(/ /g, ''), 'hex'), G: Buffer.from(('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: Buffer.from(('00' + 'ffffffff ffffffff ffffffff ffffffff' + 'ffffffff ffffffff ffffffff fffffffe' + 'ffffffff 00000000 00000000 ffffffff'). replace(/ /g, ''), 'hex'), a: Buffer.from(('00' + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE' + 'FFFFFFFF 00000000 00000000 FFFFFFFC'). replace(/ /g, ''), 'hex'), b: Buffer.from(( 'b3312fa7 e23ee7e4 988e056b e3f82d19' + '181d9c6e fe814112 0314088f 5013875a' + 'c656398d 8a2ed19d 2a85c8ed d3ec2aef'). replace(/ /g, ''), 'hex'), s: Buffer.from(('00' + 'a335926a a319a27a 1d00896a 6773a482' + '7acdac73'). replace(/ /g, ''), 'hex'), n: Buffer.from(('00' + 'ffffffff ffffffff ffffffff ffffffff' + 'ffffffff ffffffff c7634d81 f4372ddf' + '581a0db2 48b0a77a ecec196a ccc52973'). replace(/ /g, ''), 'hex'), G: Buffer.from(('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: Buffer.from(( '01ffffff ffffffff ffffffff ffffffff' + 'ffffffff ffffffff ffffffff ffffffff' + 'ffffffff ffffffff ffffffff ffffffff' + 'ffffffff ffffffff ffffffff ffffffff' + 'ffff').replace(/ /g, ''), 'hex'), a: Buffer.from(('01FF' + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' + 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFC'). replace(/ /g, ''), 'hex'), b: Buffer.from(('51' + '953eb961 8e1c9a1f 929a21a0 b68540ee' + 'a2da725b 99b315f3 b8b48991 8ef109e1' + '56193951 ec7e937b 1652c0bd 3bb1bf07' + '3573df88 3d2c34f1 ef451fd4 6b503f00'). replace(/ /g, ''), 'hex'), s: Buffer.from(('00' + 'd09e8800 291cb853 96cc6717 393284aa' + 'a0da64ba').replace(/ /g, ''), 'hex'), n: Buffer.from(('01ff' + 'ffffffff ffffffff ffffffff ffffffff' + 'ffffffff ffffffff ffffffff fffffffa' + '51868783 bf2f966b 7fcc0148 f709a5d0' + '3bb5c9b8 899c47ae bb6fb71e 91386409'). replace(/ /g, ''), 'hex'), G: Buffer.from(('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 }; node-sshpk-1.16.1/lib/certificate.js000066400000000000000000000265201342215657600172610ustar00rootroot00000000000000// Copyright 2016 Joyent, Inc. module.exports = Certificate; var assert = require('assert-plus'); var Buffer = require('safer-buffer').Buffer; 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.getExtension = function (keyOrOid) { assert.string(keyOrOid, 'keyOrOid'); var ext = this.getExtensions().filter(function (maybeExt) { if (maybeExt.format === 'x509') return (maybeExt.oid === keyOrOid); if (maybeExt.format === 'openssh') return (maybeExt.name === keyOrOid); return (false); })[0]; return (ext); }; Certificate.prototype.getExtensions = function () { var exts = []; var x509 = this.signatures.x509; if (x509 && x509.extras && x509.extras.exts) { x509.extras.exts.forEach(function (ext) { ext.format = 'x509'; exts.push(ext); }); } var openssh = this.signatures.openssh; if (openssh && openssh.exts) { openssh.exts.forEach(function (ext) { ext.format = 'openssh'; exts.push(ext); }); } return (exts); }; 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 = Buffer.from('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 = Buffer.from('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 * [1,1] -- openssh format now unpacks extensions */ Certificate.prototype._sshpkApiVersion = [1, 1]; Certificate._oldVersionDetect = function (obj) { return ([1, 0]); }; node-sshpk-1.16.1/lib/dhe.js000066400000000000000000000245501342215657600155400ustar00rootroot00000000000000// Copyright 2017 Joyent, Inc. module.exports = { DiffieHellman: DiffieHellman, generateECDSA: generateECDSA, generateED25519: generateED25519 }; var assert = require('assert-plus'); var crypto = require('crypto'); var Buffer = require('safer-buffer').Buffer; var algs = require('./algs'); var utils = require('./utils'); var nacl = require('tweetnacl'); var Key = require('./key'); var PrivateKey = require('./private-key'); var CRYPTO_HAVE_ECDH = (crypto.createECDH !== undefined); var ecdh = require('ecc-jsbn'); var ec = require('ecc-jsbn/lib/ec'); var jsbn = require('jsbn').BigInteger; 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) { 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 (this._isPriv) { utils.assertCompatible(key, PrivateKey, [1, 5], 'key'); this._priv = key.part.k.data; } } 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') { var k = pk.part.k; if (!pk.part.k) k = pk.part.r; this._priv = k.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.A.data; while (pub[0] === 0x00 && pub.length > 32) pub = pub.slice(1); var priv = this._priv; assert.strictEqual(pub.length, 32); assert.strictEqual(priv.length, 32); var secret = nacl.box.before(new Uint8Array(pub), new Uint8Array(priv)); return (Buffer.from(secret)); } 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: Buffer.from(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 = Buffer.from(priv.toByteArray()); pub = Buffer.from(this._ecParams.getCurve(). encodePointHex(pub), 'hex'); this._priv = new ECPrivate(this._ecParams, priv); parts.push({name: 'curve', data: Buffer.from(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') { var pair = nacl.box.keyPair(); priv = Buffer.from(pair.secretKey); pub = Buffer.from(pair.publicKey); priv = Buffer.concat([priv, pub]); assert.strictEqual(priv.length, 64); assert.strictEqual(pub.length, 32); parts.push({name: 'A', data: pub}); parts.push({name: 'k', data: priv}); 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 (Buffer.from(S.getX().toBigInteger().toByteArray())); }; function generateED25519() { var pair = nacl.sign.keyPair(); var priv = Buffer.from(pair.secretKey); var pub = Buffer.from(pair.publicKey); assert.strictEqual(priv.length, 64); assert.strictEqual(pub.length, 32); var parts = []; parts.push({name: 'A', data: pub}); parts.push({name: 'k', data: priv.slice(0, 32)}); 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: Buffer.from(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 { 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 = Buffer.from(priv.toByteArray()); pub = Buffer.from(ecParams.getCurve(). encodePointHex(pub), 'hex'); parts.push({name: 'curve', data: Buffer.from(curve)}); parts.push({name: 'Q', data: pub}); parts.push({name: 'd', data: priv}); key = new PrivateKey({ type: 'ecdsa', curve: curve, parts: parts }); return (key); } } node-sshpk-1.16.1/lib/ed-compat.js000066400000000000000000000044371342215657600166530ustar00rootroot00000000000000// Copyright 2015 Joyent, Inc. module.exports = { Verifier: Verifier, Signer: Signer }; var nacl = require('tweetnacl'); var stream = require('stream'); var util = require('util'); var assert = require('assert-plus'); var Buffer = require('safer-buffer').Buffer; var Signature = require('./signature'); function Verifier(key, hashAlgo) { 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 = Buffer.from(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 = Buffer.from(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.A.data))); }; function Signer(key, hashAlgo) { 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 = Buffer.from(chunk, 'binary'); this.chunks.push(chunk); }; Signer.prototype.sign = function () { var sig = nacl.sign.detached( new Uint8Array(Buffer.concat(this.chunks)), new Uint8Array(Buffer.concat([ this.key.part.k.data, this.key.part.A.data]))); var sigBuf = Buffer.from(sig); var sigObj = Signature.parse(sigBuf, 'ed25519', 'raw'); sigObj.hashAlgorithm = 'sha512'; return (sigObj); }; node-sshpk-1.16.1/lib/errors.js000066400000000000000000000053221342215657600163100ustar00rootroot00000000000000// 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 }; node-sshpk-1.16.1/lib/fingerprint.js000066400000000000000000000126321342215657600173250ustar00rootroot00000000000000// Copyright 2018 Joyent, Inc. module.exports = Fingerprint; var assert = require('assert-plus'); var Buffer = require('safer-buffer').Buffer; var algs = require('./algs'); var crypto = require('crypto'); var errs = require('./errors'); var Key = require('./key'); var PrivateKey = require('./private-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; this.hashType = opts.hashType; } Fingerprint.prototype.toString = function (format) { if (format === undefined) { if (this.algorithm === 'md5' || this.hashType === 'spki') format = 'hex'; else format = 'base64'; } assert.string(format); switch (format) { case 'hex': if (this.hashType === 'spki') return (this.hash.toString('hex')); return (addColons(this.hash.toString('hex'))); case 'base64': if (this.hashType === 'spki') return (this.hash.toString('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' && this.hashType !== 'ssh') { utils.assertCompatible(other, Key, [1, 7], 'key with spki'); if (PrivateKey.isPrivateKey(other)) { utils.assertCompatible(other, PrivateKey, [1, 6], 'privatekey with spki support'); } } else 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, this.hashType); 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); }; /*JSSTYLED*/ var base64RE = /^[A-Za-z0-9+\/=]+$/; /*JSSTYLED*/ var hexRE = /^[a-fA-F0-9]+$/; 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; if (options.algorithms !== undefined) enAlgs = options.algorithms; assert.optionalArrayOfString(enAlgs, 'algorithms'); var hashType = 'ssh'; if (options.hashType !== undefined) hashType = options.hashType; assert.string(hashType, 'options.hashType'); var parts = fp.split(':'); if (parts.length == 2) { alg = parts[0].toLowerCase(); if (!base64RE.test(parts[1])) throw (new FingerprintFormatError(fp)); try { hash = Buffer.from(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.map(function (p) { while (p.length < 2) p = '0' + p; if (p.length > 2) throw (new FingerprintFormatError(fp)); return (p); }); parts = parts.join(''); if (!hexRE.test(parts) || parts.length % 2 !== 0) throw (new FingerprintFormatError(fp)); try { hash = Buffer.from(parts, 'hex'); } catch (e) { throw (new FingerprintFormatError(fp)); } } else { if (hexRE.test(fp)) { hash = Buffer.from(fp, 'hex'); } else if (base64RE.test(fp)) { hash = Buffer.from(fp, 'base64'); } else { throw (new FingerprintFormatError(fp)); } switch (hash.length) { case 32: alg = 'sha256'; break; case 16: alg = 'md5'; break; case 20: alg = 'sha1'; break; case 64: alg = 'sha512'; break; default: throw (new FingerprintFormatError(fp)); } /* Plain hex/base64: guess it's probably SPKI unless told. */ if (options.hashType === undefined) hashType = 'spki'; } 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', hashType: hashType })); }; 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 * [1,2] -- hashType and spki support */ Fingerprint.prototype._sshpkApiVersion = [1, 2]; Fingerprint._oldVersionDetect = function (obj) { assert.func(obj.toString); assert.func(obj.matches); return ([1, 0]); }; node-sshpk-1.16.1/lib/formats/000077500000000000000000000000001342215657600161075ustar00rootroot00000000000000node-sshpk-1.16.1/lib/formats/auto.js000066400000000000000000000065521342215657600174250ustar00rootroot00000000000000// Copyright 2018 Joyent, Inc. module.exports = { read: read, write: write }; var assert = require('assert-plus'); var Buffer = require('safer-buffer').Buffer; 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'); var dnssec = require('./dnssec'); var putty = require('./putty'); var DNSSEC_PRIVKEY_HEADER_PREFIX = 'Private-key-format: v1'; 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)); if (buf.match(/^putty-user-key-file-2:/i)) return (putty.read(buf, options)); if (findDNSSECHeader(buf)) return (dnssec.read(buf, options)); buf = Buffer.from(buf, 'binary'); } else { assert.buffer(buf); if (findPEMHeader(buf)) return (pem.read(buf, options)); if (findSSHHeader(buf)) return (ssh.read(buf, options)); if (findPuTTYHeader(buf)) return (putty.read(buf, options)); if (findDNSSECHeader(buf)) return (dnssec.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 findPuTTYHeader(buf) { var offset = 0; while (offset < buf.length && (buf[offset] === 32 || buf[offset] === 10 || buf[offset] === 9)) ++offset; if (offset + 22 <= buf.length && buf.slice(offset, offset + 22).toString('ascii').toLowerCase() === 'putty-user-key-file-2:') return (true); return (false); } 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 findDNSSECHeader(buf) { // private case first if (buf.length <= DNSSEC_PRIVKEY_HEADER_PREFIX.length) return (false); var headerCheck = buf.slice(0, DNSSEC_PRIVKEY_HEADER_PREFIX.length); if (headerCheck.toString('ascii') === DNSSEC_PRIVKEY_HEADER_PREFIX) return (true); // public-key RFC3110 ? // 'domain.com. IN KEY ...' or 'domain.com. IN DNSKEY ...' // skip any comment-lines if (typeof (buf) !== 'string') { buf = buf.toString('ascii'); } var lines = buf.split('\n'); var line = 0; /* JSSTYLED */ while (lines[line].match(/^\;/)) line++; if (lines[line].toString('ascii').match(/\. IN KEY /)) return (true); if (lines[line].toString('ascii').match(/\. IN DNSKEY /)) return (true); return (false); } function write(key, options) { throw (new Error('"auto" format cannot be used for writing')); } node-sshpk-1.16.1/lib/formats/dnssec.js000066400000000000000000000217511342215657600177320ustar00rootroot00000000000000// Copyright 2017 Joyent, Inc. module.exports = { read: read, write: write }; var assert = require('assert-plus'); var Buffer = require('safer-buffer').Buffer; var Key = require('../key'); var PrivateKey = require('../private-key'); var utils = require('../utils'); var SSHBuffer = require('../ssh-buffer'); var Dhe = require('../dhe'); var supportedAlgos = { 'rsa-sha1' : 5, 'rsa-sha256' : 8, 'rsa-sha512' : 10, 'ecdsa-p256-sha256' : 13, 'ecdsa-p384-sha384' : 14 /* * ed25519 is hypothetically supported with id 15 * but the common tools available don't appear to be * capable of generating/using ed25519 keys */ }; var supportedAlgosById = {}; Object.keys(supportedAlgos).forEach(function (k) { supportedAlgosById[supportedAlgos[k]] = k.toUpperCase(); }); function read(buf, options) { if (typeof (buf) !== 'string') { assert.buffer(buf, 'buf'); buf = buf.toString('ascii'); } var lines = buf.split('\n'); if (lines[0].match(/^Private-key-format\: v1/)) { var algElems = lines[1].split(' '); var algoNum = parseInt(algElems[1], 10); var algoName = algElems[2]; if (!supportedAlgosById[algoNum]) throw (new Error('Unsupported algorithm: ' + algoName)); return (readDNSSECPrivateKey(algoNum, lines.slice(2))); } // skip any comment-lines var line = 0; /* JSSTYLED */ while (lines[line].match(/^\;/)) line++; // we should now have *one single* line left with our KEY on it. if ((lines[line].match(/\. IN KEY /) || lines[line].match(/\. IN DNSKEY /)) && lines[line+1].length === 0) { return (readRFC3110(lines[line])); } throw (new Error('Cannot parse dnssec key')); } function readRFC3110(keyString) { var elems = keyString.split(' '); //unused var flags = parseInt(elems[3], 10); //unused var protocol = parseInt(elems[4], 10); var algorithm = parseInt(elems[5], 10); if (!supportedAlgosById[algorithm]) throw (new Error('Unsupported algorithm: ' + algorithm)); var base64key = elems.slice(6, elems.length).join(); var keyBuffer = Buffer.from(base64key, 'base64'); if (supportedAlgosById[algorithm].match(/^RSA-/)) { // join the rest of the body into a single base64-blob var publicExponentLen = keyBuffer.readUInt8(0); if (publicExponentLen != 3 && publicExponentLen != 1) throw (new Error('Cannot parse dnssec key: ' + 'unsupported exponent length')); var publicExponent = keyBuffer.slice(1, publicExponentLen+1); publicExponent = utils.mpNormalize(publicExponent); var modulus = keyBuffer.slice(1+publicExponentLen); modulus = utils.mpNormalize(modulus); // now, make the key var rsaKey = { type: 'rsa', parts: [] }; rsaKey.parts.push({ name: 'e', data: publicExponent}); rsaKey.parts.push({ name: 'n', data: modulus}); return (new Key(rsaKey)); } if (supportedAlgosById[algorithm] === 'ECDSA-P384-SHA384' || supportedAlgosById[algorithm] === 'ECDSA-P256-SHA256') { var curve = 'nistp384'; var size = 384; if (supportedAlgosById[algorithm].match(/^ECDSA-P256-SHA256/)) { curve = 'nistp256'; size = 256; } var ecdsaKey = { type: 'ecdsa', curve: curve, size: size, parts: [ {name: 'curve', data: Buffer.from(curve) }, {name: 'Q', data: utils.ecNormalize(keyBuffer) } ] }; return (new Key(ecdsaKey)); } throw (new Error('Unsupported algorithm: ' + supportedAlgosById[algorithm])); } function elementToBuf(e) { return (Buffer.from(e.split(' ')[1], 'base64')); } function readDNSSECRSAPrivateKey(elements) { var rsaParams = {}; elements.forEach(function (element) { if (element.split(' ')[0] === 'Modulus:') rsaParams['n'] = elementToBuf(element); else if (element.split(' ')[0] === 'PublicExponent:') rsaParams['e'] = elementToBuf(element); else if (element.split(' ')[0] === 'PrivateExponent:') rsaParams['d'] = elementToBuf(element); else if (element.split(' ')[0] === 'Prime1:') rsaParams['p'] = elementToBuf(element); else if (element.split(' ')[0] === 'Prime2:') rsaParams['q'] = elementToBuf(element); else if (element.split(' ')[0] === 'Exponent1:') rsaParams['dmodp'] = elementToBuf(element); else if (element.split(' ')[0] === 'Exponent2:') rsaParams['dmodq'] = elementToBuf(element); else if (element.split(' ')[0] === 'Coefficient:') rsaParams['iqmp'] = elementToBuf(element); }); // now, make the key var key = { type: 'rsa', parts: [ { name: 'e', data: utils.mpNormalize(rsaParams['e'])}, { name: 'n', data: utils.mpNormalize(rsaParams['n'])}, { name: 'd', data: utils.mpNormalize(rsaParams['d'])}, { name: 'p', data: utils.mpNormalize(rsaParams['p'])}, { name: 'q', data: utils.mpNormalize(rsaParams['q'])}, { name: 'dmodp', data: utils.mpNormalize(rsaParams['dmodp'])}, { name: 'dmodq', data: utils.mpNormalize(rsaParams['dmodq'])}, { name: 'iqmp', data: utils.mpNormalize(rsaParams['iqmp'])} ] }; return (new PrivateKey(key)); } function readDNSSECPrivateKey(alg, elements) { if (supportedAlgosById[alg].match(/^RSA-/)) { return (readDNSSECRSAPrivateKey(elements)); } if (supportedAlgosById[alg] === 'ECDSA-P384-SHA384' || supportedAlgosById[alg] === 'ECDSA-P256-SHA256') { var d = Buffer.from(elements[0].split(' ')[1], 'base64'); var curve = 'nistp384'; var size = 384; if (supportedAlgosById[alg] === 'ECDSA-P256-SHA256') { curve = 'nistp256'; size = 256; } // DNSSEC generates the public-key on the fly (go calculate it) var publicKey = utils.publicFromPrivateECDSA(curve, d); var Q = publicKey.part['Q'].data; var ecdsaKey = { type: 'ecdsa', curve: curve, size: size, parts: [ {name: 'curve', data: Buffer.from(curve) }, {name: 'd', data: d }, {name: 'Q', data: Q } ] }; return (new PrivateKey(ecdsaKey)); } throw (new Error('Unsupported algorithm: ' + supportedAlgosById[alg])); } function dnssecTimestamp(date) { var year = date.getFullYear() + ''; //stringify var month = (date.getMonth() + 1); var timestampStr = year + month + date.getUTCDate(); timestampStr += '' + date.getUTCHours() + date.getUTCMinutes(); timestampStr += date.getUTCSeconds(); return (timestampStr); } function rsaAlgFromOptions(opts) { if (!opts || !opts.hashAlgo || opts.hashAlgo === 'sha1') return ('5 (RSASHA1)'); else if (opts.hashAlgo === 'sha256') return ('8 (RSASHA256)'); else if (opts.hashAlgo === 'sha512') return ('10 (RSASHA512)'); else throw (new Error('Unknown or unsupported hash: ' + opts.hashAlgo)); } function writeRSA(key, options) { // if we're missing parts, add them. if (!key.part.dmodp || !key.part.dmodq) { utils.addRSAMissing(key); } var out = ''; out += 'Private-key-format: v1.3\n'; out += 'Algorithm: ' + rsaAlgFromOptions(options) + '\n'; var n = utils.mpDenormalize(key.part['n'].data); out += 'Modulus: ' + n.toString('base64') + '\n'; var e = utils.mpDenormalize(key.part['e'].data); out += 'PublicExponent: ' + e.toString('base64') + '\n'; var d = utils.mpDenormalize(key.part['d'].data); out += 'PrivateExponent: ' + d.toString('base64') + '\n'; var p = utils.mpDenormalize(key.part['p'].data); out += 'Prime1: ' + p.toString('base64') + '\n'; var q = utils.mpDenormalize(key.part['q'].data); out += 'Prime2: ' + q.toString('base64') + '\n'; var dmodp = utils.mpDenormalize(key.part['dmodp'].data); out += 'Exponent1: ' + dmodp.toString('base64') + '\n'; var dmodq = utils.mpDenormalize(key.part['dmodq'].data); out += 'Exponent2: ' + dmodq.toString('base64') + '\n'; var iqmp = utils.mpDenormalize(key.part['iqmp'].data); out += 'Coefficient: ' + iqmp.toString('base64') + '\n'; // Assume that we're valid as-of now var timestamp = new Date(); out += 'Created: ' + dnssecTimestamp(timestamp) + '\n'; out += 'Publish: ' + dnssecTimestamp(timestamp) + '\n'; out += 'Activate: ' + dnssecTimestamp(timestamp) + '\n'; return (Buffer.from(out, 'ascii')); } function writeECDSA(key, options) { var out = ''; out += 'Private-key-format: v1.3\n'; if (key.curve === 'nistp256') { out += 'Algorithm: 13 (ECDSAP256SHA256)\n'; } else if (key.curve === 'nistp384') { out += 'Algorithm: 14 (ECDSAP384SHA384)\n'; } else { throw (new Error('Unsupported curve')); } var base64Key = key.part['d'].data.toString('base64'); out += 'PrivateKey: ' + base64Key + '\n'; // Assume that we're valid as-of now var timestamp = new Date(); out += 'Created: ' + dnssecTimestamp(timestamp) + '\n'; out += 'Publish: ' + dnssecTimestamp(timestamp) + '\n'; out += 'Activate: ' + dnssecTimestamp(timestamp) + '\n'; return (Buffer.from(out, 'ascii')); } function write(key, options) { if (PrivateKey.isPrivateKey(key)) { if (key.type === 'rsa') { return (writeRSA(key, options)); } else if (key.type === 'ecdsa') { return (writeECDSA(key, options)); } else { throw (new Error('Unsupported algorithm: ' + key.type)); } } else if (Key.isKey(key)) { /* * RFC3110 requires a keyname, and a keytype, which we * don't really have a mechanism for specifying such * additional metadata. */ throw (new Error('Format "dnssec" only supports ' + 'writing private keys')); } else { throw (new Error('key is not a Key or PrivateKey')); } } node-sshpk-1.16.1/lib/formats/openssh-cert.js000066400000000000000000000210601342215657600210560ustar00rootroot00000000000000// 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 Buffer = require('safer-buffer').Buffer; 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 = Buffer.from(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()); var exts = []; var extbuf = new SSHBuffer({ buffer: sshbuf.readBuffer() }); var ext; while (!extbuf.atEnd()) { ext = { critical: true }; ext.name = extbuf.readString(); ext.data = extbuf.readBuffer(); exts.push(ext); } extbuf = new SSHBuffer({ buffer: sshbuf.readBuffer() }); while (!extbuf.atEnd()) { ext = { critical: false }; ext.name = extbuf.readString(); ext.data = extbuf.readBuffer(); exts.push(ext); } cert.signatures.openssh.exts = exts; /* 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 = Buffer.alloc(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)); var exts = sig.exts; if (exts === undefined) exts = []; var extbuf = new SSHBuffer({}); exts.forEach(function (ext) { if (ext.critical !== true) return; extbuf.writeString(ext.name); extbuf.writeBuffer(ext.data); }); buf.writeBuffer(extbuf.toBuffer()); extbuf = new SSHBuffer({}); exts.forEach(function (ext) { if (ext.critical === true) return; extbuf.writeString(ext.name); extbuf.writeBuffer(ext.data); }); buf.writeBuffer(extbuf.toBuffer()); /* reserved */ buf.writeBuffer(Buffer.alloc(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)); } node-sshpk-1.16.1/lib/formats/pem.js000066400000000000000000000164471342215657600172420ustar00rootroot00000000000000// Copyright 2018 Joyent, Inc. module.exports = { read: read, write: write }; var assert = require('assert-plus'); var asn1 = require('asn1'); var crypto = require('crypto'); var Buffer = require('safer-buffer').Buffer; 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'); var OID_PBES2 = '1.2.840.113549.1.5.13'; var OID_PBKDF2 = '1.2.840.113549.1.5.12'; var OID_TO_CIPHER = { '1.2.840.113549.3.7': '3des-cbc', '2.16.840.1.101.3.4.1.2': 'aes128-cbc', '2.16.840.1.101.3.4.1.42': 'aes256-cbc' }; var CIPHER_TO_OID = {}; Object.keys(OID_TO_CIPHER).forEach(function (k) { CIPHER_TO_OID[OID_TO_CIPHER[k]] = k; }); var OID_TO_HASH = { '1.2.840.113549.2.7': 'sha1', '1.2.840.113549.2.9': 'sha256', '1.2.840.113549.2.11': 'sha512' }; var HASH_TO_OID = {}; Object.keys(OID_TO_HASH).forEach(function (k) { HASH_TO_OID[OID_TO_HASH[k]] = k; }); /* * 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(/[\r\n]+/g); var m; var si = -1; while (!m && si < lines.length) { m = lines[++si].match(/*JSSTYLED*/ /[-]+[ ]*BEGIN ([A-Z0-9][A-Za-z0-9]+ )?(PUBLIC|PRIVATE) KEY[ ]*[-]+/); } assert.ok(m, 'invalid PEM header'); var m2; var ei = lines.length; while (!m2 && ei > 0) { m2 = lines[--ei].match(/*JSSTYLED*/ /[-]+[ ]*END ([A-Z0-9][A-Za-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(); } lines = lines.slice(si, ei + 1); 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 = Buffer.from(lines, 'base64'); 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 = Buffer.from( 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 = Buffer.from(parts[1], 'hex'); key = utils.opensslKeyDeriv(cipher, iv, options.passphrase, 1).key; } } } if (alg && alg.toLowerCase() === 'encrypted') { var eder = new asn1.BerReader(buf); var pbesEnd; eder.readSequence(); eder.readSequence(); pbesEnd = eder.offset + eder.length; var method = eder.readOID(); if (method !== OID_PBES2) { throw (new Error('Unsupported PEM/PKCS8 encryption ' + 'scheme: ' + method)); } eder.readSequence(); /* PBES2-params */ eder.readSequence(); /* keyDerivationFunc */ var kdfEnd = eder.offset + eder.length; var kdfOid = eder.readOID(); if (kdfOid !== OID_PBKDF2) throw (new Error('Unsupported PBES2 KDF: ' + kdfOid)); eder.readSequence(); var salt = eder.readString(asn1.Ber.OctetString, true); var iterations = eder.readInt(); var hashAlg = 'sha1'; if (eder.offset < kdfEnd) { eder.readSequence(); var hashAlgOid = eder.readOID(); hashAlg = OID_TO_HASH[hashAlgOid]; if (hashAlg === undefined) { throw (new Error('Unsupported PBKDF2 hash: ' + hashAlgOid)); } } eder._offset = kdfEnd; eder.readSequence(); /* encryptionScheme */ var cipherOid = eder.readOID(); cipher = OID_TO_CIPHER[cipherOid]; if (cipher === undefined) { throw (new Error('Unsupported PBES2 cipher: ' + cipherOid)); } iv = eder.readString(asn1.Ber.OctetString, true); eder._offset = pbesEnd; buf = eder.readString(asn1.Ber.OctetString, true); if (typeof (options.passphrase) === 'string') { options.passphrase = Buffer.from( options.passphrase, 'utf-8'); } if (!Buffer.isBuffer(options.passphrase)) { throw (new errors.KeyEncryptedError( options.filename, 'PEM')); } var cinfo = utils.opensshCipherInfo(cipher); cipher = cinfo.opensslName; key = utils.pbkdf2(hashAlg, salt, iterations, cinfo.keySize, options.passphrase); alg = undefined; } 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', 'ed25519': 'EdDSA' }[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 = Buffer.alloc(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)); } node-sshpk-1.16.1/lib/formats/pkcs1.js000066400000000000000000000214761342215657600175000ustar00rootroot00000000000000// Copyright 2015 Joyent, Inc. module.exports = { read: read, readPkcs1: readPkcs1, write: write, writePkcs1: writePkcs1 }; var assert = require('assert-plus'); var asn1 = require('asn1'); var Buffer = require('safer-buffer').Buffer; 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)); case 'EDDSA': case 'EdDSA': if (type === 'private') return (readPkcs1EdDSAPrivate(der)); throw (new Error(type + ' keys not supported with EdDSA')); 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 readPkcs1EdDSAPrivate(der) { var version = readMPInt(der, 'version'); assert.strictEqual(version.readUInt8(0), 1); // private key var k = der.readString(asn1.Ber.OctetString, true); der.readSequence(0xa0); var oid = der.readOID(); assert.strictEqual(oid, '1.3.101.112', 'the ed25519 curve identifier'); der.readSequence(0xa1); var A = utils.readBitString(der); var key = { type: 'ed25519', parts: [ { name: 'A', data: utils.zeroPadToLength(A, 32) }, { name: 'k', data: k } ] }; 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: Buffer.from(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: Buffer.from(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; case 'ed25519': if (PrivateKey.isPrivateKey(key)) writePkcs1EdDSAPrivate(der, key); else writePkcs1EdDSAPublic(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 = Buffer.from([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 = Buffer.from([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 = Buffer.from([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(); } function writePkcs1EdDSAPrivate(der, key) { var ver = Buffer.from([1]); der.writeBuffer(ver, asn1.Ber.Integer); der.writeBuffer(key.part.k.data, asn1.Ber.OctetString); der.startSequence(0xa0); der.writeOID('1.3.101.112'); der.endSequence(); der.startSequence(0xa1); utils.writeBitString(der, key.part.A.data); der.endSequence(); } function writePkcs1EdDSAPublic(der, key) { throw (new Error('Public keys are not supported for EdDSA PKCS#1')); } node-sshpk-1.16.1/lib/formats/pkcs8.js000066400000000000000000000343131342215657600175010ustar00rootroot00000000000000// Copyright 2018 Joyent, Inc. module.exports = { read: read, readPkcs8: readPkcs8, write: write, writePkcs8: writePkcs8, pkcs8ToBuffer: pkcs8ToBuffer, readECDSACurve: readECDSACurve, writeECDSACurve: writeECDSACurve }; var assert = require('assert-plus'); var asn1 = require('asn1'); var Buffer = require('safer-buffer').Buffer; 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)); case '1.3.101.112': if (type === 'public') { return (readPkcs8EdDSAPublic(der)); } else { return (readPkcs8EdDSAPrivate(der)); } case '1.3.101.110': if (type === 'public') { return (readPkcs8X25519Public(der)); } else { return (readPkcs8X25519Private(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); var Q; if (der.peek() == 0xa0) { der.readSequence(0xa0); der._offset += der.length; } if (der.peek() == 0xa1) { der.readSequence(0xa1); Q = der.readString(asn1.Ber.BitString, true); Q = utils.ecNormalize(Q); } if (Q === undefined) { var pub = utils.publicFromPrivateECDSA(curveName, d); Q = pub.part.Q.data; } var key = { type: 'ecdsa', parts: [ { name: 'curve', data: Buffer.from(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: Buffer.from(curveName) }, { name: 'Q', data: Q } ] }; return (new Key(key)); } function readPkcs8EdDSAPublic(der) { if (der.peek() === 0x00) der.readByte(); var A = utils.readBitString(der); var key = { type: 'ed25519', parts: [ { name: 'A', data: utils.zeroPadToLength(A, 32) } ] }; return (new Key(key)); } function readPkcs8X25519Public(der) { var A = utils.readBitString(der); var key = { type: 'curve25519', parts: [ { name: 'A', data: utils.zeroPadToLength(A, 32) } ] }; return (new Key(key)); } function readPkcs8EdDSAPrivate(der) { if (der.peek() === 0x00) der.readByte(); der.readSequence(asn1.Ber.OctetString); var k = der.readString(asn1.Ber.OctetString, true); k = utils.zeroPadToLength(k, 32); var A; if (der.peek() === asn1.Ber.BitString) { A = utils.readBitString(der); A = utils.zeroPadToLength(A, 32); } else { A = utils.calculateED25519Public(k); } var key = { type: 'ed25519', parts: [ { name: 'A', data: utils.zeroPadToLength(A, 32) }, { name: 'k', data: utils.zeroPadToLength(k, 32) } ] }; return (new PrivateKey(key)); } function readPkcs8X25519Private(der) { if (der.peek() === 0x00) der.readByte(); der.readSequence(asn1.Ber.OctetString); var k = der.readString(asn1.Ber.OctetString, true); k = utils.zeroPadToLength(k, 32); var A = utils.calculateX25519Public(k); var key = { type: 'curve25519', parts: [ { name: 'A', data: utils.zeroPadToLength(A, 32) }, { name: 'k', data: utils.zeroPadToLength(k, 32) } ] }; return (new PrivateKey(key)); } function pkcs8ToBuffer(key) { var der = new asn1.BerWriter(); writePkcs8(der, key); return (der.buffer); } function writePkcs8(der, key) { der.startSequence(); if (PrivateKey.isPrivateKey(key)) { var sillyInt = Buffer.from([0]); 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; case 'ed25519': der.writeOID('1.3.101.112'); if (PrivateKey.isPrivateKey(key)) throw (new Error('Ed25519 private keys in pkcs8 ' + 'format are not supported')); writePkcs8EdDSAPublic(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 = Buffer.from([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 = Buffer.from([1]); 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 = Buffer.from([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 = Buffer.from([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(); } function writePkcs8EdDSAPublic(key, der) { der.endSequence(); utils.writeBitString(der, key.part.A.data); } function writePkcs8EdDSAPrivate(key, der) { der.endSequence(); var k = utils.mpNormalize(key.part.k.data, true); der.startSequence(asn1.Ber.OctetString); der.writeBuffer(k, asn1.Ber.OctetString); der.endSequence(); } node-sshpk-1.16.1/lib/formats/putty.js000066400000000000000000000044371342215657600176420ustar00rootroot00000000000000// Copyright 2018 Joyent, Inc. module.exports = { read: read, write: write }; var assert = require('assert-plus'); var Buffer = require('safer-buffer').Buffer; var rfc4253 = require('./rfc4253'); var Key = require('../key'); var errors = require('../errors'); function read(buf, options) { var lines = buf.toString('ascii').split(/[\r\n]+/); var found = false; var parts; var si = 0; while (si < lines.length) { parts = splitHeader(lines[si++]); if (parts && parts[0].toLowerCase() === 'putty-user-key-file-2') { found = true; break; } } if (!found) { throw (new Error('No PuTTY format first line found')); } var alg = parts[1]; parts = splitHeader(lines[si++]); assert.equal(parts[0].toLowerCase(), 'encryption'); parts = splitHeader(lines[si++]); assert.equal(parts[0].toLowerCase(), 'comment'); var comment = parts[1]; parts = splitHeader(lines[si++]); assert.equal(parts[0].toLowerCase(), 'public-lines'); var publicLines = parseInt(parts[1], 10); if (!isFinite(publicLines) || publicLines < 0 || publicLines > lines.length) { throw (new Error('Invalid public-lines count')); } var publicBuf = Buffer.from( lines.slice(si, si + publicLines).join(''), 'base64'); var keyType = rfc4253.algToKeyType(alg); var key = rfc4253.read(publicBuf); if (key.type !== keyType) { throw (new Error('Outer key algorithm mismatch')); } key.comment = comment; return (key); } function splitHeader(line) { var idx = line.indexOf(':'); if (idx === -1) return (null); var header = line.slice(0, idx); ++idx; while (line[idx] === ' ') ++idx; var rest = line.slice(idx); return ([header, rest]); } function write(key, options) { assert.object(key); if (!Key.isKey(key)) throw (new Error('Must be a public key')); var alg = rfc4253.keyTypeToAlg(key); var buf = rfc4253.write(key); var comment = key.comment || ''; var b64 = buf.toString('base64'); var lines = wrap(b64, 64); lines.unshift('Public-Lines: ' + lines.length); lines.unshift('Comment: ' + comment); lines.unshift('Encryption: none'); lines.unshift('PuTTY-User-Key-File-2: ' + alg); return (Buffer.from(lines.join('\n') + '\n')); } function wrap(txt, len) { var lines = []; var pos = 0; while (pos < txt.length) { lines.push(txt.slice(pos, pos + 64)); pos += 64; } return (lines); } node-sshpk-1.16.1/lib/formats/rfc4253.js000066400000000000000000000102201342215657600175300ustar00rootroot00000000000000// 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 Buffer = require('safer-buffer').Buffer; 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 = Buffer.from(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) { var p = parts[i]; p.name = algInfo.parts[i]; /* * OpenSSH stores ed25519 "private" keys as seed + public key * concat'd together (k followed by A). We want to keep them * separate for other formats that don't do this. */ if (key.type === 'ed25519' && p.name === 'k') p.data = p.data.slice(0, 32); if (p.name !== 'curve' && algInfo.normalize !== false) { var nd; if (key.type === 'ed25519') { nd = utils.zeroPadToLength(p.data, 32); } else { nd = utils.mpNormalize(p.data); } if (nd.toString('binary') !== p.data.toString('binary')) { 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) { if (key.type === 'ed25519') data = utils.zeroPadToLength(data, 32); else data = utils.mpNormalize(data); } if (key.type === 'ed25519' && parts[i] === 'k') data = Buffer.concat([data, key.part.A.data]); buf.writeBuffer(data); } return (buf.toBuffer()); } node-sshpk-1.16.1/lib/formats/ssh-private.js000066400000000000000000000154261342215657600207220ustar00rootroot00000000000000// Copyright 2015 Joyent, Inc. module.exports = { read: read, readSSHPrivate: readSSHPrivate, write: write }; var assert = require('assert-plus'); var asn1 = require('asn1'); var Buffer = require('safer-buffer').Buffer; 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 = Buffer.from(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 = Buffer.from(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 = Buffer.alloc(0); var cinf = { blockSize: 8 }; var passphrase; if (options !== undefined) { passphrase = options.passphrase; if (typeof (passphrase) === 'string') passphrase = Buffer.from(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 = Buffer.from(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 = Buffer.alloc(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)); } node-sshpk-1.16.1/lib/formats/ssh.js000066400000000000000000000061771342215657600172550ustar00rootroot00000000000000// Copyright 2015 Joyent, Inc. module.exports = { read: read, write: write }; var assert = require('assert-plus'); var Buffer = require('safer-buffer').Buffer; 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+\/]+[=]*)([ \t]+([^ \t][^\n]*[\n]*)?)?$/; /*JSSTYLED*/ var SSHKEY_RE2 = /^([a-z0-9-]+)[ \t\n]+([a-zA-Z0-9+\/][a-zA-Z0-9+\/ \t\n=]*)([^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 = Buffer.from(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 = Buffer.from(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] ? 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 (Buffer.from(parts.join(' '))); } node-sshpk-1.16.1/lib/formats/x509-pem.js000066400000000000000000000040011342215657600177240ustar00rootroot00000000000000// 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 Buffer = require('safer-buffer').Buffer; 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; var si = -1; while (!m && si < lines.length) { m = lines[++si].match(/*JSSTYLED*/ /[-]+[ ]*BEGIN CERTIFICATE[ ]*[-]+/); } assert.ok(m, 'invalid PEM header'); var m2; var ei = lines.length; while (!m2 && ei > 0) { m2 = lines[--ei].match(/*JSSTYLED*/ /[-]+[ ]*END CERTIFICATE[ ]*[-]+/); } assert.ok(m2, 'invalid PEM footer'); lines = lines.slice(si, ei + 1); 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 = Buffer.from(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 = Buffer.alloc(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)); } node-sshpk-1.16.1/lib/formats/x509.js000066400000000000000000000461441342215657600171630ustar00rootroot00000000000000// 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 Buffer = require('safer-buffer').Buffer; 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', 'ed25519-sha512': '1.3.101.112' }; 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 = Buffer.from(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')); } } function writeDate(der, date) { if (date.getUTCFullYear() >= 2050 || date.getUTCFullYear() < 1950) { der.writeString(dateToGTime(date), asn1.Ber.GeneralizedTime); } else { der.writeString(dateToUTCTime(date), asn1.Ber.UTCTime); } } /* 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; if (!sig.extras.exts) 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, m) { if (m === undefined) m = 2; var s = '' + n; while (s.length < m) 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 dateToGTime(d) { var s = ''; s += zeroPad(d.getUTCFullYear(), 4); 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 = Buffer.alloc(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]); if (sig.algo.match(/^rsa-/)) der.writeNull(); der.endSequence(); cert.issuer.toAsn1(der); der.startSequence(); writeDate(der, cert.validFrom); writeDate(der, cert.validUntil); 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 = Buffer.alloc(1 + blen); // zero-filled 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); } node-sshpk-1.16.1/lib/identity.js000066400000000000000000000234641342215657600166340ustar00rootroot00000000000000// 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'); var Buffer = require('safer-buffer').Buffer; /*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.postalCode = '2.5.4.17'; oids.serialNumber = '2.5.4.5'; oids.street = '2.5.4.9'; oids.x500UniqueIdentifier = '2.5.4.45'; oids.role = '2.5.4.72'; oids.telephoneNumber = '2.5.4.20'; oids.description = '2.5.4.13'; 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'; oids.title = '2.5.4.12'; oids.gn = '2.5.4.42'; oids.initials = '2.5.4.43'; oids.pseudonym = '2.5.4.65'; oids.emailAddress = '1.2.840.113549.1.9.1'; 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) { var n = c.name.toUpperCase(); /*JSSTYLED*/ n = n.replace(/=/g, '\\='); var v = c.value; /*JSSTYLED*/ v = v.replace(/,/g, '\\,'); return (n + '=' + v); }).join(', ')); }; Identity.prototype.get = function (name, asArray) { assert.string(name, 'name'); var arr = this.componentLookup[name]; if (arr === undefined || arr.length === 0) return (undefined); if (!asArray && arr.length > 1) throw (new Error('Multiple values for attribute ' + name)); if (!asArray) return (arr[0].value); return (arr.map(function (c) { return (c.value); })); }; Identity.prototype.toArray = function (idx) { return (this.components.map(function (c) { return ({ name: c.name, value: c.value }); })); }; /* * 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 this identity was parsed from a DN, use the ASN.1 types * from the original representation (otherwise this might not * be a full match for the original in some validators). */ if (c.asn1type === asn1.Ber.Utf8String || c.value.match(NOT_IA5)) { var v = Buffer.from(c.value, 'utf8'); der.writeBuffer(v, asn1.Ber.Utf8String); } else if (c.asn1type === asn1.Ber.IA5String || c.value.match(NOT_PRINTABLE)) { der.writeString(c.value, asn1.Ber.IA5String); } else { var type = asn1.Ber.PrintableString; if (c.asn1type !== undefined) type = c.asn1type; der.writeString(c.value, type); } 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 = ['']; var idx = 0; var rem = dn; while (rem.length > 0) { var m; /*JSSTYLED*/ if ((m = /^,/.exec(rem)) !== null) { parts[++idx] = ''; rem = rem.slice(m[0].length); /*JSSTYLED*/ } else if ((m = /^\\,/.exec(rem)) !== null) { parts[idx] += ','; rem = rem.slice(m[0].length); /*JSSTYLED*/ } else if ((m = /^\\./.exec(rem)) !== null) { parts[idx] += m[0]; rem = rem.slice(m[0].length); /*JSSTYLED*/ } else if ((m = /^[^\\,]+/.exec(rem)) !== null) { parts[idx] += m[0]; rem = rem.slice(m[0].length); } else { throw (new Error('Failed to parse DN')); } } var cmps = parts.map(function (c) { c = c.trim(); var eqPos = c.indexOf('='); while (eqPos > 0 && c.charAt(eqPos - 1) === '\\') eqPos = c.indexOf('=', eqPos + 1); if (eqPos === -1) { throw (new Error('Failed to parse DN')); } /*JSSTYLED*/ var name = c.slice(0, eqPos).toLowerCase().replace(/\\=/g, '='); var value = c.slice(eqPos + 1); return ({ name: name, value: value }); }); return (new Identity({ components: cmps })); }; Identity.fromArray = function (components) { assert.arrayOfObject(components, 'components'); components.forEach(function (cmp) { assert.object(cmp, 'component'); assert.string(cmp.name, 'component.name'); if (!Buffer.isBuffer(cmp.value) && !(typeof (cmp.value) === 'string')) { throw (new Error('Invalid component value')); } }); return (new Identity({ components: components })); }; 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, asn1type: type, 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]); }; node-sshpk-1.16.1/lib/index.js000066400000000000000000000023761342215657600161110ustar00rootroot00000000000000// 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, identityFromArray: Identity.fromArray, /* errors */ FingerprintFormatError: errs.FingerprintFormatError, InvalidAlgorithmError: errs.InvalidAlgorithmError, KeyParseError: errs.KeyParseError, SignatureParseError: errs.SignatureParseError, KeyEncryptedError: errs.KeyEncryptedError, CertificateParseError: errs.CertificateParseError }; node-sshpk-1.16.1/lib/key.js000066400000000000000000000176651342215657600156010ustar00rootroot00000000000000// Copyright 2018 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']; formats['dnssec'] = require('./formats/dnssec'); formats['putty'] = require('./formats/putty'); formats['ppk'] = formats['putty']; 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' || this.type === 'curve25519') { 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, type) { assert.string(algo, 'algorithm'); assert.optionalString(type, 'type'); if (type === undefined) type = 'ssh'; algo = algo.toLowerCase(); if (algs.hashAlgs[algo] === undefined) throw (new InvalidAlgorithmError(algo)); var cacheKey = algo + '||' + type; if (this._hashCache[cacheKey]) return (this._hashCache[cacheKey]); var buf; if (type === 'ssh') { buf = this.toBuffer('rfc4253'); } else if (type === 'spki') { buf = formats.pkcs8.pkcs8ToBuffer(this); } else { throw (new Error('Hash type ' + type + ' not supported')); } var hash = crypto.createHash(algo).update(buf).digest(); this._hashCache[cacheKey] = hash; return (hash); }; Key.prototype.fingerprint = function (algo, type) { if (algo === undefined) algo = 'sha256'; if (type === undefined) type = 'ssh'; assert.string(algo, 'algorithm'); assert.string(type, 'type'); var opts = { type: 'key', hash: this.hash(algo, type), algorithm: algo, hashType: type }; 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 * [1,6] -- changed ed25519 part names * [1,7] -- spki hash types */ Key.prototype._sshpkApiVersion = [1, 7]; 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]); }; node-sshpk-1.16.1/lib/private-key.js000066400000000000000000000150771342215657600172440ustar00rootroot00000000000000// Copyright 2017 Joyent, Inc. module.exports = PrivateKey; var assert = require('assert-plus'); var Buffer = require('safer-buffer').Buffer; 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 = require('./ed-compat'); var nacl = require('tweetnacl'); 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']; formats['dnssec'] = require('./formats/dnssec'); 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, type) { return (this.toPublic().hash(algo, type)); }; PrivateKey.prototype.fingerprint = function (algo, type) { return (this.toPublic().fingerprint(algo, type)); }; 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) { assert.string(newType, 'type'); var priv, pub, pair; if (this.type === 'ed25519' && newType === 'curve25519') { priv = this.part.k.data; if (priv[0] === 0x00) priv = priv.slice(1); pair = nacl.box.keyPair.fromSecretKey(new Uint8Array(priv)); pub = Buffer.from(pair.publicKey); return (new PrivateKey({ type: 'curve25519', parts: [ { name: 'A', data: utils.mpNormalize(pub) }, { name: 'k', data: utils.mpNormalize(priv) } ] })); } else if (this.type === 'curve25519' && newType === 'ed25519') { priv = this.part.k.data; if (priv[0] === 0x00) priv = priv.slice(1); pair = nacl.sign.keyPair.fromSeed(new Uint8Array(priv)); pub = Buffer.from(pair.publicKey); return (new PrivateKey({ type: 'ed25519', parts: [ { name: 'A', data: utils.mpNormalize(pub) }, { name: 'k', data: utils.mpNormalize(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 = Buffer.from(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 * [1,5] -- changed ed25519 part names and format * [1,6] -- type arguments for hash() and fingerprint() */ PrivateKey.prototype._sshpkApiVersion = [1, 6]; 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]); }; node-sshpk-1.16.1/lib/signature.js000066400000000000000000000174651342215657600170100ustar00rootroot00000000000000// Copyright 2015 Joyent, Inc. module.exports = Signature; var assert = require('assert-plus'); var Buffer = require('safer-buffer').Buffer; 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 = Buffer.from(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]); }; node-sshpk-1.16.1/lib/ssh-buffer.js000066400000000000000000000074451342215657600170500ustar00rootroot00000000000000// Copyright 2015 Joyent, Inc. module.exports = SSHBuffer; var assert = require('assert-plus'); var Buffer = require('safer-buffer').Buffer; 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 || Buffer.alloc(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 = Buffer.alloc(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(Buffer.from(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; }; node-sshpk-1.16.1/lib/utils.js000066400000000000000000000231471342215657600161410ustar00rootroot00000000000000// Copyright 2015 Joyent, Inc. module.exports = { bufferSplit: bufferSplit, addRSAMissing: addRSAMissing, calculateDSAPublic: calculateDSAPublic, calculateED25519Public: calculateED25519Public, calculateX25519Public: calculateX25519Public, mpNormalize: mpNormalize, mpDenormalize: mpDenormalize, ecNormalize: ecNormalize, countZeros: countZeros, assertCompatible: assertCompatible, isCompatible: isCompatible, opensslKeyDeriv: opensslKeyDeriv, opensshCipherInfo: opensshCipherInfo, publicFromPrivateECDSA: publicFromPrivateECDSA, zeroPadToLength: zeroPadToLength, writeBitString: writeBitString, readBitString: readBitString, pbkdf2: pbkdf2 }; var assert = require('assert-plus'); var Buffer = require('safer-buffer').Buffer; var PrivateKey = require('./private-key'); var Key = require('./key'); var crypto = require('crypto'); var algs = require('./algs'); var asn1 = require('asn1'); var ec = require('ecc-jsbn/lib/ec'); var jsbn = require('jsbn').BigInteger; var nacl = require('tweetnacl'); 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: 24, iv: 8 }, 'aes-128-cbc': { key: 16, iv: 16 }, 'aes-256-cbc': { key: 32, 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 = Buffer.alloc(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) }); } /* See: RFC2898 */ function pbkdf2(hashAlg, salt, iterations, size, passphrase) { var hkey = Buffer.alloc(salt.length + 4); salt.copy(hkey); var gen = 0, ts = []; var i = 1; while (gen < size) { var t = T(i++); gen += t.length; ts.push(t); } return (Buffer.concat(ts).slice(0, size)); function T(I) { hkey.writeUInt32BE(I, hkey.length - 4); var hmac = crypto.createHmac(hashAlg, passphrase); hmac.update(hkey); var Ti = hmac.digest(); var Uc = Ti; var c = 1; while (c++ < iterations) { hmac = crypto.createHmac(hashAlg, passphrase); hmac.update(Uc); Uc = hmac.digest(); for (var x = 0; x < Ti.length; ++x) Ti[x] ^= Uc[x]; } return (Ti); } } /* 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 = Buffer.alloc(buf.length + 1); b[0] = 0x0; buf.copy(b, 1); return (b); } function readBitString(der, tag) { if (tag === undefined) tag = asn1.Ber.BitString; var buf = der.readString(tag, true); assert.strictEqual(buf[0], 0x00, 'bit strings with unused bits are ' + 'not supported (0x' + buf[0].toString(16) + ')'); return (buf.slice(1)); } function writeBitString(der, buf, tag) { if (tag === undefined) tag = asn1.Ber.BitString; var b = Buffer.alloc(buf.length + 1); b[0] = 0x00; buf.copy(b, 1); der.writeBuffer(b, tag); } 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 = Buffer.alloc(buf.length + 1); b[0] = 0x00; buf.copy(b, 1); buf = b; } return (buf); } function mpDenormalize(buf) { assert.buffer(buf); while (buf.length > 1 && buf[0] === 0x00) buf = buf.slice(1); return (buf); } function zeroPadToLength(buf, len) { assert.buffer(buf); assert.number(len); while (buf.length > len) { assert.equal(buf[0], 0x00); buf = buf.slice(1); } while (buf.length < len) { var b = Buffer.alloc(buf.length + 1); b[0] = 0x00; buf.copy(b, 1); buf = b; } return (buf); } function bigintToMpBuf(bigint) { var buf = Buffer.from(bigint.toByteArray()); buf = mpNormalize(buf); return (buf); } function calculateDSAPublic(g, p, x) { assert.buffer(g); assert.buffer(p); assert.buffer(x); g = new jsbn(g); p = new jsbn(p); x = new jsbn(x); var y = g.modPow(x, p); var ybuf = bigintToMpBuf(y); return (ybuf); } function calculateED25519Public(k) { assert.buffer(k); var kp = nacl.sign.keyPair.fromSeed(new Uint8Array(k)); return (Buffer.from(kp.publicKey)); } function calculateX25519Public(k) { assert.buffer(k); var kp = nacl.box.keyPair.fromSeed(new Uint8Array(k)); return (Buffer.from(kp.publicKey)); } function addRSAMissing(key) { assert.object(key); assertCompatible(key, PrivateKey, [1, 1]); var d = new jsbn(key.part.d.data); var buf; if (!key.part.dmodp) { var p = new jsbn(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 jsbn(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 publicFromPrivateECDSA(curveName, priv) { assert.string(curveName, 'curveName'); assert.buffer(priv); var params = algs.curves[curveName]; var p = new jsbn(params.p); var a = new jsbn(params.a); var b = new jsbn(params.b); var curve = new ec.ECCurveFp(p, a, b); var G = curve.decodePointHex(params.G.toString('hex')); var d = new jsbn(mpNormalize(priv)); var pub = G.multiply(d); pub = Buffer.from(curve.encodePointHex(pub), 'hex'); var parts = []; parts.push({name: 'curve', data: Buffer.from(curveName)}); parts.push({name: 'Q', data: pub}); var key = new Key({type: 'ecdsa', curve: curve, parts: parts}); return (key); } 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); } node-sshpk-1.16.1/man/000077500000000000000000000000001342215657600144415ustar00rootroot00000000000000node-sshpk-1.16.1/man/src/000077500000000000000000000000001342215657600152305ustar00rootroot00000000000000node-sshpk-1.16.1/man/src/sshpk-conv.md000066400000000000000000000072261342215657600176540ustar00rootroot00000000000000sshpk-conv 1 "Jan 2016" sshpk "sshpk Commands" ============================================== NAME ---- sshpk-conv - convert between key formats SYNOPSYS -------- `sshpk-conv` -t FORMAT [FILENAME] [OPTIONS...] `sshpk-conv` -i [FILENAME] [OPTIONS...] DESCRIPTION ----------- 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. In the second form, with the `-i` option given, identifies a key and prints to stderr information about its nature, size and fingerprint. EXAMPLES -------- Assume the following SSH-format public key in `id_ecdsa.pub`: ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTI...9M/4c4= user@host Identify it with `-i`: $ 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 Convert it to `pkcs8` format, for use with e.g. OpenSSL: $ sshpk-conv -t pkcs8 id_ecdsa -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAsA4R6N6AS3gzaPBeLjG2ObSgUsR zOt+kWJoijLnw3ZMYUKmAx+lD0I5XUxdrPcs1vH5f3cn9TvRvO9L0z/hzg== -----END PUBLIC KEY----- Retrieve the public half of a private key: $ openssl genrsa 2048 | sshpk-conv -t ssh -c foo@bar ssh-rsa AAAAB3NzaC1yc2EAAA...koK7 foo@bar Convert a private key to PKCS#1 (OpenSSL) format from a new-style OpenSSH key format (the `ssh-keygen -o` format): $ ssh-keygen -o -f foobar ... $ sshpk-conv -p -t pkcs1 foobar -----BEGIN RSA PRIVATE KEY----- MIIDpAIBAAKCAQEA6T/GYJndb1TRH3+NL.... -----END RSA PRIVATE KEY----- OPTIONS ------- `-i, --identify` Instead of converting the key, output identifying information about it to stderr, including its type, size and fingerprints. `-p, --private` Treat the key as a private key instead of a public key (the default). If you supply `sshpk-conv` 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. `-f PATH, --file=PATH` 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. `-o PATH, --out=PATH` Output file name to use instead of stdout. `-T FORMAT, --informat=FORMAT` `-t FORMAT, --outformat=FORMAT` Selects the input and output formats to be used (see FORMATS, below). `-c TEXT, --comment=TEXT` Sets the key comment for the output file, if supported. FORMATS ------- Currently supported formats: `pem, pkcs1` The standard PEM format used by older OpenSSH and most TLS libraries such as OpenSSL. The classic `id_rsa` file is usually in this format. It is an ASN.1 encoded structure, base64-encoded and placed between PEM headers. `ssh` The SSH public key text format (the format of an `id_rsa.pub` file). A single line, containing 3 space separated parts: the key type, key body and optional key comment. `pkcs8` 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 `pkcs1`. `openssh` The new `ssh-keygen -o` format from OpenSSH. This can be mistaken for a PEM encoding but is actually an OpenSSH internal format. `rfc4253` The internal binary format of keys when sent over the wire in the SSH protocol. This is also the format that the `ssh-agent` uses in its protocol. SEE ALSO -------- ssh-keygen(1), openssl(1) BUGS ---- Encrypted (password-protected) keys are not supported. Report bugs at [Github](https://github.com/arekinath/node-sshpk/issues) node-sshpk-1.16.1/man/src/sshpk-sign.md000066400000000000000000000044051342215657600176430ustar00rootroot00000000000000sshpk-sign 1 "Jan 2016" sshpk "sshpk Commands" ============================================== NAME ---- sshpk-sign - sign data using an SSH key SYNOPSYS -------- `sshpk-sign` -i KEYPATH [OPTION...] DESCRIPTION ----------- Takes in arbitrary bytes, and signs them using an SSH private key. The key can be of any type or format supported by the `sshpk` library, including the standard OpenSSH formats, as well as PEM PKCS#1 and PKCS#8. The signature is printed out in Base64 encoding, unless the `--binary` or `-b` option is given. EXAMPLES -------- Signing with default settings: $ printf 'foo' | sshpk-sign -i ~/.ssh/id_ecdsa MEUCIAMdLS/vXrrtWFepwe... Signing in SSH (RFC 4253) format (rather than the default ASN.1): $ printf 'foo' | sshpk-sign -i ~/.ssh/id_ecdsa -t ssh AAAAFGVjZHNhLXNoYTIt... Saving the binary signature to a file: $ printf 'foo' | sshpk-sign -i ~/.ssh/id_ecdsa \ -o signature.bin -b $ cat signature.bin | base64 MEUCIAMdLS/vXrrtWFepwe... OPTIONS ------- `-v, --verbose` Print extra information about the key and signature to stderr when signing. `-b, --binary` Don't base64-encode the signature before outputting it. `-i KEY, --identity=KEY` Select the key to be used for signing. `KEY` must be a relative or absolute filesystem path to the key file. Any format supported by the `sshpk` library is supported, including OpenSSH formats and standard PEM PKCS. `-f PATH, --file=PATH` Input file to sign instead of stdin. `-o PATH, --out=PATH` Output file to save signature in instead of stdout. `-H HASH, --hash=HASH` Set the hash algorithm to be used for signing. This should be one of `sha1`, `sha256` or `sha512`. Some key types may place restrictions on which hash algorithms may be used (e.g. ED25519 keys can only use SHA-512). `-t FORMAT, --format=FORMAT` Choose the signature format to use, from `asn1`, `ssh` or `raw` (only for ED25519 signatures). The `asn1` 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 `ssh` format is used in the SSH protocol and by the ssh-agent. SEE ALSO -------- sshpk-verify(1) BUGS ---- Report bugs at [Github](https://github.com/arekinath/node-sshpk/issues) node-sshpk-1.16.1/man/src/sshpk-verify.md000066400000000000000000000040521342215657600202050ustar00rootroot00000000000000sshpk-verify 1 "Jan 2016" sshpk "sshpk Commands" ============================================== NAME ---- sshpk-verify - verify a signature on data using an SSH key SYNOPSYS -------- `sshpk-verify` -i KEYPATH -s SIGNATURE [OPTION...] DESCRIPTION ----------- 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. EXAMPLES -------- $ printf 'foo' | sshpk-verify -i ~/.ssh/id_ecdsa -s MEUCIQCYp... OK $ printf 'foo' | sshpk-verify -i ~/.ssh/id_ecdsa -s GARBAGE... NOT OK EXIT STATUS ----------- `0` Signature validates and matches the key. `1` Signature is parseable and the correct length but does not match the key or otherwise is invalid. `2` The signature or key could not be parsed. `3` Invalid commandline options were supplied. OPTIONS ------- `-v, --verbose` Print extra information about the key and signature to stderr when verifying. `-i KEY, --identity=KEY` Select the key to be used for verification. `KEY` must be a relative or absolute filesystem path to the key file. Any format supported by the `sshpk` library is supported, including OpenSSH formats and standard PEM PKCS. `-s BASE64, --signature=BASE64` Supplies the base64-encoded signature to be verified. `-f PATH, --file=PATH` Input file to verify instead of stdin. `-H HASH, --hash=HASH` Set the hash algorithm to be used for signing. This should be one of `sha1`, `sha256` or `sha512`. Some key types may place restrictions on which hash algorithms may be used (e.g. ED25519 keys can only use SHA-512). `-t FORMAT, --format=FORMAT` Choose the signature format to use, from `asn1`, `ssh` or `raw` (only for ED25519 signatures). The `asn1` 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 `ssh` format is used in the SSH protocol and by the ssh-agent. SEE ALSO -------- sshpk-sign(1) BUGS ---- Report bugs at [Github](https://github.com/arekinath/node-sshpk/issues) node-sshpk-1.16.1/package.json000066400000000000000000000023751342215657600161630ustar00rootroot00000000000000{ "name": "sshpk", "version": "1.16.1", "description": "A library for finding and using SSH public keys", "main": "lib/index.js", "scripts": { "test": "tape test/*.js" }, "repository": { "type": "git", "url": "git+https://github.com/joyent/node-sshpk.git" }, "author": "Joyent, Inc", "contributors": [ { "name": "Dave Eddy", "email": "dave@daveeddy.com" }, { "name": "Mark Cavage", "email": "mcavage@gmail.com" }, { "name": "Alex Wilson", "email": "alex@cooperi.net" } ], "license": "MIT", "bugs": { "url": "https://github.com/arekinath/node-sshpk/issues" }, "engines": { "node": ">=0.10.0" }, "directories": { "bin": "./bin", "lib": "./lib", "man": "./man/man1" }, "homepage": "https://github.com/arekinath/node-sshpk#readme", "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", "dashdash": "^1.12.0", "getpass": "^0.1.1", "safer-buffer": "^2.0.2", "jsbn": "~0.1.0", "tweetnacl": "~0.14.0", "ecc-jsbn": "~0.1.1", "bcrypt-pbkdf": "^1.0.0" }, "optionalDependencies": { }, "devDependencies": { "tape": "^3.5.0", "benchmark": "^1.0.0", "sinon": "^1.17.2", "temp": "^0.8.2" } } node-sshpk-1.16.1/test/000077500000000000000000000000001342215657600146455ustar00rootroot00000000000000node-sshpk-1.16.1/test/assets/000077500000000000000000000000001342215657600161475ustar00rootroot00000000000000node-sshpk-1.16.1/test/assets/1024b-dsa-example-cert.der000066400000000000000000000015631342215657600225310ustar00rootroot000000000000000‚n0‚×0  *†H†÷ 0›1 0 UJP10 UTokyo10UChuo-ku10U Frank4DD10U WebCert Support10UFrank4DD Web CA1#0! *†H†÷  support@frank4dd.com0 120822072702Z 170821072702Z0J1 0 UJP10 U Tokyo10U Frank4DD10U www.example.com0‚¶0‚+*†HÎ80‚™'JÖ‚‡•ÌþÙ¦ºÞ¬pß~;p‹Q¬Ž=­ýŸ»=H%ÀQd5[jbý¹?.¢Íx´»qG7 ´¨¡¢ØdŸ¼ni§ª½Rç‹Mœ|EU<¨™þ;¸Eê¼AqèR¦JÀ]tå7YVkS‡ÿ…ü.¤DBÃ~òº4uÕFžÔÜÆ%@œàQ¦ì$@ó˧VÚ5»›€Sðr½á£X+H²·W#Î3'üL@ô—!JÒf{á,+ ü#¦Ÿâÿ šbÌ‹–¶yÛ÷Z€åËð2°ªÐüòtªÆé/®bc}ÒÞ‹\#CßT+vÛEäðH… sW†ÂÌØ4•5¡å•+ß”@kú)ñÛ­4ãtÈ„€>˜Pö•ÅZªw²'w¸pŠf&.ÖZø»¹is”‡—š”e+§ÖUêBÑ:Aï+ ‹|ª½Fѹ;¶h y÷šÌî¸DK¥R6Nƒ§ß3O$š’€§OHYéÜ—,˜3»ðˆÁü’󘩂Q e41¦íî²/d!0  *†H†÷ Ñš²˜EnÚrbLsÙö_Zï¹[ Y6S²hû’‘ÀµWËh»— ÿÞR4%~ÿrºÅ4Ähœ6EÓ嬕¨e×´ŒdL–Úp8ìcÑaL/ ¤^Ô_{”‰CÙ_5´Tõ •F@ý½qÛ; _x/õÊ„ÏR¶ˆ¯ node-sshpk-1.16.1/test/assets/3des.pem000066400000000000000000000033271342215657600175150ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,91DE47E39A642704 T5h5N8sO/mT8zRfqVDc2Kmgy5Az9w63T91Gvl57XhAxd7jD2vZhbAdD3qdnYc9Ue h4uve27OcJXQXHTUaAZY2ZR/9e9NFIkSnbEQHVzMa0W5I7v7JvN9Ms8z9WJuxd9k 9M8t6rYiLQXbdKG3RhEyS+m5O/tU1dxWakwIxlE9fpLcHWgEO2YEPwKjiM/WY0Uj +eH02oaPIVIC6Eyni7CTCjkhgTn8xI+yHfIow94IUYg4OJNes27dhruH/nybPYPt gW6eQfENrXZNTCzp3E71/WB/27JVI8eNkTtluoFTn8KAeiDNIB0b/KFpJoIFTgWX ysYqiv6a5q7Q+mxEet+krZ40LBsh2cNLqJGCRh/nGU3Zs8hozyUfkhBMzjvLc36E F2cqtjBGeds1kHvBAdbBBNLel11icRkTzIw0cMa1YulYdJARf+cgWugk+NVgEOpK g3G6QymJiVm4DudbtTcmBqgfYju9bo8X1hkGB1w+eUZMjLDCv0ZfCZCKovpZorkD PJa+y12fwEQ79NZxmfUKCBLVzO4n5Bh2MzWJZQSh3oLSP90fRyWS0Rq8l6N4z90m RowD62laYR9zydLZX+gkjGiIEjNxwcEY/iuHi32ufONyFTTDUcidZ/RZJdd0zk5r 1t6FbrTcM0tIukN0behKri6jbTMd91DYSpO7xB+fKugfka+grYWyLeQc0brqbqNn Pwt+FuM+qVoXe2FdY4cy/Jhqb/hYsvXuhPJ5IowN3QNnvsSduq0NwM2wXGNF+l8s z40HsTZly5lVChold8EjbNi9xZLWRQL5UtPdacgr+U2NTqiM7Eup0YfU9wn50GNg /pjzkTY8fpkio3mjkIRcfEfSnERYRnOP0zDMkd+bJdQcb0sjCpdxS8vXfFvLQ1Af zBz5DLa1vq8Cc7C0vsLjBEC2LQygv0q9nU7fvg9TMuSQNXj0TJY3I2i8ZZHvyPVL j4u6Pfpg0bjAYsnBoeyMzt7ii1wJk76e23SeZQxOz5+1z1L8J9NyzH4zZeTOSXqq MZ1eW8tQRnYSnfyQVyXRyKHvH+aPYrMo3ElLfseRDdU0sikQ/XVneMOGQCI0+pCx RIXpcnUgIcT2f3sCAQ+t0jmxWeirhLYpBMmAs3TLrdDyG5n/DReV6utXRSvJMC6/ yWF5w4IGhvjkERFisugqPsMTXfW4xWHwq+MU6IU1TurRIJRZHPs3WgICPeCOJFBv bQHvwtHmHZJ6ijIF+SPkTV0PoHxRXv8O2QsqiFSVp03FjImrShxeU2iIz3SzB3Di gpaYyBhXQitMTNvtCAPPdFUHrpB5ZZ+qI3sStvMTMaSb8EpSU1H79L/7Olv6wtLx w3PCtCaz56P0X8cZP57MSGt+E7x3+GKYNFC5znNyVthgKz66z/z33epzD2j2Zf4b VvRE6W/RzHN2UOhnqdk6IX7SO7ynPO5Sx/bKL+ARVRD51NpOSzTUujBEoeB0ObFN B4PWao7GOeh/WUTF83AYOtEk+J/8CYMNB1IClrpZszcCyAAkx26OdoOPAGMBD1V/ HnE2S4h22855esmjQOggwNCtf0Tg6PG7+jhb8MwerYwaiqfn2hQpAz6ZKff2Qeh5 -----END RSA PRIVATE KEY----- node-sshpk-1.16.1/test/assets/3des.pub000066400000000000000000000006021342215657600175130ustar00rootroot00000000000000ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLISAQ2h/VFo0tGe3irSmk3KU5x5IYtPke1yk8hSgd/AKbJlDuqPF3BfbEkmV/gA7EpxPhr5QkfcLCkAjWZhUJccn0Dmz6Ypd615IQrEPMS48wFl4yRSDaPyGcOi+lcgrgclcnTG9/vEqRfqw7y8aRZIq880nNoxHe/TQbeQuuGf0Zdts4t5YFbm8MkwCMSlY+DRSy462YZ4h7zBYOA6TDcSJvvHVGe937xqavMK2btj9wIij2qtCP4L23zDl2QCM+c9DxC+FvNY6fyNrePs2pbyZb2z3Bg+SR/J+hSqMUSYKLBYzQnG/c0T8xE59bk1P8jOeJGVgQGS6m9CSwVOgZ test node-sshpk-1.16.1/test/assets/Kecdsatest.+013+43896.key000066400000000000000000000001631342215657600220210ustar00rootroot00000000000000ecdsatest. IN KEY 0 3 13 es1l0ZlSrePQHoKVPXcefo6ExgKfO+KkoT57saLvugu1GrnwHRpNmvk6 yOjQeu865o5vI+wtar62A5mgSf/fvQ== node-sshpk-1.16.1/test/assets/Kecdsatest.+013+43896.pem000066400000000000000000000003431342215657600220120ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- MHcCAQEEILi6bncoctoBJQdw3jJKl+cY30lfAMGDjuLlI/YR7grfoAoGCCqGSM49 AwEHoUQDQgAEes1l0ZlSrePQHoKVPXcefo6ExgKfO+KkoT57saLvugu1GrnwHRpN mvk6yOjQeu865o5vI+wtar62A5mgSf/fvQ== -----END EC PRIVATE KEY----- node-sshpk-1.16.1/test/assets/Kecdsatest.+013+43896.private000066400000000000000000000002731342215657600227050ustar00rootroot00000000000000Private-key-format: v1.3 Algorithm: 13 (ECDSAP256SHA256) PrivateKey: uLpudyhy2gElB3DeMkqX5xjfSV8AwYOO4uUj9hHuCt8= Created: 20170814234326 Publish: 20170814234326 Activate: 20170814234326 node-sshpk-1.16.1/test/assets/Kecdsatest.+013+43896_pub.pem000066400000000000000000000002621342215657600226600ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEes1l0ZlSrePQHoKVPXcefo6ExgKf O+KkoT57saLvugu1GrnwHRpNmvk6yOjQeu865o5vI+wtar62A5mgSf/fvQ== -----END PUBLIC KEY----- node-sshpk-1.16.1/test/assets/Krsatest.+005+57206.key000066400000000000000000000003121342215657600215120ustar00rootroot00000000000000rsatest. IN KEY 0 3 5 AwEAAdXDanWK1Cp18HaFIO5oDglGE78b9Z/rRMuyXbBYsqy3FakcR+Es lHlioo3IrDZJQ3ZWQ15M925+Iynwx4CoLGz0mHZ97EG6Y0s0Fc8wCTL/ U4MvW/NNXtUQBydQc+A9GGjotXX8TC6ycGIzuPdJsP+lDIfTZsS7loVG Xb4m/hc9 node-sshpk-1.16.1/test/assets/Krsatest.+005+57206.pem000066400000000000000000000015671342215657600215200ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDVw2p1itQqdfB2hSDuaA4JRhO/G/Wf60TLsl2wWLKstxWpHEfh LJR5YqKNyKw2SUN2VkNeTPdufiMp8MeAqCxs9Jh2fexBumNLNBXPMAky/1ODL1vz TV7VEAcnUHPgPRho6LV1/EwusnBiM7j3SbD/pQyH02bEu5aFRl2+Jv4XPQIDAQAB AoGAYNB6vPW9leWInQU6nv99q/GTK/EL0/wIUoFcMWxasCLTqp3maDN6o2dq2/BR Ht0bstLq/CC7x81VO7+Te8+vHm3aHK8GQIuEExtJo/ydulUPFnMmmZa6kAFVrTvK s09+KAu93K+bGch9zvPw51uKMiqAvOsYhvqHf/Pi2qxY5YECQQDrScsW1vekyjjF UlcIFO2S8HwkCIjKyRxwG9l9NHa6tzyHV9yIjcmMLwB+AyzM90cQYFH6Od1d9sEu xBCXiE+RAkEA6JSPWFx7WdlSMT7PQ45NF7bHM6Vp8lfXQr1zLMpdXS1O3Oy3Bbpq bmnjaToeNmcvRMPhtOeK9912nNiHxgqO7QJAatUVxqgSx5seTdIGPGAsQwS4iS/q 1JCePfUXOndg1YSvkhB9zO78LY+F3LGaXPKGLNRfRIuTjL+mlZJmqjc1UQJAK4QQ RfIXyjnVHQ2pbfRkDDnQj6M1bXht+DjGIe1DBroBdWh83f+BBmOdfwS2vmsT9wPH aTehUrsHBFWnIbC8CQJBAKTKY7rnSu0qE4vNLfCVa+seJGXUe9z1a/U1cOtJWQwm 7EY6IxCKRNPH7mdvf+2mAmuRR1xdsTRMp4y+Y3qTOow= -----END RSA PRIVATE KEY----- node-sshpk-1.16.1/test/assets/Krsatest.+005+57206.private000066400000000000000000000017621342215657600224060ustar00rootroot00000000000000Private-key-format: v1.3 Algorithm: 5 (RSASHA1) Modulus: 1cNqdYrUKnXwdoUg7mgOCUYTvxv1n+tEy7JdsFiyrLcVqRxH4SyUeWKijcisNklDdlZDXkz3bn4jKfDHgKgsbPSYdn3sQbpjSzQVzzAJMv9Tgy9b801e1RAHJ1Bz4D0YaOi1dfxMLrJwYjO490mw/6UMh9NmxLuWhUZdvib+Fz0= PublicExponent: AQAB PrivateExponent: YNB6vPW9leWInQU6nv99q/GTK/EL0/wIUoFcMWxasCLTqp3maDN6o2dq2/BRHt0bstLq/CC7x81VO7+Te8+vHm3aHK8GQIuEExtJo/ydulUPFnMmmZa6kAFVrTvKs09+KAu93K+bGch9zvPw51uKMiqAvOsYhvqHf/Pi2qxY5YE= Prime1: 60nLFtb3pMo4xVJXCBTtkvB8JAiIyskccBvZfTR2urc8h1fciI3JjC8AfgMszPdHEGBR+jndXfbBLsQQl4hPkQ== Prime2: 6JSPWFx7WdlSMT7PQ45NF7bHM6Vp8lfXQr1zLMpdXS1O3Oy3BbpqbmnjaToeNmcvRMPhtOeK9912nNiHxgqO7Q== Exponent1: atUVxqgSx5seTdIGPGAsQwS4iS/q1JCePfUXOndg1YSvkhB9zO78LY+F3LGaXPKGLNRfRIuTjL+mlZJmqjc1UQ== Exponent2: K4QQRfIXyjnVHQ2pbfRkDDnQj6M1bXht+DjGIe1DBroBdWh83f+BBmOdfwS2vmsT9wPHaTehUrsHBFWnIbC8CQ== Coefficient: pMpjuudK7SoTi80t8JVr6x4kZdR73PVr9TVw60lZDCbsRjojEIpE08fuZ29/7aYCa5FHXF2xNEynjL5jepM6jA== Created: 20170814221729 Publish: 20170814221729 Activate: 20170814221729 node-sshpk-1.16.1/test/assets/Krsatest.+005+57206_pub.pem000066400000000000000000000004201342215657600223510ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVw2p1itQqdfB2hSDuaA4JRhO/ G/Wf60TLsl2wWLKstxWpHEfhLJR5YqKNyKw2SUN2VkNeTPdufiMp8MeAqCxs9Jh2 fexBumNLNBXPMAky/1ODL1vzTV7VEAcnUHPgPRho6LV1/EwusnBiM7j3SbD/pQyH 02bEu5aFRl2+Jv4XPQIDAQAB -----END PUBLIC KEY----- node-sshpk-1.16.1/test/assets/cloudflare.pem000066400000000000000000000036541342215657600210020ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIFfDCCBSOgAwIBAgIRAKUKr1+KSsQLm/QUXECt7cYwCgYIKoZIzj0EAwIwgZIx CzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNV BAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTgwNgYDVQQD Ey9DT01PRE8gRUNDIERvbWFpbiBWYWxpZGF0aW9uIFNlY3VyZSBTZXJ2ZXIgQ0Eg MjAeFw0xNjA3MDUwMDAwMDBaFw0xNzAxMDgyMzU5NTlaMGwxITAfBgNVBAsTGERv bWFpbiBDb250cm9sIFZhbGlkYXRlZDEhMB8GA1UECxMYUG9zaXRpdmVTU0wgTXVs dGktRG9tYWluMSQwIgYDVQQDExtzbmkxMTMzNTYuY2xvdWRmbGFyZXNzbC5jb20w WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARgm17F3ag1w7gicQ7Qmo/OTCMpFm1C DO0vQ9pehgY8CYYrAJFzlRwjTpdXLxZ18LDAhS9FDosDNRERnglOeVBso4IDfTCC A3kwHwYDVR0jBBgwFoAUQAlhZ/C8g3FP3hIILG/U1Ct2PZYwHQYDVR0OBBYEFGhp JT1yvejIdhQVK0HY0u/yJ16nMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAA MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBPBgNVHSAESDBGMDoGCysG AQQBsjEBAgIHMCswKQYIKwYBBQUHAgEWHWh0dHBzOi8vc2VjdXJlLmNvbW9kby5j b20vQ1BTMAgGBmeBDAECATBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLmNv bW9kb2NhNC5jb20vQ09NT0RPRUNDRG9tYWluVmFsaWRhdGlvblNlY3VyZVNlcnZl ckNBMi5jcmwwgYgGCCsGAQUFBwEBBHwwejBRBggrBgEFBQcwAoZFaHR0cDovL2Ny dC5jb21vZG9jYTQuY29tL0NPTU9ET0VDQ0RvbWFpblZhbGlkYXRpb25TZWN1cmVT ZXJ2ZXJDQTIuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC5jb21vZG9jYTQu Y29tMIIBxAYDVR0RBIIBuzCCAbeCG3NuaTExMzM1Ni5jbG91ZGZsYXJlc3NsLmNv bYISKi5hdmVyeS1za2FjaGF0Lm1sggsqLmJsZWFjaC5tbIIWKi5idW5rYmVkc2Zv cmdpcmxzLmNvbYIXKi5jaGljZnVybmlzaGluZzEwMS54eXqCCyouaW1leW91Lmlv ggwqLmtuZmVtNDAuY2aCGSoubWV0YWxkZXRlY3Rpbmdob3d0by54eXqCDCoubmx5 dnU0MC5jZoIMKi5vYmtrZzQwLmdhgg8qLm9ub21hZC5vbmxpbmWCFCoub3V0bGFu ZGlzaGpvc2guY29tggwqLnRsaW9qNDUuZ2GCEGF2ZXJ5LXNrYWNoYXQubWyCCWJs ZWFjaC5tbIIUYnVua2JlZHNmb3JnaXJscy5jb22CFWNoaWNmdXJuaXNoaW5nMTAx Lnh5eoIJaW1leW91LmlvggprbmZlbTQwLmNmghdtZXRhbGRldGVjdGluZ2hvd3Rv Lnh5eoIKbmx5dnU0MC5jZoIKb2Jra2c0MC5nYYINb25vbWFkLm9ubGluZYISb3V0 bGFuZGlzaGpvc2guY29tggp0bGlvajQ1LmdhMAoGCCqGSM49BAMCA0cAMEQCIAss 1QbMKvQtnCVbXjNr3rXLThFAwpOGQjWD8u5Mh7+HAiBxnaMWa4+OB59rx1ypvqB4 u9pTEKNZOM7c3kgawXq4Pw== -----END CERTIFICATE----- node-sshpk-1.16.1/test/assets/comodo.crt000066400000000000000000000016431342215657600201450ustar00rootroot000000000000000‚Ÿ0‚% [%ÎiÄ&UfÓ9 ™©T­0 *†HÎ=0…1 0 UGB10UGreater Manchester10USalford10U COMODO CA Limited1+0)U"COMODO ECC Certification Authority0 140925000000Z 290924235959Z0’1 0 UGB10UGreater Manchester10USalford10U COMODO CA Limited1806U/COMODO ECC Domain Validation Secure Server CA 20Y0*†HÎ=*†HÎ=B8:Éi„pYލŠ0ß¼Þüy:%,kA!‚êù>Jä3ÌÏ*CüòdÀá%P‚$ͶI8%G‘H¤­£‚f0‚b0U#0€uq§H¼êAGß”ÄHw™Óy0U@ agð¼ƒqOÞ,oÔÔ+v=–0Uÿ†0Uÿ0ÿ0U%0++0U 00U 0g 0LUE0C0A ? =†;http://crl.comodoca.com/COMODOECCCertificationAuthority.crl0r+f0d0;+0†/http://crt.comodoca.com/COMODOECCAddTrustCA.crt0%+0†http://ocsp.comodoca4.com0 *†HÎ=h0e1¬hG%€OVÀ¢7 —ZPÄçí´aË(Š 2¦âq߉oz fkй.C÷Ro0…|Žf’ºšE ”J0aÑIÜoëç-ɉÏj|ì…Î0%Yºp4¸4çÑâËRnode-sshpk-1.16.1/test/assets/curdle-pkix-privonly.pem000066400000000000000000000001671342215657600227650ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC -----END PRIVATE KEY----- node-sshpk-1.16.1/test/assets/curdle-pkix-withpub.pem000066400000000000000000000003261342215657600225620ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MHICAQEwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC oB8wHQYKKoZIhvcNAQkJFDEPDA1DdXJkbGUgQ2hhaXJzgSEAGb9ECWmEzf6FQbrB Z9w7lshQhqowtrbLDFw4rXAxZuE= -----END PRIVATE KEY------ node-sshpk-1.16.1/test/assets/digicert-ca.crt000066400000000000000000000022721342215657600210370ustar00rootroot000000000000000‚¶0‚ž  y©D°Œ• ’a_âkƒ0  *†H†÷  0l1 0 UUS10U  DigiCert Inc10U www.digicert.com1+0)U"DigiCert High Assurance EV Root CA0 131022120000Z 281022120000Z0u1 0 UUS10U  DigiCert Inc10U www.digicert.com1402U+DigiCert SHA2 Extended Validation Server CA0‚"0  *†H†÷ ‚0‚ ‚×S¤Qø™¦HKg'ª“IÐ9í °°‡ñg(†…ŒŽcÚ¼±@8âÓõ쥸=>Å™2ìŒúñ ¦d!…Ë4°Rˆ+h›Ò±°³Òçˆï8wTS_€y?.ª¨K+ «·c¹5·}¼YKßQJÒ¡â ₇j®ê×dÖ˜Uèý¯PlT¼òýJò»ôվމUØÀq4îöÜ-ìć%†Ø!ä°M ‰Ü9&Ýö×”…Ø!pooÿ\ºáEËVW(~ AWª·¸'»±äú*ï!#u­-›†5Œœwµs­Ø”-äó îÁNb~Àqž,Þñù(3£‚I0‚E0Uÿ0ÿ0Uÿ†0U%0++04+(0&0$+0†http://ocsp.digicert.com0KUD0B0@ > <†:http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl0=U 60402U 0*0(+https://www.digicert.com/CPS0U=ÓP¥Ö ­îóJ` eÓ!ÔøøÖ0U#0€±>Ãiø¿GÔ˜&ïcd+Ã0  *†H†÷  ‚¶Ð†á†íÅ ð4tÁv̆ ¨ðJŠBÖ?È©M­|­æ¶P¸¢Mˆ±)!ÜçÚÆ«9r[ðG ¹²M‘„Ü» .(È|ç+iè¨ûtÞ›‰Àq¢ÃuásÄ„ node-sshpk-1.16.1/test/assets/george-openssh.pub000066400000000000000000000031251342215657600216050ustar00rootroot00000000000000ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgzc/ITc93psigtgu8QX+zM61g/eCQp4CAEi/vFdqp3TwAAACBANBGJdbHdT5d/1tU3d3Cw1Hr2/PoyYsmaGP82wH+2apK0RoZOmQfHlc/oyz9yordFB/VgleR800m5rJJH2TvwMqphw611oGDu+hSqV5UGyQBKIzPfh4mi9WHY4rZ6nHEeC2SiT6QKZG7dutDvXHmjBrLU+hwBY/Fd7oBN9P0Qxu3AAAAFQC0/mjeSy8EnwMuUhO098QaKBbYFQAAAIEAtZiJz9yGBwT1vsoLM938qkWSYU78qseOqXmpXFgCi9nbtXWvrLFEMAsQIUTBzNkEyDWyVBU8ld9ycvlaj5jclNaRJ/JLcGyzK/8I78/QvtiY/VkSxLxymOkLI33q/yXWn5yUEU5HyBdiyI4eLFvYS2slyxYWq63b6NTr99lFBd4AAACBAItcldZqWy1ZyoLMLcFzYV3Q80vU2aFXWckDU7xPERsjSnmxIuvKSZGCpZZX6XqWn0zcdtu+AZGVZu1FOpV/g0cckpGi2ACtZ2XLGZ2IdMk0cTrZTmzXPBLxy5gBkO1CijIjGy2d5B4ojI9vAf5uTc+qY15qel1KzXuPgzP+zABmAAAAAAAAAAAAAAABAAAACWdlb3JnZWtleQAAAAoAAAAGZ2VvcmdlAAAAAFeRWggAAAAAWXE8fQAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAGzAAAAB3NzaC1kc3MAAACBANBGJdbHdT5d/1tU3d3Cw1Hr2/PoyYsmaGP82wH+2apK0RoZOmQfHlc/oyz9yordFB/VgleR800m5rJJH2TvwMqphw611oGDu+hSqV5UGyQBKIzPfh4mi9WHY4rZ6nHEeC2SiT6QKZG7dutDvXHmjBrLU+hwBY/Fd7oBN9P0Qxu3AAAAFQC0/mjeSy8EnwMuUhO098QaKBbYFQAAAIEAtZiJz9yGBwT1vsoLM938qkWSYU78qseOqXmpXFgCi9nbtXWvrLFEMAsQIUTBzNkEyDWyVBU8ld9ycvlaj5jclNaRJ/JLcGyzK/8I78/QvtiY/VkSxLxymOkLI33q/yXWn5yUEU5HyBdiyI4eLFvYS2slyxYWq63b6NTr99lFBd4AAACBAItcldZqWy1ZyoLMLcFzYV3Q80vU2aFXWckDU7xPERsjSnmxIuvKSZGCpZZX6XqWn0zcdtu+AZGVZu1FOpV/g0cckpGi2ACtZ2XLGZ2IdMk0cTrZTmzXPBLxy5gBkO1CijIjGy2d5B4ojI9vAf5uTc+qY15qel1KzXuPgzP+zABmAAAANwAAAAdzc2gtZHNzAAAAKC53ceRpJIQ73wc1BHbp9cccco08sPylyIEbBgT2e2SHBZV/WMOeInM= id_dsa node-sshpk-1.16.1/test/assets/george-x509.pem000066400000000000000000000016031342215657600206250ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICazCCAigCCQC5yqE79U0ouDALBglghkgBZQMEAwIwGDEWMBQGCgmSJomT8ixk AQETBmdlb3JnZTAeFw0xNjA3MjEyMzI2MjJaFw0xNzA3MjEyMzI2MjJaMBgxFjAU BgoJkiaJk/IsZAEBEwZnZW9yZ2UwggG4MIIBLAYHKoZIzjgEATCCAR8CgYEA0EYl 1sd1Pl3/W1Td3cLDUevb8+jJiyZoY/zbAf7ZqkrRGhk6ZB8eVz+jLP3Kit0UH9WC V5HzTSbmskkfZO/AyqmHDrXWgYO76FKpXlQbJAEojM9+HiaL1YdjitnqccR4LZKJ PpApkbt260O9ceaMGstT6HAFj8V3ugE30/RDG7cCFQC0/mjeSy8EnwMuUhO098Qa KBbYFQKBgQC1mInP3IYHBPW+ygsz3fyqRZJhTvyqx46pealcWAKL2du1da+ssUQw CxAhRMHM2QTINbJUFTyV33Jy+VqPmNyU1pEn8ktwbLMr/wjvz9C+2Jj9WRLEvHKY 6Qsjfer/JdafnJQRTkfIF2LIjh4sW9hLayXLFharrdvo1Ov32UUF3gOBhQACgYEA i1yV1mpbLVnKgswtwXNhXdDzS9TZoVdZyQNTvE8RGyNKebEi68pJkYKlllfpepaf TNx2274BkZVm7UU6lX+DRxySkaLYAK1nZcsZnYh0yTRxOtlObNc8EvHLmAGQ7UKK MiMbLZ3kHiiMj28B/m5Nz6pjXmp6XUrNe4+DM/7MAGYwCwYJYIZIAWUDBAMCAzAA MC0CFQCvM7xt2Yzh/5hKwFXTzNWhTfaeNgIUM3mu1O1fK1s2V+TTIKx3KIvVm8I= -----END CERTIFICATE----- node-sshpk-1.16.1/test/assets/google_jp_458san.pem000066400000000000000000000231101342215657600217160ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIcFzCCG4CgAwIBAgIGR09PUAFxMA0GCSqGSIb3DQEBBQUAMEYxCzAJBgNVBAYT AlVTMRMwEQYDVQQKEwpHb29nbGUgSW5jMSIwIAYDVQQDExlHb29nbGUgSW50ZXJu ZXQgQXV0aG9yaXR5MB4XDTEyMTAyNDEzNTczOVoXDTEzMDYwNzE5NDMyN1owZDEL MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50 YWluIFZpZXcxEzARBgNVBAoTCkdvb2dsZSBJbmMxEzARBgNVBAMTCmdvb2dsZS5j b20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMNn/Rw5irMPscWpYsExcGQT wqdxT/U9Pfybt9ttPYlXVbCd6yux0jWGNBHN+f4kCc5pwrbjmA4QSRY2uVa4T8f2 g3NucDDveUi29WVN+FJcyhj+V38lEkYbdhpIZL149dK5fAN1zzwCo10Nk+lhebcY fCtMHLmuCX2D6mJ2CnPVAgMBAAGjghnwMIIZ7DAMBgNVHRMBAf8EAjAAMB0GA1Ud JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQU0Qp1w0hi4nhbaJEB h/wuZwO4OyIwHwYDVR0jBBgwFoAUv8Aw6/VDET5nup6R+/xq2uNrEiQwWwYDVR0f BFQwUjBQoE6gTIZKaHR0cDovL3d3dy5nc3RhdGljLmNvbS9Hb29nbGVJbnRlcm5l dEF1dGhvcml0eS9Hb29nbGVJbnRlcm5ldEF1dGhvcml0eS5jcmwwZgYIKwYBBQUH AQEEWjBYMFYGCCsGAQUFBzAChkpodHRwOi8vd3d3LmdzdGF0aWMuY29tL0dvb2ds ZUludGVybmV0QXV0aG9yaXR5L0dvb2dsZUludGVybmV0QXV0aG9yaXR5LmNydDCC GLYGA1UdEQSCGK0wghipggpnb29nbGUuY29tggwqLmdvb2dsZS5jb22CDSoueW91 dHViZS5jb22CC3lvdXR1YmUuY29tghYqLnlvdXR1YmUtbm9jb29raWUuY29tggh5 b3V0dS5iZYILKi55dGltZy5jb22CDSouYW5kcm9pZC5jb22CC2FuZHJvaWQuY29t ghQqLmdvb2dsZWNvbW1lcmNlLmNvbYISZ29vZ2xlY29tbWVyY2UuY29tghAqLnVy bC5nb29nbGUuY29tggwqLnVyY2hpbi5jb22CCnVyY2hpbi5jb22CFiouZ29vZ2xl LWFuYWx5dGljcy5jb22CFGdvb2dsZS1hbmFseXRpY3MuY29tghIqLmNsb3VkLmdv b2dsZS5jb22CBmdvby5nbIIEZy5jb4INKi5nc3RhdGljLmNvbYIPKi5nb29nbGVh cGlzLmNughYqLmFwcGVuZ2luZS5nb29nbGUuY29tggsqLmdvb2dsZS5hY4ILKi5n b29nbGUuYWSCCyouZ29vZ2xlLmFlggsqLmdvb2dsZS5hZoILKi5nb29nbGUuYWeC CyouZ29vZ2xlLmFsggsqLmdvb2dsZS5hbYILKi5nb29nbGUuYXOCCyouZ29vZ2xl LmF0ggsqLmdvb2dsZS5heoILKi5nb29nbGUuYmGCCyouZ29vZ2xlLmJlggsqLmdv b2dsZS5iZoILKi5nb29nbGUuYmeCCyouZ29vZ2xlLmJpggsqLmdvb2dsZS5iaoIL Ki5nb29nbGUuYnOCCyouZ29vZ2xlLmJ5ggsqLmdvb2dsZS5jYYIMKi5nb29nbGUu Y2F0ggsqLmdvb2dsZS5jY4ILKi5nb29nbGUuY2SCCyouZ29vZ2xlLmNmggsqLmdv b2dsZS5jZ4ILKi5nb29nbGUuY2iCCyouZ29vZ2xlLmNpggsqLmdvb2dsZS5jbIIL Ki5nb29nbGUuY22CCyouZ29vZ2xlLmNugg4qLmdvb2dsZS5jby5hb4IOKi5nb29n bGUuY28uYneCDiouZ29vZ2xlLmNvLmNrgg4qLmdvb2dsZS5jby5jcoIOKi5nb29n bGUuY28uaHWCDiouZ29vZ2xlLmNvLmlkgg4qLmdvb2dsZS5jby5pbIIOKi5nb29n bGUuY28uaW2CDiouZ29vZ2xlLmNvLmlugg4qLmdvb2dsZS5jby5qZYIOKi5nb29n bGUuY28uanCCDiouZ29vZ2xlLmNvLmtlgg4qLmdvb2dsZS5jby5rcoIOKi5nb29n bGUuY28ubHOCDiouZ29vZ2xlLmNvLm1hgg4qLmdvb2dsZS5jby5teoIOKi5nb29n bGUuY28ubnqCDiouZ29vZ2xlLmNvLnRogg4qLmdvb2dsZS5jby50eoIOKi5nb29n bGUuY28udWeCDiouZ29vZ2xlLmNvLnVrgg4qLmdvb2dsZS5jby51eoIOKi5nb29n bGUuY28udmWCDiouZ29vZ2xlLmNvLnZpgg4qLmdvb2dsZS5jby56YYIOKi5nb29n bGUuY28uem2CDiouZ29vZ2xlLmNvLnp3gg8qLmdvb2dsZS5jb20uYWaCDyouZ29v Z2xlLmNvbS5hZ4IPKi5nb29nbGUuY29tLmFpgg8qLmdvb2dsZS5jb20uYXKCDyou Z29vZ2xlLmNvbS5hdYIPKi5nb29nbGUuY29tLmJkgg8qLmdvb2dsZS5jb20uYmiC DyouZ29vZ2xlLmNvbS5iboIPKi5nb29nbGUuY29tLmJvgg8qLmdvb2dsZS5jb20u YnKCDyouZ29vZ2xlLmNvbS5ieYIPKi5nb29nbGUuY29tLmJ6gg8qLmdvb2dsZS5j b20uY26CDyouZ29vZ2xlLmNvbS5jb4IPKi5nb29nbGUuY29tLmN1gg8qLmdvb2ds ZS5jb20uY3mCDyouZ29vZ2xlLmNvbS5kb4IPKi5nb29nbGUuY29tLmVjgg8qLmdv b2dsZS5jb20uZWeCDyouZ29vZ2xlLmNvbS5ldIIPKi5nb29nbGUuY29tLmZqgg8q Lmdvb2dsZS5jb20uZ2WCDyouZ29vZ2xlLmNvbS5naIIPKi5nb29nbGUuY29tLmdp gg8qLmdvb2dsZS5jb20uZ3KCDyouZ29vZ2xlLmNvbS5ndIIPKi5nb29nbGUuY29t Lmhrgg8qLmdvb2dsZS5jb20uaXGCDyouZ29vZ2xlLmNvbS5qbYIPKi5nb29nbGUu Y29tLmpvgg8qLmdvb2dsZS5jb20ua2iCDyouZ29vZ2xlLmNvbS5rd4IPKi5nb29n bGUuY29tLmxigg8qLmdvb2dsZS5jb20ubHmCDyouZ29vZ2xlLmNvbS5tdIIPKi5n b29nbGUuY29tLm14gg8qLmdvb2dsZS5jb20ubXmCDyouZ29vZ2xlLmNvbS5uYYIP Ki5nb29nbGUuY29tLm5mgg8qLmdvb2dsZS5jb20ubmeCDyouZ29vZ2xlLmNvbS5u aYIPKi5nb29nbGUuY29tLm5wgg8qLmdvb2dsZS5jb20ubnKCDyouZ29vZ2xlLmNv bS5vbYIPKi5nb29nbGUuY29tLnBhgg8qLmdvb2dsZS5jb20ucGWCDyouZ29vZ2xl LmNvbS5waIIPKi5nb29nbGUuY29tLnBrgg8qLmdvb2dsZS5jb20ucGyCDyouZ29v Z2xlLmNvbS5wcoIPKi5nb29nbGUuY29tLnB5gg8qLmdvb2dsZS5jb20ucWGCDyou Z29vZ2xlLmNvbS5ydYIPKi5nb29nbGUuY29tLnNhgg8qLmdvb2dsZS5jb20uc2KC DyouZ29vZ2xlLmNvbS5zZ4IPKi5nb29nbGUuY29tLnNsgg8qLmdvb2dsZS5jb20u c3aCDyouZ29vZ2xlLmNvbS50aoIPKi5nb29nbGUuY29tLnRugg8qLmdvb2dsZS5j b20udHKCDyouZ29vZ2xlLmNvbS50d4IPKi5nb29nbGUuY29tLnVhgg8qLmdvb2ds ZS5jb20udXmCDyouZ29vZ2xlLmNvbS52Y4IPKi5nb29nbGUuY29tLnZlgg8qLmdv b2dsZS5jb20udm6CCyouZ29vZ2xlLmN2ggsqLmdvb2dsZS5jeoILKi5nb29nbGUu ZGWCCyouZ29vZ2xlLmRqggsqLmdvb2dsZS5ka4ILKi5nb29nbGUuZG2CCyouZ29v Z2xlLmR6ggsqLmdvb2dsZS5lZYILKi5nb29nbGUuZXOCCyouZ29vZ2xlLmZpggsq Lmdvb2dsZS5mbYILKi5nb29nbGUuZnKCCyouZ29vZ2xlLmdhggsqLmdvb2dsZS5n ZYILKi5nb29nbGUuZ2eCCyouZ29vZ2xlLmdsggsqLmdvb2dsZS5nbYILKi5nb29n bGUuZ3CCCyouZ29vZ2xlLmdyggsqLmdvb2dsZS5neYILKi5nb29nbGUuaGuCCyou Z29vZ2xlLmhuggsqLmdvb2dsZS5ocoILKi5nb29nbGUuaHSCCyouZ29vZ2xlLmh1 ggsqLmdvb2dsZS5pZYILKi5nb29nbGUuaW2CDSouZ29vZ2xlLmluZm+CCyouZ29v Z2xlLmlxggsqLmdvb2dsZS5pc4ILKi5nb29nbGUuaXSCDiouZ29vZ2xlLml0LmFv ggsqLmdvb2dsZS5qZYILKi5nb29nbGUuam+CDSouZ29vZ2xlLmpvYnOCCyouZ29v Z2xlLmpwggsqLmdvb2dsZS5rZ4ILKi5nb29nbGUua2mCCyouZ29vZ2xlLmt6ggsq Lmdvb2dsZS5sYYILKi5nb29nbGUubGmCCyouZ29vZ2xlLmxrggsqLmdvb2dsZS5s dIILKi5nb29nbGUubHWCCyouZ29vZ2xlLmx2ggsqLmdvb2dsZS5tZIILKi5nb29n bGUubWWCCyouZ29vZ2xlLm1nggsqLmdvb2dsZS5ta4ILKi5nb29nbGUubWyCCyou Z29vZ2xlLm1uggsqLmdvb2dsZS5tc4ILKi5nb29nbGUubXWCCyouZ29vZ2xlLm12 ggsqLmdvb2dsZS5td4ILKi5nb29nbGUubmWCDiouZ29vZ2xlLm5lLmpwggwqLmdv b2dsZS5uZXSCCyouZ29vZ2xlLm5sggsqLmdvb2dsZS5ub4ILKi5nb29nbGUubnKC CyouZ29vZ2xlLm51gg8qLmdvb2dsZS5vZmYuYWmCCyouZ29vZ2xlLnBrggsqLmdv b2dsZS5wbIILKi5nb29nbGUucG6CCyouZ29vZ2xlLnBzggsqLmdvb2dsZS5wdIIL Ki5nb29nbGUucm+CCyouZ29vZ2xlLnJzggsqLmdvb2dsZS5ydYILKi5nb29nbGUu cneCCyouZ29vZ2xlLnNjggsqLmdvb2dsZS5zZYILKi5nb29nbGUuc2iCCyouZ29v Z2xlLnNpggsqLmdvb2dsZS5za4ILKi5nb29nbGUuc22CCyouZ29vZ2xlLnNuggsq Lmdvb2dsZS5zb4ILKi5nb29nbGUuc3SCCyouZ29vZ2xlLnRkggsqLmdvb2dsZS50 Z4ILKi5nb29nbGUudGuCCyouZ29vZ2xlLnRsggsqLmdvb2dsZS50bYILKi5nb29n bGUudG6CCyouZ29vZ2xlLnRvggsqLmdvb2dsZS50cIILKi5nb29nbGUudHSCCyou Z29vZ2xlLnVzggsqLmdvb2dsZS51eoILKi5nb29nbGUudmeCCyouZ29vZ2xlLnZ1 ggsqLmdvb2dsZS53c4IJZ29vZ2xlLmFjgglnb29nbGUuYWSCCWdvb2dsZS5hZYIJ Z29vZ2xlLmFmgglnb29nbGUuYWeCCWdvb2dsZS5hbIIJZ29vZ2xlLmFtgglnb29n bGUuYXOCCWdvb2dsZS5hdIIJZ29vZ2xlLmF6gglnb29nbGUuYmGCCWdvb2dsZS5i ZYIJZ29vZ2xlLmJmgglnb29nbGUuYmeCCWdvb2dsZS5iaYIJZ29vZ2xlLmJqggln b29nbGUuYnOCCWdvb2dsZS5ieYIJZ29vZ2xlLmNhggpnb29nbGUuY2F0gglnb29n bGUuY2OCCWdvb2dsZS5jZIIJZ29vZ2xlLmNmgglnb29nbGUuY2eCCWdvb2dsZS5j aIIJZ29vZ2xlLmNpgglnb29nbGUuY2yCCWdvb2dsZS5jbYIJZ29vZ2xlLmNuggxn b29nbGUuY28uYW+CDGdvb2dsZS5jby5id4IMZ29vZ2xlLmNvLmNrggxnb29nbGUu Y28uY3KCDGdvb2dsZS5jby5odYIMZ29vZ2xlLmNvLmlkggxnb29nbGUuY28uaWyC DGdvb2dsZS5jby5pbYIMZ29vZ2xlLmNvLmluggxnb29nbGUuY28uamWCDGdvb2ds ZS5jby5qcIIMZ29vZ2xlLmNvLmtlggxnb29nbGUuY28ua3KCDGdvb2dsZS5jby5s c4IMZ29vZ2xlLmNvLm1hggxnb29nbGUuY28ubXqCDGdvb2dsZS5jby5ueoIMZ29v Z2xlLmNvLnRoggxnb29nbGUuY28udHqCDGdvb2dsZS5jby51Z4IMZ29vZ2xlLmNv LnVrggxnb29nbGUuY28udXqCDGdvb2dsZS5jby52ZYIMZ29vZ2xlLmNvLnZpggxn b29nbGUuY28uemGCDGdvb2dsZS5jby56bYIMZ29vZ2xlLmNvLnp3gg1nb29nbGUu Y29tLmFmgg1nb29nbGUuY29tLmFngg1nb29nbGUuY29tLmFpgg1nb29nbGUuY29t LmFygg1nb29nbGUuY29tLmF1gg1nb29nbGUuY29tLmJkgg1nb29nbGUuY29tLmJo gg1nb29nbGUuY29tLmJugg1nb29nbGUuY29tLmJvgg1nb29nbGUuY29tLmJygg1n b29nbGUuY29tLmJ5gg1nb29nbGUuY29tLmJ6gg1nb29nbGUuY29tLmNugg1nb29n bGUuY29tLmNvgg1nb29nbGUuY29tLmN1gg1nb29nbGUuY29tLmN5gg1nb29nbGUu Y29tLmRvgg1nb29nbGUuY29tLmVjgg1nb29nbGUuY29tLmVngg1nb29nbGUuY29t LmV0gg1nb29nbGUuY29tLmZqgg1nb29nbGUuY29tLmdlgg1nb29nbGUuY29tLmdo gg1nb29nbGUuY29tLmdpgg1nb29nbGUuY29tLmdygg1nb29nbGUuY29tLmd0gg1n b29nbGUuY29tLmhrgg1nb29nbGUuY29tLmlxgg1nb29nbGUuY29tLmptgg1nb29n bGUuY29tLmpvgg1nb29nbGUuY29tLmtogg1nb29nbGUuY29tLmt3gg1nb29nbGUu Y29tLmxigg1nb29nbGUuY29tLmx5gg1nb29nbGUuY29tLm10gg1nb29nbGUuY29t Lm14gg1nb29nbGUuY29tLm15gg1nb29nbGUuY29tLm5hgg1nb29nbGUuY29tLm5m gg1nb29nbGUuY29tLm5ngg1nb29nbGUuY29tLm5pgg1nb29nbGUuY29tLm5wgg1n b29nbGUuY29tLm5ygg1nb29nbGUuY29tLm9tgg1nb29nbGUuY29tLnBhgg1nb29n bGUuY29tLnBlgg1nb29nbGUuY29tLnBogg1nb29nbGUuY29tLnBrgg1nb29nbGUu Y29tLnBsgg1nb29nbGUuY29tLnBygg1nb29nbGUuY29tLnB5gg1nb29nbGUuY29t LnFhgg1nb29nbGUuY29tLnJ1gg1nb29nbGUuY29tLnNhgg1nb29nbGUuY29tLnNi gg1nb29nbGUuY29tLnNngg1nb29nbGUuY29tLnNsgg1nb29nbGUuY29tLnN2gg1n b29nbGUuY29tLnRqgg1nb29nbGUuY29tLnRugg1nb29nbGUuY29tLnRygg1nb29n bGUuY29tLnR3gg1nb29nbGUuY29tLnVhgg1nb29nbGUuY29tLnV5gg1nb29nbGUu Y29tLnZjgg1nb29nbGUuY29tLnZlgg1nb29nbGUuY29tLnZugglnb29nbGUuY3aC CWdvb2dsZS5jeoIJZ29vZ2xlLmRlgglnb29nbGUuZGqCCWdvb2dsZS5ka4IJZ29v Z2xlLmRtgglnb29nbGUuZHqCCWdvb2dsZS5lZYIJZ29vZ2xlLmVzgglnb29nbGUu ZmmCCWdvb2dsZS5mbYIJZ29vZ2xlLmZygglnb29nbGUuZ2GCCWdvb2dsZS5nZYIJ Z29vZ2xlLmdngglnb29nbGUuZ2yCCWdvb2dsZS5nbYIJZ29vZ2xlLmdwgglnb29n bGUuZ3KCCWdvb2dsZS5neYIJZ29vZ2xlLmhrgglnb29nbGUuaG6CCWdvb2dsZS5o coIJZ29vZ2xlLmh0gglnb29nbGUuaHWCCWdvb2dsZS5pZYIJZ29vZ2xlLmltggtn b29nbGUuaW5mb4IJZ29vZ2xlLmlxgglnb29nbGUuaXOCCWdvb2dsZS5pdIIMZ29v Z2xlLml0LmFvgglnb29nbGUuamWCCWdvb2dsZS5qb4ILZ29vZ2xlLmpvYnOCCWdv b2dsZS5qcIIJZ29vZ2xlLmtngglnb29nbGUua2mCCWdvb2dsZS5reoIJZ29vZ2xl Lmxhgglnb29nbGUubGmCCWdvb2dsZS5sa4IJZ29vZ2xlLmx0gglnb29nbGUubHWC CWdvb2dsZS5sdoIJZ29vZ2xlLm1kgglnb29nbGUubWWCCWdvb2dsZS5tZ4IJZ29v Z2xlLm1rgglnb29nbGUubWyCCWdvb2dsZS5tboIJZ29vZ2xlLm1zgglnb29nbGUu bXWCCWdvb2dsZS5tdoIJZ29vZ2xlLm13gglnb29nbGUubmWCDGdvb2dsZS5uZS5q cIIKZ29vZ2xlLm5ldIIJZ29vZ2xlLm5sgglnb29nbGUubm+CCWdvb2dsZS5ucoIJ Z29vZ2xlLm51gg1nb29nbGUub2ZmLmFpgglnb29nbGUucGuCCWdvb2dsZS5wbIIJ Z29vZ2xlLnBugglnb29nbGUucHOCCWdvb2dsZS5wdIIJZ29vZ2xlLnJvgglnb29n bGUucnOCCWdvb2dsZS5ydYIJZ29vZ2xlLnJ3gglnb29nbGUuc2OCCWdvb2dsZS5z ZYIJZ29vZ2xlLnNogglnb29nbGUuc2mCCWdvb2dsZS5za4IJZ29vZ2xlLnNtggln b29nbGUuc26CCWdvb2dsZS5zb4IJZ29vZ2xlLnN0gglnb29nbGUudGSCCWdvb2ds ZS50Z4IJZ29vZ2xlLnRrgglnb29nbGUudGyCCWdvb2dsZS50bYIJZ29vZ2xlLnRu gglnb29nbGUudG+CCWdvb2dsZS50cIIJZ29vZ2xlLnR0gglnb29nbGUudXOCCWdv b2dsZS51eoIJZ29vZ2xlLnZngglnb29nbGUudnWCCWdvb2dsZS53czANBgkqhkiG 9w0BAQUFAAOBgQCROJdKT00d96BpNG4j3Xf5Kz7kJENMTYtgsGQW5E6y2yjRaguD LPO+y4IH9KiVXD+qO8koye9yOMNawN9r/DFQd+t2nDmvlpcwJBNguiuqxl+rJaU8 KKgswikGaaM4z+i4vHuXcCKZtM/ELAaJlSaBPip4GBAkgv7D9hwh+sWvYA== -----END CERTIFICATE----- node-sshpk-1.16.1/test/assets/id_dsa000066400000000000000000000012401342215657600173120ustar00rootroot00000000000000-----BEGIN DSA PRIVATE KEY----- MIIBvAIBAAKBgQDQRiXWx3U+Xf9bVN3dwsNR69vz6MmLJmhj/NsB/tmqStEaGTpk Hx5XP6Ms/cqK3RQf1YJXkfNNJuaySR9k78DKqYcOtdaBg7voUqleVBskASiMz34e JovVh2OK2epxxHgtkok+kCmRu3brQ71x5oway1PocAWPxXe6ATfT9EMbtwIVALT+ aN5LLwSfAy5SE7T3xBooFtgVAoGBALWYic/chgcE9b7KCzPd/KpFkmFO/KrHjql5 qVxYAovZ27V1r6yxRDALECFEwczZBMg1slQVPJXfcnL5Wo+Y3JTWkSfyS3Bssyv/ CO/P0L7YmP1ZEsS8cpjpCyN96v8l1p+clBFOR8gXYsiOHixb2EtrJcsWFqut2+jU 6/fZRQXeAoGBAItcldZqWy1ZyoLMLcFzYV3Q80vU2aFXWckDU7xPERsjSnmxIuvK SZGCpZZX6XqWn0zcdtu+AZGVZu1FOpV/g0cckpGi2ACtZ2XLGZ2IdMk0cTrZTmzX PBLxy5gBkO1CijIjGy2d5B4ojI9vAf5uTc+qY15qel1KzXuPgzP+zABmAhR5Ka7I RmcEdr9K068f2jbETwzO0Q== -----END DSA PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_dsa2000066400000000000000000000023101342215657600173730ustar00rootroot00000000000000-----BEGIN DSA PRIVATE KEY----- MIIDVgIBAAKCAQEAkaGyxxfZ5GVrRKkJhZfMd1+AhD2/RYM92xFQjPdZrSj19EpK x14i/OcZqQSBaGl7k9unilksXQz9OkI2+4b0TEIuLCnlacodJv/iMfVPFgD5DXIg GnbTkAKbDGJ7nQXvLPceqAU+jgg9RWdr09w7PFBqd/4kEkU064Len3nRG2bOdM1H k3uxelMBnGR3jWdoPZn4GhJNREwfgVAaT2Ivd6OKf1rUBdXNEt8SCvoVeZbF7O7E 5gmrJ+RZnXbHFOn3MK67T0E9dPdR9tvCb94uHxOyf4PKsVq8c3zgr5b/V3hJP7T7 RNigVjOZFfukS3AkjJxqy9klBRw/qEea4CUh7QIhAPsMq2jrY7BQe796yiJm1B1f 7TsrxhRepf7udUMG7ZTzAoIBAQCQjU/KGKMXh0I0Mn7V+EU4HgTaAV4lR8vplWud 8I3tCve9Tx/PfTh9nidDBN+FNYGxzifmV6JDXh1T2hOjL5aml4PsytPW4PA9385w 2HtYnGgTG1i5u4PDtH93xeaxRbF9H8QMPy0pCs/M4YeNDmcoExuJtAfTUDfhrx0T zF0Qj81LBPtoRn0SSIw2gl5xlL1ogepLnV7uLNLGBsA9y9dTgXNyNSjacrVWXSu6 ET8OhHz4Mf6ejHEYlb5C7Q0UEBBhdrIo03CQupAHs/lI5/RNq52KVho6CLnWwUB0 SM6zM3ZK58FbOft+uVRrBNJw6oO0OdE89Y8tEO72ti3QnQdyAoIBABbQZDAMxflA v6OqPP2aS4nwgOdg124+f62Yb1B9li9Yt3b/VfGcx0W+Q/k4+k5ZsSAU9AKiITBG 5ewgoR8PhMh3SdrRB4xGlF5bD5I/5ZSFGsKOEpKgeKx3VLU0+OMauVwiVJ/IfwCF xxGSOBIE7QX1W3X8C+jbpo2aUGOX644Bge3a3PWgsPdIVo6xfhTVH5VfYr8SUlS3 uNy2cFakoVsgBEUTACMMgLWf4NgwLLZvs2BchXUOV1MuhQ+2oTEiNEuX6e8I+TYc 1OaY6jrLClnurXLTahailaPBegkyyrLrQsFcjbRVP5ZIKSztgeaK8/xwRgk8+CPA R7bVA/Jts34CIBAVL14QdvTgXiKE1I86mQwWfIBWwROmVymNTvas7eo3 -----END DSA PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_dsa3000066400000000000000000000023101342215657600173740ustar00rootroot00000000000000-----BEGIN DSA PRIVATE KEY----- MIIDVgIBAAKCAQEAkaGyxxfZ5GVrRKkJhZfMd1+AhD2/RYM92xFQjPdZrSj19EpK x14i/OcZqQSBaGl7k9unilksXQz9OkI2+4b0TEIuLCnlacodJv/iMfVPFgD5DXIg GnbTkAKbDGJ7nQXvLPceqAU+jgg9RWdr09w7PFBqd/4kEkU064Len3nRG2bOdM1H k3uxelMBnGR3jWdoPZn4GhJNREwfgVAaT2Ivd6OKf1rUBdXNEt8SCvoVeZbF7O7E 5gmrJ+RZnXbHFOn3MK67T0E9dPdR9tvCb94uHxOyf4PKsVq8c3zgr5b/V3hJP7T7 RNigVjOZFfukS3AkjJxqy9klBRw/qEea4CUh7QIhAPsMq2jrY7BQe796yiJm1B1f 7TsrxhRepf7udUMG7ZTzAoIBAQCQjU/KGKMXh0I0Mn7V+EU4HgTaAV4lR8vplWud 8I3tCve9Tx/PfTh9nidDBN+FNYGxzifmV6JDXh1T2hOjL5aml4PsytPW4PA9385w 2HtYnGgTG1i5u4PDtH93xeaxRbF9H8QMPy0pCs/M4YeNDmcoExuJtAfTUDfhrx0T zF0Qj81LBPtoRn0SSIw2gl5xlL1ogepLnV7uLNLGBsA9y9dTgXNyNSjacrVWXSu6 ET8OhHz4Mf6ejHEYlb5C7Q0UEBBhdrIo03CQupAHs/lI5/RNq52KVho6CLnWwUB0 SM6zM3ZK58FbOft+uVRrBNJw6oO0OdE89Y8tEO72ti3QnQdyAoIBAESsDh8jMSuj BGKdRnvst22GUy+QxzNQgCIXrLkuTPY0y8Cm/nOoYp6g3lbffItT8HwVZH1OCv7I TrIppgZRnAQDIg3yEjqxWkWiLWNmvRtzJRx8jZ1udC0hprdQksskCW5kJCUAUInd gnDDCgCMI3bEJbzE9OrSmyB3jNbvr0+LlMjjLtAmuOu7k4/194OB964I6+K01tmT 5cq9L/0SrBzhSWRmYWepw3GOYgOGSjgJ8W+85y9cvBvLCjT33JWV/Hjkl5yxBlMt vcPHhP5mPaYQlqg65+T/Tw8XhCGjmTs5wu+8T2gq3JA5Ra38fkfcPPwOaBrdpMkx jRk5tkPeTVkCIFxdP5feum/mTjLPYSGm3X8sOStPIKiXA1xWhO2HVX4a -----END DSA PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_dsa8000066400000000000000000000007751342215657600174160ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBANBGJdbHdT5d/1tU3d3Cw1Hr2/Po yYsmaGP82wH+2apK0RoZOmQfHlc/oyz9yordFB/VgleR800m5rJJH2TvwMqphw61 1oGDu+hSqV5UGyQBKIzPfh4mi9WHY4rZ6nHEeC2SiT6QKZG7dutDvXHmjBrLU+hw BY/Fd7oBN9P0Qxu3AhUAtP5o3ksvBJ8DLlITtPfEGigW2BUCgYEAtZiJz9yGBwT1 vsoLM938qkWSYU78qseOqXmpXFgCi9nbtXWvrLFEMAsQIUTBzNkEyDWyVBU8ld9y cvlaj5jclNaRJ/JLcGyzK/8I78/QvtiY/VkSxLxymOkLI33q/yXWn5yUEU5HyBdi yI4eLFvYS2slyxYWq63b6NTr99lFBd4EFgIUeSmuyEZnBHa/StOvH9o2xE8MztE= -----END PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_ecdsa000066400000000000000000000004401342215657600176230ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- MIGkAgEBBDCNOaMOKbtjXYQykwv+FCUUi2jd5ojUv4QZ3BhoBPEse3uEaSlWrYSy NnxiulPa3TegBwYFK4EEACKhZANiAAQIVUh8EgyMx3mJtkVSYQiH8eG+sK8Wvt8s 6y9r3XaHgnRNoZ4ccvY64dcVgdFFOhn1tlIj7mQYh1ptmIIxd8jtpNi/uBPy4w3N lvD2oCnA/3VnEnBM6QaKS+EK92HMyYM= -----END EC PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_ecdsa2000066400000000000000000000003431342215657600177070ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- MHcCAQEEIPW9rvKT8InuuPgS0vnxvVg9jceruVYxF6ymvutCrJq5oAoGCCqGSM49 AwEHoUQDQgAEr36EUZVn1FPrWmDy3sQaCS926E+v8IFh/H7mtAURE6PwSOSgYgfb HKkc4cHPRaKQrmFhzBMzlgy+c3G5TSHj5w== -----END EC PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_ecdsa3000066400000000000000000000003431342215657600177100ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- MHcCAQEEIElpEce7IBpLPhhJplazlzUu79ArwCGgOpXtDibgoiIcoAoGCCqGSM49 AwEHoUQDQgAEgk/N0KnqJNE0vPe3Ke/rh6zaJUx22jSs1jEwm6WWyCV/6kcnDMZv KfyqtVuLhhx6laP6vuKcd//YgKWE5oqDPA== -----END EC PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_ecdsa8000066400000000000000000000004621342215657600177170ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCNOaMOKbtjXYQykwv+ FCUUi2jd5ojUv4QZ3BhoBPEse3uEaSlWrYSyNnxiulPa3TehZANiAAQIVUh8EgyM x3mJtkVSYQiH8eG+sK8Wvt8s6y9r3XaHgnRNoZ4ccvY64dcVgdFFOhn1tlIj7mQY h1ptmIIxd8jtpNi/uBPy4w3NlvD2oCnA/3VnEnBM6QaKS+EK92HMyYM= -----END PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_ecdsa_enc000066400000000000000000000011021342215657600204440ustar00rootroot00000000000000-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABCxRf8+2g kOoRguCgCcgocnAAAAEAAAAAEAAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlz dHAyNTYAAABBBJIH5wFP3F6cuSwYBr0L1PdH+sL3uNIwpLlXF3OaUUIt1omTUKaGZ79vFb tIH5A78WRmEdLMLi6EA5Hy6AI5YNEAAADAJsEFTLkiT/A2Vfer0iK3rGtvNrjuuuYGS8VV xRenc9N4QFNtUHMbNoqTriyLplAU5/LwEAJ9kXtdCkvcpFjW3h6OqG9ttvSiyrfk/84ULG raqvAuBdyEK6T8iuo4f62r7kdJxGQMJM52LtKaU/E2aPFadwTDfeQY8W53AFKIplHyG4Hj 5LOSvoDzkMZgMxqCLHyEqAenPwj9OjIJ7ff60Mk6dJs+RmFynAEGYI3d3oviIRNvYJdjhv lAAFohORH6 -----END OPENSSH PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_ecdsa_exp000066400000000000000000000010541342215657600205010ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- MIIBaAIBAQQgfWnzITQ2ccYyf3NGOr56Lv742w7h9bDKGarDL8Tj0ByggfowgfcC AQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA//////////////// MFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57Pr vVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEE axfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54W K84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8 YyVRAgEBoUQDQgAEOSFT+KQbnCLPSpSkmxmIXxTUkA8Q/aMP2QJ2bY6cTDbegg81 Yo/PKMtYKkn1Tu+vD8ZjVBL8g2qjbMpc0yryIQ== -----END EC PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_ecdsa_pkcs8_enc000066400000000000000000000007041342215657600215630ustar00rootroot00000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIBEzBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQI8ss6mjBMp84CAggA MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECPYbjSRfW4DmBIHAczs2+q5pZYOv XHiGkWmOU7bAoLFbQy12vsswU/4wAZlm5/MNooJKQBx2cEDYKPQhhOoC6usARTnP WaEqEkk++bTWc/JfQMJRHTWZwF7YIIA6J3VP11uRTyDiZeorGOr5qlUzwILZoT63 d+EUI7SfkQA6c2zEEYqZWYA+tB+ptztUsxmkiREfR3IOB3IWr63IbCsDmdt9/gny 47CRD5hnJxTkjWqsNBI8ZerlBgAjInKWx1vMkx7q+GZjZHcDp62r -----END ENCRYPTED PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_ecdsa_pkcs8_enc2000066400000000000000000000007201342215657600216430ustar00rootroot00000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIBHDBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQILKyFq/D9ok4CAggA MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBBIrV2g9Fy0mn+DhZKJN6EdBIHA myZhhrYCTj58V3Je3Mn3H0dDY4o5rK1Mu+LOCFTQqjArO0FLsw6d/Xv5jmbT8Bq9 VZgmTrY1V+SHa1dVrEG4YnAXjorOVcEYxdUkpzkmJVl/vP2HYx0PFrL81+sDp2Ua 6SmX5ZE11Tq05y4oL+AQQJzAyf4BNAbUSjgd/83WE1pA4qeYE+nzEy26yrozWlLc CJL8oq1DvubHOQX3HL4K68sU55M/i3tKLUFfz8e2KN0H8w3j8YgmF/pjn/t7kdAU -----END ENCRYPTED PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_ecdsa_pkcs8_enc3000066400000000000000000000007001342215657600216420ustar00rootroot00000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIBDjBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQI7mY+aVq9o5gCAgKa MB0GCWCGSAFlAwQBKgQQT5Y7S7LPoiJCYvKaOTKpIwSBwAdB+Y0Nr3YEkiQsOqMc uLWM1QnVy7XOuv1ePOeU8oWZEp/YTX8xu1lRMrNOAdwXI99p+4aNCDEhyGPedi+7 6/fDsLD0NRpBchrRTJG2ZdTNF2ayABuDCoc39tGk1NwTNNQEJD1qIu46OJtbUca/ OfZBmuJS7JY7jZRwSpwyUlo9KfAn0ufleGQNOEF856uhVWjYt1ZPLhg0N+hC568+ w8Sk42ViF/kRid6EQI+1i4syqofWHSJHbLYxmqIS7Fv59Q== -----END ENCRYPTED PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_ed25519000066400000000000000000000006431342215657600175470ustar00rootroot00000000000000-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW QyNTUxOQAAACBItKZHz3v/pG5p00h9Jn69CeBauzO27IRQCgergsiw5gAAAKAcKylwHCsp cAAAAAtzc2gtZWQyNTUxOQAAACBItKZHz3v/pG5p00h9Jn69CeBauzO27IRQCgergsiw5g AAAEBEaF9oi0FmKnEBKpaATCCBV/XP6cp7uFt8tt8ENXK9YEi0pkfPe/+kbmnTSH0mfr0J 4Fq7M7bshFAKB6uCyLDmAAAAHWFsZXgud2lsc29uQGF3aWxzb24tbWJwLmxvY2Fs -----END OPENSSH PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_ed25519.pem000066400000000000000000000002641342215657600203260ustar00rootroot00000000000000-----BEGIN EdDSA PRIVATE KEY----- MFECAQEEIERoX2iLQWYqcQEqloBMIIFX9c/pynu4W3y23wQ1cr1goAUGAytlcKEj AyEASLSmR897/6RuadNIfSZ+vQngWrsztuyEUAoHq4LIsOY= -----END EdDSA PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_ed25519.pub000066400000000000000000000001571342215657600203340ustar00rootroot00000000000000ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEi0pkfPe/+kbmnTSH0mfr0J4Fq7M7bshFAKB6uCyLDm alex.wilson@awilson-mbp.local node-sshpk-1.16.1/test/assets/id_ed255192000066400000000000000000000006431342215657600176310ustar00rootroot00000000000000-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW QyNTUxOQAAACDdMFL6rLlROgXMIxuET/u7O23buNjC8e7QgpVqvSxTAAAAAKD0dTLu9HUy 7gAAAAtzc2gtZWQyNTUxOQAAACDdMFL6rLlROgXMIxuET/u7O23buNjC8e7QgpVqvSxTAA AAAEAUXDO6pxLSslECmp3beDxMFE8p0anVZIcyDYvkVhUXPt0wUvqsuVE6BcwjG4RP+7s7 bdu42MLx7tCClWq9LFMAAAAAHWFsZXgud2lsc29uQGF3aWxzb24tbWJwLmxvY2Fs -----END OPENSSH PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_rsa000066400000000000000000000015671342215657600173440ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQDVml3YDVqimFyVgK8rgEEitA++Gq67rXqvKV40V5GlT7OGQL+i 0zrX8ikLR8IpCvVcs37F78KohF9wDj854nkcUCbNh0Jihor3I5aYlpvEFlO4S8nj Vw9KOrY+L9/0ALRAK6UO96gTwROW5o/8gtyDxUJxEF2DiWzegumQJW1SNwIDAQAB AoGABTb/k4a/77hIil3Z6PX4oSBEQh/kpDBYDm60HhMFO0P23hA2nYMKrLr8xYm6 88WQt/Kp5as01Whl7BZs9LzSuBLQsnDfC+k9rv7lPK4La3bYX/T7y1V6Eypo8ITk UJgpGRNwUMzLGS9TVpLs+gnlJum7eSvkGP/ZODadRJU3EgECQQDwekZQSmCOh2b9 yX8XmzEV3zVotYx8IACqhitoNuc8tiGbvLqHZPzJ3Hgu6RY95xsaofnsyQNHRP78 WjdJ+r1bAkEA42QB2ALDM+s0iPbEfbTQFFIklvWRiCY5fFS5huMNVFykPHwhs3p0 BJJWCQD8NbpmSPcKcNEolkfc/gDBa4DJVQJBAKgqed1QBfHmEknLjMrvRgYrj2fn /ZQXtR+Kr/Qy4MX9/8au1io0nupy+MClU156rOOU/fduIpLGVyIV3LApXh0CQE9i usIPNNcLZmvquu6oEX0GsH+DfCtsLOWbLqpI2n55WV1EeP+P4LE35ZF/Jo4bZVpT 5PE+FE1jCWQkH2LIs4ECQQCO1JfuvJIyP/IOvjdC1mHdPdFh4ULdGJDb3Kegk3an pPaa0ju1qfQc1dWOapefdL+/o3ZGuFf55fhqIdS0OeYk -----END RSA PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_rsa2000066400000000000000000000034631342215657600174230ustar00rootroot00000000000000-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn NhAAAAAwEAAQAAAQEAsxwONcGQTXixn1ww8oB+Ta89lREjaFTKOXeSo8xHE2ET4zxEfseU 80hSGCE6I6iX6izGsWNaCipko4oEAN7ssZmy2Aa6HQJAJSZsNPWJm7HbycT+kJvAUEnGBX hk7NGU9q/qfUVG6Th7iinCtxLt/LVNhxcTQOUYrIAQcIeua44kPkQUep8r8+RdpYdYW6cQ SK0wPSQ3zIY1VhiCjovR+WIL0qRQ/19wcGMY7qbcOdYxivn60T1gM9F6toGCq5PW5nfx1Q CL7HbwoAZ950ntL8VCVKN/Mcz1nzuScMTKrjQPFbKqWUDSx45iAwgOFyDda3R3K+pL9VMD sFLw0MmzSQAAA9jdCyjh3Qso4QAAAAdzc2gtcnNhAAABAQCzHA41wZBNeLGfXDDygH5Nrz 2VESNoVMo5d5KjzEcTYRPjPER+x5TzSFIYITojqJfqLMaxY1oKKmSjigQA3uyxmbLYBrod AkAlJmw09YmbsdvJxP6Qm8BQScYFeGTs0ZT2r+p9RUbpOHuKKcK3Eu38tU2HFxNA5RisgB Bwh65rjiQ+RBR6nyvz5F2lh1hbpxBIrTA9JDfMhjVWGIKOi9H5YgvSpFD/X3BwYxjuptw5 1jGK+frRPWAz0Xq2gYKrk9bmd/HVAIvsdvCgBn3nSe0vxUJUo38xzPWfO5JwxMquNA8Vsq pZQNLHjmIDCA4XIN1rdHcr6kv1UwOwUvDQybNJAAAAAwEAAQAAAQBj5+ZVPd8MF6KcTYRQ ADRziKhFGgYyD/mtDHGTRELxIFlDiz55qUIAYfrI0t/nPAdg7BD4qX5z5Sm1vyp0geRtPF px/W6a98Jn9oKtF7jmS9NZPLTyXK5tGnmGW52QK2d4IrAdqCLhvEvMyXZ/P+PX7hmMnOZ0 cFXPArAo1MYJ35Pe/eum+W05bXWYm9JmYm1oi2fROu7KrZLFF8YCmWUPR6v/J3Ts9+DlPx lCjwCMnqRrKDhFLSrZvHRUrhJYRg25irlt3+rTNvucgFwnEq7feEIQx16LzUZQzaE8pmcp Dboaf+qivQ3IuBT///ZgTKON3XLjI3VdUam45S7P+NwBAAAAgAJkJHe0VKh+cn6jtmeGJM A4+RP322se//9mxFYLJ7fiT/ash7BjzagaWlu4X4kXQN2ypTbm8fAc4GRbCbN4DY9Usege 90b7yuh63zl3I5vZhX5mjUIU+zQdyvPQyseAiBY5RhYO9XrqV/xzROIL3FP11QDTpLgsoC nz3i2cJSOSAAAAgQDntSkBZNiO7Wi69+IVmS9uv54ar70xptzUT1CjV7bYTHoNTGrdAdRg xg7BdR+VhD5pfS3Q46p9ECmSNJ5k+0/1JkSTFN/Fgfm202s4ZV1XKejxbNO+UWoiCEmehR 0X5kKmKwQuJHHnd3ECZdZZOJ646aFVXORmd2oQvEU09x85KQAAAIEAxeM1DQ5msxQiSNuh ispjjEgYBHXv8hRR3CXT+rSGbrtpRhpMePk5SBntt4QAxQuYR0VeVV1Us2oxy8JhriEJtx 6gF1gcWCO3+Ysy+puegOMMSh6QiRUwh82YuIwqUZyhafrGNAd8wcJOTFA2APKLMQLIvAJ2 3VW/cTZzBs1CTSEAAAAdYWxleC53aWxzb25AYXdpbHNvbi1tYnAubG9jYWwBAgMEBQY= -----END OPENSSH PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_rsa8000066400000000000000000000016241342215657600174260ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANWaXdgNWqKYXJWA ryuAQSK0D74arruteq8pXjRXkaVPs4ZAv6LTOtfyKQtHwikK9VyzfsXvwqiEX3AO PznieRxQJs2HQmKGivcjlpiWm8QWU7hLyeNXD0o6tj4v3/QAtEArpQ73qBPBE5bm j/yC3IPFQnEQXYOJbN6C6ZAlbVI3AgMBAAECgYAFNv+Thr/vuEiKXdno9fihIERC H+SkMFgObrQeEwU7Q/beEDadgwqsuvzFibrzxZC38qnlqzTVaGXsFmz0vNK4EtCy cN8L6T2u/uU8rgtrdthf9PvLVXoTKmjwhORQmCkZE3BQzMsZL1NWkuz6CeUm6bt5 K+QY/9k4Np1ElTcSAQJBAPB6RlBKYI6HZv3JfxebMRXfNWi1jHwgAKqGK2g25zy2 IZu8uodk/MnceC7pFj3nGxqh+ezJA0dE/vxaN0n6vVsCQQDjZAHYAsMz6zSI9sR9 tNAUUiSW9ZGIJjl8VLmG4w1UXKQ8fCGzenQEklYJAPw1umZI9wpw0SiWR9z+AMFr gMlVAkEAqCp53VAF8eYSScuMyu9GBiuPZ+f9lBe1H4qv9DLgxf3/xq7WKjSe6nL4 wKVTXnqs45T9924iksZXIhXcsCleHQJAT2K6wg801wtma+q67qgRfQawf4N8K2ws 5ZsuqkjafnlZXUR4/4/gsTflkX8mjhtlWlPk8T4UTWMJZCQfYsizgQJBAI7Ul+68 kjI/8g6+N0LWYd090WHhQt0YkNvcp6CTdqek9prSO7Wp9BzV1Y5ql590v7+jdka4 V/nl+Goh1LQ55iQ= -----END PRIVATE KEY----- node-sshpk-1.16.1/test/assets/id_rsa_o000066400000000000000000000020651342215657600176540ustar00rootroot00000000000000-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAmQAAAAdzc2gtcn NhAAAAAwEAAQAAAIMKgR1iX5uS85yGwyVakn7PmO8JF28phKeP/oLtb1KZIvNj9iUot7Ql pvsIIW0hAIrldajTN9AK/acmwp/whfFHjHVlJymw0ckm6WkOsY0j+yVxXHcHmOsOcQGVo/ t5REqQFU72Q276zaIvY74qjuS7ToLW2w2sezEzicGMD6pkmvLw4QAAAiDG7ds0xu3bNAAA AAdzc2gtcnNhAAAAgwqBHWJfm5LznIbDJVqSfs+Y7wkXbymEp4/+gu1vUpki82P2JSi3tC Wm+wghbSEAiuV1qNM30Ar9pybCn/CF8UeMdWUnKbDRySbpaQ6xjSP7JXFcdweY6w5xAZWj +3lESpAVTvZDbvrNoi9jviqO5LtOgtbbDax7MTOJwYwPqmSa8vDhAAAAAwEAAQAAAIMGaI AxnFv/iUirWe+20no0UXs6E6bIMFo82SqsiOZd79mF2QsQTQnEkprAegvmPzt9AouM15a+ rcHEPqVuCXiJip256SmekmYoNQF60DzdAVmvAZL3BlSBh5YSesyqxrRVSVdZ/JOMHt83RZ WJY1ssjCaqF3NaY1TdDz35jVaSZF9hwQAAAEICNCv1JsBVFxlxYI+eQAv1sw1cW9d7xEIu Tcj35WrCF/Gs/cJmAk1OqLO2Ts/v3SmBtGDivT5SJDCjxzQCKNBkf9oAAABCA2qT6tU1Nz 3+jMNWrdUt7sD8339RBlvPGxx9xfSDP+Zd4/boNq9DuulbLNFoXDwJmfZ1rdISCpcfEUh9 fSuMFQQZAAAAQgMTI1Elin7z9ImbTHr21dPk5v2mjxXa1ibSyUfg+YWtoX1ndRqecUz/ba xK3A/tsaazFlupA2emjVXNl8w38b2sCQAAAB1hbGV4LndpbHNvbkBhd2lsc29uLW1icC5s b2NhbAECAwQF -----END OPENSSH PRIVATE KEY----- node-sshpk-1.16.1/test/assets/jim-openssh.pub000066400000000000000000000014451342215657600211170ustar00rootroot00000000000000ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgjP3tdayWI31bxhQEtB/QwEdVPw0a4T8OKM1/ZNVpptMAAAADAQABAAAAgQDVml3YDVqimFyVgK8rgEEitA++Gq67rXqvKV40V5GlT7OGQL+i0zrX8ikLR8IpCvVcs37F78KohF9wDj854nkcUCbNh0Jihor3I5aYlpvEFlO4S8njVw9KOrY+L9/0ALRAK6UO96gTwROW5o/8gtyDxUJxEF2DiWzegumQJW1SNwAAAAAAAAAAAAAAAgAAAAZqaW1rZXkAAAALAAAAB2ppbS5jb20AAAAAV5Fv1AAAAABZcVI2AAAAAAAAAAAAAAAAAAAAlwAAAAdzc2gtcnNhAAAAAwEAAQAAAIEA1Zpd2A1aophclYCvK4BBIrQPvhquu616ryleNFeRpU+zhkC/otM61/IpC0fCKQr1XLN+xe/CqIRfcA4/OeJ5HFAmzYdCYoaK9yOWmJabxBZTuEvJ41cPSjq2Pi/f9AC0QCulDveoE8ETluaP/ILcg8VCcRBdg4ls3oLpkCVtUjcAAACPAAAAB3NzaC1yc2EAAACAASHTzs/SOITFA9bhATC751bYIaJbg0u7xbP+RaFfczDMbnYTB2fD3ddjjJy/HlEdZ0Jb4y1och2n7FEPzxY/vmZNh7dFDc7Ii8NMcDEdkk5Vg7wXijJFtQtPlyaWdNpaJSqD+mV0/WuAgcQo/5o6oyz5l132JWuqM162aU/28vg= id_rsa node-sshpk-1.16.1/test/assets/jim-x509-text.pem000066400000000000000000000044001342215657600211140ustar00rootroot00000000000000Certificate: Data: Version: 1 (0x0) Serial Number: ab:fd:52:3c:3e:52:c0:7b Signature Algorithm: sha1WithRSAEncryption Issuer: DC = jim, DC = com Validity Not Before: Jul 22 01:04:26 2016 GMT Not After : Jul 22 01:04:26 2017 GMT Subject: DC = jim, DC = com Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (1024 bit) Modulus: 00:d5:9a:5d:d8:0d:5a:a2:98:5c:95:80:af:2b:80: 41:22:b4:0f:be:1a:ae:bb:ad:7a:af:29:5e:34:57: 91:a5:4f:b3:86:40:bf:a2:d3:3a:d7:f2:29:0b:47: c2:29:0a:f5:5c:b3:7e:c5:ef:c2:a8:84:5f:70:0e: 3f:39:e2:79:1c:50:26:cd:87:42:62:86:8a:f7:23: 96:98:96:9b:c4:16:53:b8:4b:c9:e3:57:0f:4a:3a: b6:3e:2f:df:f4:00:b4:40:2b:a5:0e:f7:a8:13:c1: 13:96:e6:8f:fc:82:dc:83:c5:42:71:10:5d:83:89: 6c:de:82:e9:90:25:6d:52:37 Exponent: 65537 (0x10001) Signature Algorithm: sha1WithRSAEncryption 10:53:47:a4:a6:91:97:6b:42:06:7e:8f:25:e1:46:56:ae:a0: 4e:84:38:db:ac:e8:76:2d:c4:81:53:4a:22:1c:1f:e9:58:70: 25:88:3c:bc:86:a5:d0:03:7a:eb:d7:b8:ab:72:6e:39:f2:85: 05:ba:91:07:bc:1d:ba:c9:08:8e:d6:e3:4b:41:c2:2e:5d:38: 86:a1:40:36:c5:c7:a9:82:36:1b:65:a8:67:d5:66:d8:4c:9b: 8a:16:d7:0d:c6:43:95:b2:af:83:9a:3d:f8:ca:f7:35:46:8a: f8:95:ca:a5:83:97:e8:3c:4f:1a:1f:63:8d:ae:81:b6:3f:03: 3b:79 -----BEGIN CERTIFICATE----- MIIByzCCATQCCQCr/VI8PlLAezANBgkqhkiG9w0BAQUFADAqMRMwEQYKCZImiZPy LGQBGRYDamltMRMwEQYKCZImiZPyLGQBGRYDY29tMB4XDTE2MDcyMjAxMDQyNloX DTE3MDcyMjAxMDQyNlowKjETMBEGCgmSJomT8ixkARkWA2ppbTETMBEGCgmSJomT 8ixkARkWA2NvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1Zpd2A1aophc lYCvK4BBIrQPvhquu616ryleNFeRpU+zhkC/otM61/IpC0fCKQr1XLN+xe/CqIRf cA4/OeJ5HFAmzYdCYoaK9yOWmJabxBZTuEvJ41cPSjq2Pi/f9AC0QCulDveoE8ET luaP/ILcg8VCcRBdg4ls3oLpkCVtUjcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQAQ U0ekppGXa0IGfo8l4UZWrqBOhDjbrOh2LcSBU0oiHB/pWHAliDy8hqXQA3rr17ir cm458oUFupEHvB26yQiO1uNLQcIuXTiGoUA2xcepgjYbZahn1WbYTJuKFtcNxkOV sq+Dmj34yvc1Ror4lcqlg5foPE8aH2ONroG2PwM7eQ== -----END CERTIFICATE----- node-sshpk-1.16.1/test/assets/jim-x509-utf8.pem000066400000000000000000000013211342215657600210150ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIB5zCCAVACCQDOUqSuHM0PuzANBgkqhkiG9w0BAQsFADA4MQ0wCwYDVQQKDAR0 ZXN0MQ8wDQYDVQQLDAZmb29iYXIxFjAUBgNVBAMMDWEgdGVzdCBzdHJpbmcwHhcN MTcxMjA4MDA0NzA3WhcNMjcxMjA2MDA0NzA3WjA4MQ0wCwYDVQQKDAR0ZXN0MQ8w DQYDVQQLDAZmb29iYXIxFjAUBgNVBAMMDWEgdGVzdCBzdHJpbmcwgZ8wDQYJKoZI hvcNAQEBBQADgY0AMIGJAoGBANWaXdgNWqKYXJWAryuAQSK0D74arruteq8pXjRX kaVPs4ZAv6LTOtfyKQtHwikK9VyzfsXvwqiEX3AOPznieRxQJs2HQmKGivcjlpiW m8QWU7hLyeNXD0o6tj4v3/QAtEArpQ73qBPBE5bmj/yC3IPFQnEQXYOJbN6C6ZAl bVI3AgMBAAEwDQYJKoZIhvcNAQELBQADgYEAIfBM7JsAzvT90Q2L4dcjxG4Vu3ER 7+NqKJJmab4SW6FmKLGK/E5h4VPmU9JaqdW2xco9vfNYshmLOSHQaeq2ZiEm0Xpv 2qOu235UxeafBnEAbnz+pRaldPFhuRWWX9Krn/YkeE7I/wcojkNZiI1E1aaRmvGL 5oTaYabrqnKdDE0= -----END CERTIFICATE----- node-sshpk-1.16.1/test/assets/jim-x509.pem000066400000000000000000000012541342215657600201360ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIByzCCATQCCQCr/VI8PlLAezANBgkqhkiG9w0BAQUFADAqMRMwEQYKCZImiZPy LGQBGRYDamltMRMwEQYKCZImiZPyLGQBGRYDY29tMB4XDTE2MDcyMjAxMDQyNloX DTE3MDcyMjAxMDQyNlowKjETMBEGCgmSJomT8ixkARkWA2ppbTETMBEGCgmSJomT 8ixkARkWA2NvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1Zpd2A1aophc lYCvK4BBIrQPvhquu616ryleNFeRpU+zhkC/otM61/IpC0fCKQr1XLN+xe/CqIRf cA4/OeJ5HFAmzYdCYoaK9yOWmJabxBZTuEvJ41cPSjq2Pi/f9AC0QCulDveoE8ET luaP/ILcg8VCcRBdg4ls3oLpkCVtUjcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQAQ U0ekppGXa0IGfo8l4UZWrqBOhDjbrOh2LcSBU0oiHB/pWHAliDy8hqXQA3rr17ir cm458oUFupEHvB26yQiO1uNLQcIuXTiGoUA2xcepgjYbZahn1WbYTJuKFtcNxkOV sq+Dmj34yvc1Ror4lcqlg5foPE8aH2ONroG2PwM7eQ== -----END CERTIFICATE----- node-sshpk-1.16.1/test/assets/joyent.pem000066400000000000000000000036171342215657600201710ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIFaDCCBFCgAwIBAgIQRqqqzQI4MxX9tbSSUtQ+HzANBgkqhkiG9w0BAQsFADBC MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMS UmFwaWRTU0wgU0hBMjU2IENBMB4XDTE2MDUyNDAwMDAwMFoXDTE3MDUyNDIzNTk1 OVowFzEVMBMGA1UEAwwMKi5qb3llbnQuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAua6H3bcQqOzUyE5NSzqkzbT2O2/hzmouEs5tUqXaWsENlsIk e+hRQ3CrPxqBf/txb4/EIPkUmi0B/RNxfhKTCZ8YRXjf7AUaD+H+aknuFmFWOU32 lsPAYw/EP8vCYFEI7DfzY7Rg1ULcLSFolUTVRIOua218kZ+rv1vlcSkLJlP4qQQ9 Q5XXqu0C26pJQCfV8hhFnHUAx33nZd9Sbgy9DmXM9PStY4x4j1RZoyQvzo25HqGI ykAtXew7f9i3Bz/ihybWBogGSZURV+vpJ2FMLnqJjOEaEe4q+GmZggcJvyHcNIlb 0AVbvHDDHYScMR+QYU6v3K0hm5W2qbmNnsc5RQIDAQABo4ICgzCCAn8wIwYDVR0R BBwwGoIMKi5qb3llbnQuY29tggpqb3llbnQuY29tMAkGA1UdEwQCMAAwKwYDVR0f BCQwIjAgoB6gHIYaaHR0cDovL2dwLnN5bWNiLmNvbS9ncC5jcmwwbwYDVR0gBGgw ZjBkBgZngQwBAgEwWjAqBggrBgEFBQcCARYeaHR0cHM6Ly93d3cucmFwaWRzc2wu Y29tL2xlZ2FsMCwGCCsGAQUFBwICMCAMHmh0dHBzOi8vd3d3LnJhcGlkc3NsLmNv bS9sZWdhbDAfBgNVHSMEGDAWgBSXwidQnsLJ7AyIMsh8reKmAU/abzAOBgNVHQ8B Af8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMFcGCCsGAQUF BwEBBEswSTAfBggrBgEFBQcwAYYTaHR0cDovL2dwLnN5bWNkLmNvbTAmBggrBgEF BQcwAoYaaHR0cDovL2dwLnN5bWNiLmNvbS9ncC5jcnQwggEEBgorBgEEAdZ5AgQC BIH1BIHyAPAAdgDd6x0reg1PpiCLga2BaHB+Lo6dAdVciI09EcTNtuy+zAAAAVTk zlluAAAEAwBHMEUCIAouSdhGoMRAWdprnvqryiiZUv8FEmiv2EFOAqaC7/fFAiEA zx7aZjtiOC5kELoSDfbHjcDAayq+OfgF49mBnULmH4wAdgCkuQmQtBhYFIe7E6LM Z3AKPDWYBPkb37jjd80OyA3cEAAAAVTkzlmnAAAEAwBHMEUCIQCMV3cI6DqlWyjy 6i0IuQAjCqzo1hKm3JBTI1dylJlBtwIgF9UHLufpaQ2U0qF0J/N+zRdVU4hTTyv4 vaxH+UcVuXAwDQYJKoZIhvcNAQELBQADggEBAICbZrdFZlyxmfNkAhehgRv3sSwD 1oBJ2sP5pSGhWOSsgb+PC7Tk36UDdGV/sv7HJwf9ssW06LlCWtcZIu7Wft1DTId7 xjH2yXogYSC3ClLfFOMdIYD0cvjBmKAwajwEfLIG8PWY9PqDNBZNj8hnvGEA+qpR mLXDQAL5MeWI0bZDANACA5iSImJwoDIa3u36RW3kTu5eoQPtg0vfLIzx++BdCH8x JWT3OB0996mQ3qAK8E4yYdYMalxme18cKCWl3agcqS9fUzF76bYA8GaLn1FJIfF0 QR3uD41rTugtDn9eMaQbeeQmdrkWCZo7EWVbODGFM3sMDuBDYAw5v64+pGU= -----END CERTIFICATE----- node-sshpk-1.16.1/test/assets/letsencrypt.pem000066400000000000000000000033751342215657600212360ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIE/DCCA+SgAwIBAgISAy33AhOr1xxbWtSsIBBKe5gJMA0GCSqGSIb3DQEBCwUA MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNjA3MjEyMzM4MDBaFw0x NjEwMTkyMzM4MDBaMBcxFTATBgNVBAMTDGNyLmpveWVudC51czCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBALFOmt+wPZpIozmBEeWutW256t0HgNJwjIRY HnnJ4jCOlJgNfKd4c2Dxwp9Avz5MXUiJkaMzN2P2sjmbt/Iqy1TwwMgC975MTmez I1hJwRR6YsXy9YOAwXP539AejZv8vhIBNkClW0bJ/ZlIFSvkfC/X/JhneIrdsIOE yZcyEMIBk9QvFwkWKHq43N+7c/siZHiQ6hWnlUzqh1xQejRvlhzTrT2Vf1U+/dkG 0RKcy4cyqXy/Uz+emvCyv75lM0vrTJmmR9jH4M59HciVrZ6OYI3kWPalp0ju1kb3 T8vNnMx8yg1TpKRSxigxJqnLOGUjVWNp+w5J62FbwLhG19iu+ksCAwEAAaOCAg0w ggIJMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU8ljh5m3JDMkAjo5WBuqgwwROLuww HwYDVR0jBBgwFoAUqEpqYwR93brm0Tm3pkVl7/Oo7KEwcAYIKwYBBQUHAQEEZDBi MC8GCCsGAQUFBzABhiNodHRwOi8vb2NzcC5pbnQteDMubGV0c2VuY3J5cHQub3Jn LzAvBggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNyeXB0Lm9y Zy8wFwYDVR0RBBAwDoIMY3Iuam95ZW50LnVzMIH+BgNVHSAEgfYwgfMwCAYGZ4EM AQIBMIHmBgsrBgEEAYLfEwEBATCB1jAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5s ZXRzZW5jcnlwdC5vcmcwgasGCCsGAQUFBwICMIGeDIGbVGhpcyBDZXJ0aWZpY2F0 ZSBtYXkgb25seSBiZSByZWxpZWQgdXBvbiBieSBSZWx5aW5nIFBhcnRpZXMgYW5k IG9ubHkgaW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBDZXJ0aWZpY2F0ZSBQb2xpY3kg Zm91bmQgYXQgaHR0cHM6Ly9sZXRzZW5jcnlwdC5vcmcvcmVwb3NpdG9yeS8wDQYJ KoZIhvcNAQELBQADggEBAFtUWwfPA2107luHzpwdh/Hqr9KofaEYpOwe3+6kqpJB fUcvxty1qE1efTLy8s6GPyzU0gqlnhEDpB6jXyimVfGJn0mwZWdIHLoKZTcOlHMm QE0yBCXGxvBgIpRPG/GMHeyzJsWHynmFopmKiKyG51Y776oVudrIxnmxQBjUvUZO HKuqeASJI8yKtVQCTnQsjEwVABpTNrB3u06hoouSQ7PdsbBRkV2hnkK80C4k6bbo Fdg0bwhqzWmEzO3575YX7We7frE/lN1knVVRZuvWig/J+j3+HJooo/wq/s2bkylY mh8jOyfWA95w2Yn+aA4jfBNm+tcqe8nFs/2GkbQ6KoY= -----END CERTIFICATE----- node-sshpk-1.16.1/test/assets/napoleon-cert.pem000066400000000000000000000023511342215657600214210ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDdDCCAt2gAwIBAgIBADANBgkqhkiG9w0BAQUFADCBmzELMAkGA1UEBhMCSlAx DjAMBgNVBAgTBVRva3lvMRAwDgYDVQQHEwdDaHVvLWt1MREwDwYDVQQKEwhGcmFu azRERDEYMBYGA1UECxMPV2ViQ2VydCBTdXBwb3J0MRgwFgYDVQQDEw9GcmFuazRE RCBXZWIgQ0ExIzAhBgkqhkiG9w0BCQEWFHN1cHBvcnRAZnJhbms0ZGQuY29tMCIY DzE3NjkwODE1MTU0NjQxWhgPMTgyMTA1MDUxNjUzMjFaMIHbMQswCQYDVQQGEwJG UjEXMBUGA1UECBQOw45sZS1kZS1GcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRwwGgYD VQQKExNIZXJlZGl0YXJ5IE1vbmFyY2h5MRYwFAYDVQQLEw1IZWFkIG9mIFN0YXRl MSkwJwYJKoZIhvcNAQkBFhpuYXBwaUBncmVhdGZyZW5jaGVtcGlyZS5mcjEbMBkG A1UEAxMSRW1wZXJvciBOYXBvbGVvbiBJMRIwEAYDVQQEEwlCb25hcGFydGUxETAP BgNVBCoTCE5hcG9sZW9uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA vdcwMpsM3EgNmeO/fvcuZsirnBZCh0yJlySGmev792ohOBvfC+v27ZKcXN+H7V+x SxEDDAFq9SCEk4MZ8h/ggtw63T6SEYeNGtnfyLv8atienun/6ocDp0+26xvj8Nxm aKL4MQM9j9aYgt2EOxUTH5kBc7mc621q2RJi0q/y0/SdX2Pp/3MKDirOs81vfc2i cEaYAisd5IOF9vpMpLr3b3Qg9T66/4hQS6DgIOkfUurWqe33sA2RRv7ql1gcxL1I mBxBtYQGsujn8fCNRK5jtMtICkEi9tks/tYzSaqgby3QGfbA18xl7FLLjnZDLVX3 ZVchhveR78/f7U/xh8C2WQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFmEiU2vn10f XvL+nJdRHJsf0P+f6v8H+vbkomog4gVbagDuFACJfAdKJhnc/gzkCF1fyeowOD68 k4e0H1vyLuk23BUmjW41nOjdg8LrTAS8fMwkj5FVSKR2mHciHWgY/BU4UypYJtcg ajH1bsqwUI50wfbggW4VzLD842q5LhnW -----END CERTIFICATE----- node-sshpk-1.16.1/test/assets/oakley_pubkey.pem000066400000000000000000000004401342215657600215130ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIGpMHsGByqGSM49AgEwcAIBATAdBgcqhkjOPQECMBICAgCbBgkqhkjOPQECAwIC AT4wCAQBAAQDBzOPBCkEAAAAAAAAAAAAAAAAAAAAAAAAAHsAAAAAAAAAAAAAAAAA AAAAAAAByAIUAqqqqqqqqqqqqsfzx4gb0IaPqGwCAQMDKgAEA2uNp3wO2DeYe+wG yTpFhT5/kMAFkxiDsyoac6/uGwqH2r617caOXQ== -----END PUBLIC KEY----- node-sshpk-1.16.1/test/assets/openssh-exts.pub000066400000000000000000000016241342215657600213220ustar00rootroot00000000000000ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgGJnHtSaSYoqtvjv5k2BeP4bKCQv3CVvjcG0EMbY/iToAAAAIbmlzdHAyNTYAAABBBK9+hFGVZ9RT61pg8t7EGgkvduhPr/CBYfx+5rQFEROj8EjkoGIH2xypHOHBz0WikK5hYcwTM5YMvnNxuU0h4+cAAAAAAAAAAAAAAAEAAAAIdXNlcl9mb28AAAAHAAAAA2ZvbwAAAABbvVB4AAAAAF2dMrUAAAAiAAAADWZvcmNlLWNvbW1hbmQAAAANAAAACWZvb2JhcmNtZAAAAHAAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAAIgAAAATZWNkc2Etc2hhMi1uaXN0cDM4NAAAAAhuaXN0cDM4NAAAAGEECFVIfBIMjMd5ibZFUmEIh/HhvrCvFr7fLOsva912h4J0TaGeHHL2OuHXFYHRRToZ9bZSI+5kGIdabZiCMXfI7aTYv7gT8uMNzZbw9qApwP91ZxJwTOkGikvhCvdhzMmDAAAAhAAAABNlY2RzYS1zaGEyLW5pc3RwMzg0AAAAaQAAADEAwZVZk2dsVAy2w3dJMbMfNsP9sYEW5Qa5DRDAddpRV3yL9Sb318KwYzfeuRFoCl/HAAAAMCnLGQ23ZHJhxCVpmtlSeuAKC2lgoqK2UNsOPDUOFg2p74dqnWsBjaUi9Ddj0HfHkA== id_ecdsa2 node-sshpk-1.16.1/test/assets/openssh-rsa256.pub000066400000000000000000000014421342215657600213570ustar00rootroot00000000000000ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAQHOnkPfKVY+TTp/r4sUhp0QAAAAMBAAEAAACBANWaXdgNWqKYXJWAryuAQSK0D74arruteq8pXjRXkaVPs4ZAv6LTOtfyKQtHwikK9VyzfsXvwqiEX3AOPznieRxQJs2HQmKGivcjlpiWm8QWU7hLyeNXD0o6tj4v3/QAtEArpQ73qBPBE5bmj/yC3IPFQnEQXYOJbN6C6ZAlbVI3AAAAAAAAAAEAAAACAAAAEGhvc3RfdGVzdGluZy5yc2EAAAAPAAAAC3Rlc3RpbmcucnNhAAAAAFjkGCkAAAAAa7AbKQAAAAAAAAAAAAAAAAAAAJcAAAAHc3NoLXJzYQAAAAMBAAEAAACBANWaXdgNWqKYXJWAryuAQSK0D74arruteq8pXjRXkaVPs4ZAv6LTOtfyKQtHwikK9VyzfsXvwqiEX3AOPznieRxQJs2HQmKGivcjlpiWm8QWU7hLyeNXD0o6tj4v3/QAtEArpQ73qBPBE5bmj/yC3IPFQnEQXYOJbN6C6ZAlbVI3AAAAlAAAAAxyc2Etc2hhMi0yNTYAAACAjpKrSo5KSdFB0IAxzQWv7oW5d6BEgx4IaQ+FXh2Oii8fSeFPo9WreBdUJkPkREdqE3AAzJZjs0as8i5tbRQXEuCBXvlwS1km7JkyUAMwSMnSArPRccgwx0zpI6j2DLhwjA/ZI2YWdwoC4o6RYDP5q/o4eHtPjAjkrSCkuQkR3k8= node-sshpk-1.16.1/test/assets/p50key.pem000066400000000000000000000033461342215657600177750ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,C874518D21E3C9C4F0CA44C8060D631B 6kCcRk72I+6eYBpvDpMu/hxJKVI9xpsJikmfyc//0HLBP6e95cuk3EHWUG5/2cLb RSniNWjeIBmxMUlJP7vCdmdnJQ+so/9JzmztwHIEk/kMW1jgNnWH53pUhuNTllFy M7/c2IOD5gWSrl/MijNNhYaglh2Zn5djJvuoJmmT3lXsIFc1FQw0luDBxYE7l5Rf PuZxuRgpHwbuAAJ2UW2NDlYxtpOI3ilh90GHl+G/DEks3N/tWvWQKWbkGy10I2Nm TbBlGf78KU5Br3fIdau5YdKUFT7vFfhuX/txB1eqV7wbMBjeDKEJNylfwANGQyMk iUZo54FdNCfZC9IYHOxJ2ntNYlV0qnD+JwffE3fmDL+QXAdr5kHY5D/C5vgLelpS 1JNQPNnRll04Sj0b3ozfmPShLhTfyRUXqyngiqLl1rp0/52B4WCZuZUz17JErwas AN8e0jmNn4nGP/MZAb4sZ2ENirkguoi+yqqeGVRVylAAHzp7yPNLDp53l4vYoQ0R H99SJ+0I8PZCeODSfQm+c76mQBfUEUXYnD2LUzNZ+qZrtlUS/i0i/3wvJ+Ek4GGL lm+81KEkbmAzAe+BhXpCa+PUhuo30yhqqneq1fqhi6Hit247nIOAXjEowTYKLwxD VGHowhBZqyB+YzCApO0KFsbDeTij/VaLdm29JpAWuN6k8l1IUr3kfJerF5oItVv+ VLNiC0P15yIbY5QaQHM5RkOh0kJcAnvuTRqz0Lq6rVQVE3qvwig86B1TCYO15dB9 9HyRDFoR2CZ2Dy6nUCQl1nnYa7sD3GxSusoMLN1DxV+afeyW7RBQP3veWxb+nNNu M6ImxzOOEZuLQ0nG+gny25KoIfH1BuQwTd82SPl7Uez8LrTY41P/SdLxa/UFodM9 BYWGdbdIgpfcTgdSoGIUvSA86RvnN7umM5DkNH8WMfm7Tfx/GCDEYANBH2yH79cn s4fCrRsE8QN4cm7LnKrhKZSEaLN5YVjoV4aiDZv3UHYdEwr1GrK2H+FxvEPCFIbh GEhP34wb9co8kQrUl0LKT+cRt5nTSF+pEDpOaE/h1B58hPNFqZJSeaUaHLUJQ84X OTJnUS+fU5B/dA/smPKPyqcq7wLjkB/FmIjYm/ezXZ9Qg2IFhBMSxAHuGdxeg8C8 vypd9E1w36pm0y5E6ilogf1+UI7SsLo2HiUz8jc25SgoMv4W45dv+jwNOAAk26Z/ vMD0diOAVSTpqtmYVEx/CsEoEXtLg36sUVR+NUFwdhTiVYRuaqhwvcHW4Z14DzLm tASkhcdd+9bjGUX3oJFsyitqSnMAzajthcEFsUuGaeI/DL+2NRZYrQNOVnmzKPJS 0cnOJnPTI1a93FbWnTjMWLR+iNZHtafUGuf2IYHlFAiR0ekVUQHcUGC4oyKZUaPI CU9rFRGeql4XYp8UC0pBCTF5a+0Dixs7HUCc4abmlgsxfcQrIa5IFCbzmBQBs6x4 9XZ9T6qedqFX5Cuy/k/9b8QKQKlzXEPFpmfXvTy0a0OS16ypCia0PuWiLgjCLkzA lqmgx4ohcj1asGUCItGeGBXbmEaBVLMgz7QDWzuIGdnq+IfVYCn37UyxdCyVkHBr -----END RSA PRIVATE KEY----- node-sshpk-1.16.1/test/assets/pkcs8-enc-bad-hash000066400000000000000000000007201342215657600213310ustar00rootroot00000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIBHDBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQILKyFq/D9ok4CAggA MAwGCCqGSIb3DQIQBQAwHQYJYIZIAWUDBAEqBBBIrV2g9Fy0mn+DhZKJN6EdBIHA myZhhrYCTj58V3Je3Mn3H0dDY4o5rK1Mu+LOCFTQqjArO0FLsw6d/Xv5jmbT8Bq9 VZgmTrY1V+SHa1dVrEG4YnAXjorOVcEYxdUkpzkmJVl/vP2HYx0PFrL81+sDp2Ua 6SmX5ZE11Tq05y4oL+AQQJzAyf4BNAbUSjgd/83WE1pA4qeYE+nzEy26yrozWlLc CJL8oq1DvubHOQX3HL4K68sU55M/i3tKLUFfz8e2KN0H8w3j8YgmF/pjn/t7kdAU -----END ENCRYPTED PRIVATE KEY----- node-sshpk-1.16.1/test/assets/pkcs8-enc-bad-iters000066400000000000000000000007201342215657600215340ustar00rootroot00000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIBHDBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQILKyFq/D9ok4CAggB MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBBIrV2g9Fy0mn+DhZKJN6EdBIHA myZhhrYCTj58V3Je3Mn3H0dDY4o5rK1Mu+LOCFTQqjArO0FLsw6d/Xv5jmbT8Bq9 VZgmTrY1V+SHa1dVrEG4YnAXjorOVcEYxdUkpzkmJVl/vP2HYx0PFrL81+sDp2Ua 6SmX5ZE11Tq05y4oL+AQQJzAyf4BNAbUSjgd/83WE1pA4qeYE+nzEy26yrozWlLc CJL8oq1DvubHOQX3HL4K68sU55M/i3tKLUFfz8e2KN0H8w3j8YgmF/pjn/t7kdAU -----END ENCRYPTED PRIVATE KEY----- node-sshpk-1.16.1/test/assets/pkcs8-enc-bad-kdf000066400000000000000000000007041342215657600211540ustar00rootroot00000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIBEzBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBAwwHAQI8ss6mjBMp84CAggA MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECPYbjSRfW4DmBIHAczs2+q5pZYOv XHiGkWmOU7bAoLFbQy12vsswU/4wAZlm5/MNooJKQBx2cEDYKPQhhOoC6usARTnP WaEqEkk++bTWc/JfQMJRHTWZwF7YIIA6J3VP11uRTyDiZeorGOr5qlUzwILZoT63 d+EUI7SfkQA6c2zEEYqZWYA+tB+ptztUsxmkiREfR3IOB3IWr63IbCsDmdt9/gny 47CRD5hnJxTkjWqsNBI8ZerlBgAjInKWx1vMkx7q+GZjZHcDp62r -----END ENCRYPTED PRIVATE KEY----- node-sshpk-1.16.1/test/assets/pkcs8-enc-bad-scheme000066400000000000000000000007041342215657600216540ustar00rootroot00000000000000-----BEGIN ENCRYPTED PRIVATE KEY----- MIIBEzBOBgkqhkiG9w0BBQ4wQTApBgkqhkiG9w0BBQwwHAQI8ss6mjBMp84CAggA MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECPYbjSRfW4DmBIHAczs2+q5pZYOv XHiGkWmOU7bAoLFbQy12vsswU/4wAZlm5/MNooJKQBx2cEDYKPQhhOoC6usARTnP WaEqEkk++bTWc/JfQMJRHTWZwF7YIIA6J3VP11uRTyDiZeorGOr5qlUzwILZoT63 d+EUI7SfkQA6c2zEEYqZWYA+tB+ptztUsxmkiREfR3IOB3IWr63IbCsDmdt9/gny 47CRD5hnJxTkjWqsNBI8ZerlBgAjInKWx1vMkx7q+GZjZHcDp62r -----END ENCRYPTED PRIVATE KEY----- node-sshpk-1.16.1/test/assets/pkcs8-nopub.pem000066400000000000000000000002241342215657600210210ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCD1/r3zho5W2MpyZEk+ 2d7gxUcQYUJzvWSOiwkUxCj8Bw== -----END PRIVATE KEY----- node-sshpk-1.16.1/test/assets/rsa.ppk000066400000000000000000000026601342215657600174540ustar00rootroot00000000000000PuTTY-User-Key-File-2: ssh-rsa Encryption: aes256-cbc Comment: rsa-key-20170331 Public-Lines: 6 AAAAB3NzaC1yc2EAAAABJQAAAQEAsJb8crG6hSSizpKs8EQip90n+n4MKs6qYKIt r4X8EeBhKMbQNXGbLC617Ui0cVQMF8nfEGe61/Fc0uQOWJdEk2ANe6rtcaFPTwYH LyPznd28c9xfBifqksdBjqH+Svr57MBqmivQi3gTIXeIlGYyXhKh9U8J2WDIpMks hE1UmsqvJgMjoqNVWG/iU+t4GeKxdDd4TGIHiZU6JfGf777pAB2+Uhi7PrSvs7Ov oetgNW7LFsPiA8zbwfj5jkVQ2ycHoAOHMuthB3bkNetL+A6V6pkfDLTVd9g0SiPF K03ut1XIw+FtxO5ioEfy5XvwkIPbAl2vInfxL0EacWFkXq08ew== Private-Lines: 14 lfdred2syPlQV1MrIG+3uAKVIrd8Wlprhxyco0A3LEbEjaUJOMaRY4GG+47MUdfG YKqtH1zWuvpBrlfmLiUySL2j4DustFvMkLD9aFI4IFUPPCbV0ujuQh1rFQuutzDj dmOFdQAcwV0/clB2ewz/tX5x0GPQq71xrLHq4qQLepaDbZFIhF+S6K+opXiSJPc6 YG6SJKMBj+jshFrHeONN+MLTCPxDb/Ulrh3Fl5no1xLjjZEtO/TETeKyeM3jUAu2 oNn8WI9MP2wEGgp2Nux8759BveUr4zH71lS9OKagG1ipxMkyikrgAZpXbxTVFXsq m+5RkZuvd9smYVJl3S2T1c/YcS5SaSaC4FTYEOw70N68Mw2nOQEWpXkdnxqUMdbp o209XxOQdYsbBi3+FWfcY/jr846XstkRx2wj5PfGFn/ULIoaMNIpYHgP2JgSsz+G rX5ZXktpCzHRBfhudqyOAzvlWqyQS5+hBpigqupUbrRHJKmuGNYkhay9W/Ka80pX +K7yom1k6JD8lK+GA+AvU+v2pxKMsvoxVDBgJUfvg4Su8wVyPj8g01DSvrM9Ld4X 1nXbA+kEijokalDsxhcp6ZjYWBFwMn+kBZ7ztBlwKf5gnoMa9A917mJiUNy1B+t8 CwYuBNilNUWSrWCcoG29c9HPyz8QVkFPfMpqhX3W43G2a3pRi2CZzwEHV+te4TDz pmpU2yObRH93nWVnFn91onKL0rHPEI4613e7Nhb8R1dhXtJZoLPbjdLJlmWUgZa/ VDfhatovJ7XzD4WRaamJaevK6LUnmULDZRkzU9fJJBLp76BJvbENiQ6GANGp4i2h bJ0sbiWMFEnKTFGpcIVLZI11xLJ7H9S6TrDJFVhVSGB114Dj0TjIdA8FyOOik77o Private-MAC: e528058a4a0851024975d88a0b012bb8b40607b0 node-sshpk-1.16.1/test/assets/secp224r1_key.pem000066400000000000000000000003171342215657600211500ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- MGgCAQEEHHq8QCQRtdhSBdbtsy8K1h9nvONPAqHE4cYkXU+gBwYFK4EEACGhPAM6 AAT8C5cN/FeBdgfXL4SXhxjtTrJr7HPLYzcrjU6Wg+d/IExBNwA6AahT/rfMtOg4 bO5Oq4YBwdrpzg== -----END EC PRIVATE KEY----- node-sshpk-1.16.1/test/assets/yubikey.pem000066400000000000000000000015201342215657600203310ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICRDCCASygAwIBAgIRAO0gfWbAn5zoJg4edq5vmYcwDQYJKoZIhvcNAQELBQAw ITEfMB0GA1UEAwwWWXViaWNvIFBJViBBdHRlc3RhdGlvbjAgFw0xNjAzMTQwMDAw MDBaGA8yMDUyMDQxNzAwMDAwMFowJTEjMCEGA1UEAwwaWXViaUtleSBQSVYgQXR0 ZXN0YXRpb24gOWUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASfpEFqoePaZIAs L2xkEdVZ67pgQWIkgaKDxQr+QidA/j+5DjStb515FJZ8qYAF64mVrZjaJgD3Outp 9G5eJWvzozwwOjARBgorBgEEAYLECgMDBAMEAwMwEwYKKwYBBAGCxAoDBwQFAgNP jfEwEAYKKwYBBAGCxAoDCAQCAQEwDQYJKoZIhvcNAQELBQADggEBAKa+hH9ExP4I 1g40Qzi6+xaB7K0nmlE4xXLAceVeBebIKMDFGdbJpcMGxw5K4GmcMlaYLxKUbUdX uQBZ5LZSiHALxinF/0Lpn1I8SS4txgy5JvSJxMyaWCuupvQ0/zKk+eTryrsO52WX RLYNdOwwlVHqhu2cNoZ7F0AynEfTwIksCcpiJX3UI8YmOnBUarJpWG2M98HbQUXx 0oLgy5I46xtY+vbMtw7tn42BjJF10RV+99VNsnUagbzCgULVLWnbaYUARA7k+Doc MWNMYnZPS5ouvHnAJGFER9/v0YELGuyt/dDCU/qPUY95UW6lXJSO2Iy41E+libW7 s4MpuZzf5rw= -----END CERTIFICATE----- node-sshpk-1.16.1/test/certs.js000066400000000000000000000361301342215657600163260ustar00rootroot00000000000000// Copyright 2018 Joyent, Inc. All rights reserved. var test = require('tape').test; var sshpk = require('../lib/index'); var fs = require('fs'); var path = require('path'); var crypto = require('crypto'); var sinon = require('sinon'); var asn1 = require('asn1'); var SSHBuffer = require('../lib/ssh-buffer'); var testDir = path.join(__dirname, 'assets'); var GEORGE_KEY, GEORGE_SSH, GEORGE_X509; var BARRY_KEY; var JIM_KEY, JIM_SSH, JIM_X509, JIM_X509_TXT; var EC_KEY, EC_KEY2; var SUE_KEY; test('setup', function (t) { var d = fs.readFileSync(path.join(testDir, 'id_dsa')); GEORGE_KEY = sshpk.parseKey(d); GEORGE_SSH = fs.readFileSync(path.join(testDir, 'george-openssh.pub')); GEORGE_X509 = fs.readFileSync(path.join(testDir, 'george-x509.pem')); d = fs.readFileSync(path.join(testDir, 'id_dsa2')); BARRY_KEY = sshpk.parsePrivateKey(d); d = fs.readFileSync(path.join(testDir, 'id_rsa')); JIM_KEY = sshpk.parsePrivateKey(d); JIM_SSH = fs.readFileSync(path.join(testDir, 'jim-openssh.pub')); JIM_X509 = fs.readFileSync(path.join(testDir, 'jim-x509.pem')); JIM_X509_TXT = fs.readFileSync(path.join(testDir, 'jim-x509-text.pem')); d = fs.readFileSync(path.join(testDir, 'id_ecdsa')); EC_KEY = sshpk.parsePrivateKey(d); d = fs.readFileSync(path.join(testDir, 'id_ecdsa2')); EC2_KEY = sshpk.parsePrivateKey(d); d = fs.readFileSync(path.join(testDir, 'id_ed25519')); SUE_KEY = sshpk.parsePrivateKey(d); t.end(); }); test('dsa openssh cert self-signed', function (t) { var cert = sshpk.parseCertificate(GEORGE_SSH, 'openssh'); t.ok(sshpk.Certificate.isCertificate(cert)); t.ok(GEORGE_KEY.fingerprint().matches(cert.subjectKey)); t.ok(cert.isSignedByKey(GEORGE_KEY)); t.ok(!cert.isSignedByKey(BARRY_KEY)); t.ok(!cert.isExpired(new Date('2016-07-22T00:00:00Z'))); t.ok(cert.isExpired(new Date('2001-07-01T00:00:00Z'))); t.ok(cert.isExpired(new Date('2017-07-23T00:00:00Z'))); t.strictEqual(cert.subjects.length, 1); t.strictEqual(cert.subjects[0].toString(), 'UID=george'); t.strictEqual(cert.subjects[0].type, 'user'); t.strictEqual(cert.subjects[0].uid, 'george'); t.throws(function () { cert.fingerprint(); }); t.end(); }); test('dsa x509 cert self-signed', function (t) { var cert = sshpk.parseCertificate(GEORGE_X509, 'pem'); t.ok(sshpk.Certificate.isCertificate(cert)); t.ok(GEORGE_KEY.fingerprint().matches(cert.subjectKey)); t.ok(cert.isSignedByKey(GEORGE_KEY)); t.ok(!cert.isSignedByKey(BARRY_KEY)); t.ok(!cert.isExpired(new Date('2016-07-22T00:00:00Z'))); t.ok(cert.isExpired(new Date('2001-07-01T00:00:00Z'))); t.ok(cert.isExpired(new Date('2017-07-23T00:00:00Z'))); t.strictEqual(cert.subjects.length, 1); t.strictEqual(cert.subjects[0].toString(), 'UID=george'); t.strictEqual(cert.subjects[0].type, 'user'); t.strictEqual(cert.subjects[0].uid, 'george'); var fp = sshpk.parseFingerprint( 'SHA256:rPrIM16iuYN1UkWprtIkRaUzerKz0JkNd/FjKG7OJCU', { type: 'certificate '}); t.ok(fp.matches(cert)); t.end(); }); test('rsa openssh cert self-signed', function (t) { var cert = sshpk.parseCertificate(JIM_SSH, 'openssh'); t.ok(sshpk.Certificate.isCertificate(cert)); t.ok(JIM_KEY.fingerprint().matches(cert.subjectKey)); t.ok(cert.isSignedByKey(JIM_KEY)); t.ok(!cert.isSignedByKey(BARRY_KEY)); t.ok(!cert.isExpired(new Date('2016-07-23T00:00:00Z'))); t.ok(cert.isExpired(new Date('2001-07-01T00:00:00Z'))); t.ok(cert.isExpired(new Date('2017-07-23T00:00:00Z'))); t.strictEqual(cert.subjects.length, 1); t.strictEqual(cert.subjects[0].toString(), 'CN=jim.com'); t.strictEqual(cert.subjects[0].type, 'host'); t.strictEqual(cert.subjects[0].hostname, 'jim.com'); t.ok(cert.issuer.equals(cert.subjects[0])); t.end(); }); test('rsa x509 cert self-signed', function (t) { var cert = sshpk.parseCertificate(JIM_X509, 'pem'); t.ok(sshpk.Certificate.isCertificate(cert)); t.ok(JIM_KEY.fingerprint().matches(cert.subjectKey)); t.ok(cert.isSignedByKey(JIM_KEY)); t.ok(!cert.isSignedByKey(BARRY_KEY)); t.ok(!cert.isExpired(new Date('2016-07-23T00:00:00Z'))); t.ok(cert.isExpired(new Date('2001-07-01T00:00:00Z'))); t.ok(cert.isExpired(new Date('2017-07-23T00:00:00Z'))); t.strictEqual(cert.subjects.length, 1); t.strictEqual(cert.subjects[0].toString(), 'DC=jim, DC=com'); t.strictEqual(cert.subjects[0].type, 'host'); t.strictEqual(cert.subjects[0].hostname, 'jim.com'); t.ok(cert.issuer.equals(cert.subjects[0])); t.ok(cert.isSignedBy(cert)); t.end(); }); test('x509 pem cert with extra text', function (t) { var cert = sshpk.parseCertificate(JIM_X509_TXT, 'pem'); t.ok(sshpk.Certificate.isCertificate(cert)); t.ok(JIM_KEY.fingerprint().matches(cert.subjectKey)); t.ok(cert.isSignedByKey(JIM_KEY)); t.end(); }); test('create rsa self-signed, loopback', function (t) { var id = sshpk.identityForHost('foobar.com'); var cert = sshpk.createSelfSignedCertificate(id, JIM_KEY); var x509 = cert.toBuffer('pem'); var cert2 = sshpk.parseCertificate(x509, 'pem'); t.ok(JIM_KEY.fingerprint().matches(cert2.subjectKey)); t.ok(cert2.subjects[0].equals(cert.subjects[0])); var ossh = cert.toBuffer('openssh'); var cert3 = sshpk.parseCertificate(ossh, 'openssh'); t.ok(JIM_KEY.fingerprint().matches(cert3.subjectKey)); t.ok(cert3.subjects[0].equals(cert.subjects[0])); t.strictEqual(cert3.subjects[0].hostname, 'foobar.com'); t.end(); }); test('create ecdsa signed, loopback', function (t) { var id = sshpk.identityForUser('jim'); var ca = sshpk.identityForHost('foobar.com'); var cacert = sshpk.createSelfSignedCertificate(ca, EC2_KEY); var cert = sshpk.createCertificate(id, EC_KEY, ca, EC2_KEY); var x509 = cert.toBuffer('pem'); var cert2 = sshpk.parseCertificate(x509, 'pem'); t.ok(EC_KEY.fingerprint().matches(cert2.subjectKey)); t.ok(cert2.subjects[0].equals(cert.subjects[0])); t.ok(cert2.isSignedBy(cacert)); var ossh = cert.toBuffer('openssh'); var cert3 = sshpk.parseCertificate(ossh, 'openssh'); t.ok(EC_KEY.fingerprint().matches(cert3.subjectKey)); t.ok(cert3.subjects[0].equals(cert.subjects[0])); t.strictEqual(cert3.subjects[0].uid, 'jim'); t.ok(cert3.isSignedBy(cacert)); t.end(); }); test('create ed25519 self-signed, loopback', function (t) { var id = sshpk.identityForHost('foobar.com'); var cert = sshpk.createSelfSignedCertificate(id, SUE_KEY); var x509 = cert.toBuffer('pem'); var cert2 = sshpk.parseCertificate(x509, 'pem'); t.ok(SUE_KEY.fingerprint().matches(cert2.subjectKey)); t.ok(cert2.subjects[0].equals(cert.subjects[0])); t.ok(cert2.isSignedByKey(SUE_KEY)); var ossh = cert.toBuffer('openssh'); var cert3 = sshpk.parseCertificate(ossh, 'openssh'); t.ok(SUE_KEY.fingerprint().matches(cert3.subjectKey)); t.ok(cert3.subjects[0].equals(cert.subjects[0])); t.strictEqual(cert3.subjects[0].hostname, 'foobar.com'); t.end(); }); test('subjectaltname', function (t) { var ids = [ sshpk.identityForHost('foobar.com'), sshpk.identityForHost('www.foobar.com'), sshpk.identityForHost('mail.foobar.com') ]; var cert = sshpk.createSelfSignedCertificate(ids, JIM_KEY); var x509 = cert.toBuffer('pem'); var cert2 = sshpk.parseCertificate(x509, 'pem'); t.ok(JIM_KEY.fingerprint().matches(cert2.subjectKey)); t.strictEqual(cert2.subjects.length, 3); t.ok(cert2.subjects[0].equals(cert.subjects[0])); t.ok(cert2.subjects[1].equals(cert.subjects[1])); t.strictEqual(cert2.subjects[0].hostname, 'foobar.com'); t.strictEqual(cert2.subjects[1].hostname, 'www.foobar.com'); var ossh = cert.toBuffer('openssh'); var cert3 = sshpk.parseCertificate(ossh, 'openssh'); t.ok(JIM_KEY.fingerprint().matches(cert3.subjectKey)); t.ok(cert3.subjects[0].equals(cert.subjects[0])); t.strictEqual(cert3.subjects.length, 3); t.strictEqual(cert3.subjects[0].hostname, 'foobar.com'); t.strictEqual(cert3.subjects[1].hostname, 'www.foobar.com'); t.end(); }); test('napoleon cert (generalizedtime) (x509)', function (t) { var cert = sshpk.parseCertificate( fs.readFileSync(path.join(testDir, 'napoleon-cert.pem')), 'pem'); t.strictEqual(cert.subjectKey.type, 'rsa'); t.ok(cert.isExpired(new Date('1901-01-01T00:00Z'))); console.log(cert.validFrom.getTime()); console.log(cert.validUntil.getTime()); t.ok(!cert.isExpired(new Date('1775-03-01T00:00Z'))); t.deepEqual(cert.subjects[0].toArray(), [ { name: 'c', value: 'FR' }, { name: 's', value: 'ÃŽle-de-France' }, { name: 'l', value: 'Paris' }, { name: 'o', value: 'Hereditary Monarchy' }, { name: 'ou', value: 'Head of State' }, { name: 'emailAddress', value: 'nappi@greatfrenchempire.fr' }, { name: 'cn', value: 'Emperor Napoleon I' }, { name: 'sn', value: 'Bonaparte' }, { name: 'gn', value: 'Napoleon' } ]); t.end(); }); test('example cert: digicert ca (x509)', function (t) { var cert = sshpk.parseCertificate( fs.readFileSync(path.join(testDir, 'digicert-ca.crt')), 'x509'); t.strictEqual(cert.subjectKey.type, 'rsa'); t.strictEqual(cert.subjects.length, 1); t.deepEqual(cert.purposes.sort(), ['ca', 'clientAuth', 'crl', 'serverAuth', 'signature']); var exts = cert.getExtensions(); t.strictEqual(exts.length, 8); exts.forEach(function (ext) { t.strictEqual(ext.format, 'x509'); t.strictEqual(typeof (ext.oid), 'string'); }); var basicExt = cert.getExtension('2.5.29.19'); t.strictEqual(basicExt.oid, '2.5.29.19'); t.strictEqual(basicExt.critical, true); t.strictEqual(basicExt.format, 'x509'); t.strictEqual(basicExt.pathLen, 0); t.end(); }); test('example cert: digicert (x509)', function (t) { var cert = sshpk.parseCertificate( fs.readFileSync(path.join(testDir, 'digicert.pem')), 'pem'); t.strictEqual(cert.subjectKey.type, 'rsa'); t.strictEqual(cert.subjects.length, 8); t.strictEqual(cert.subjects[0].hostname, 'www.digicert.com'); t.strictEqual(cert.issuer.cn, 'DigiCert SHA2 Extended Validation Server CA'); t.strictEqual(cert.issuer.get('c'), 'US'); t.strictEqual(cert.issuer.get('o'), 'DigiCert Inc'); var cacert = sshpk.parseCertificate( fs.readFileSync(path.join(testDir, 'digicert-ca.crt')), 'x509'); t.ok(cert.isSignedBy(cacert)); t.end(); }); test('example cert: joyent (x509)', function (t) { var data = fs.readFileSync(path.join(testDir, 'joyent.pem')); var cert = sshpk.parseCertificate(data, 'pem'); t.strictEqual(cert.subjectKey.type, 'rsa'); t.strictEqual(cert.subjects[0].type, 'host'); t.strictEqual(cert.subjects[0].hostname, '*.joyent.com'); t.deepEqual(cert.purposes.sort(), ['clientAuth', 'keyEncryption', 'serverAuth', 'signature']); var fp = sshpk.parseFingerprint( 'SHA1:6UMWRUe9vr93cg8AGS7Nwl1XOAA', { type: 'certificate' }); t.ok(fp.matches(cert)); t.end(); }); test('example cert: cloudflare (x509)', function (t) { var cert = sshpk.parseCertificate( fs.readFileSync(path.join(testDir, 'cloudflare.pem')), 'pem'); t.strictEqual(cert.subjectKey.type, 'ecdsa'); var id = sshpk.identityForHost('mail.imeyou.io'); t.ok(cert.subjects.some(function (subj) { return (subj.equals(id)); })); var fp = cert.fingerprint('sha1').toString('hex'); t.strictEqual(fp.toUpperCase(), 'B7:11:BA:8E:83:43:E0:4D:A2:DC:6F:F7:87:2B:5D:78:2C:B1:31:2A'); var cacert = sshpk.parseCertificate( fs.readFileSync(path.join(testDir, 'comodo.crt')), 'x509'); t.ok(cert.isSignedBy(cacert)); t.end(); }); test('example cert: letsencrypt (x509)', function (t) { var cert = sshpk.parseCertificate( fs.readFileSync(path.join(testDir, 'letsencrypt.pem')), 'pem'); t.strictEqual(cert.subjectKey.type, 'rsa'); t.strictEqual(cert.subjects[0].type, 'host'); t.strictEqual(cert.subjects[0].hostname, 'cr.joyent.us'); var fp = cert.fingerprint('sha1').toString('hex'); t.strictEqual(fp.toUpperCase(), '59:8B:FA:BF:F7:DD:D4:B5:7E:8F:53:61:B1:65:0D:DF:F5:4B:CC:72'); t.end(); }); test('example cert: DSA example (x509 DER)', function (t) { var cert = sshpk.parseCertificate( fs.readFileSync(path.join(testDir, '1024b-dsa-example-cert.der')), 'x509'); t.strictEqual(cert.subjectKey.type, 'dsa'); t.strictEqual(cert.subjects[0].type, 'host'); t.strictEqual(cert.subjects[0].hostname, 'www.example.com'); var cacert = sshpk.parseCertificate( fs.readFileSync(path.join(testDir, 'frank4dd-cacert.der')), 'x509'); t.ok(cert.isSignedBy(cacert)); t.end(); }); test('example cert: lots of SAN (x509)', function (t) { var cert = sshpk.parseCertificate( fs.readFileSync(path.join(testDir, 'google_jp_458san.pem')), 'pem'); t.strictEqual(cert.subjectKey.type, 'rsa'); t.strictEqual(cert.subjects[0].type, 'host'); t.strictEqual(cert.subjects[0].hostname, 'google.com'); var id = sshpk.identityForHost('google.co.jp'); t.ok(cert.subjects.some(function (subj) { return (subj.equals(id)); })); t.end(); }); test('example cert: openssh rsa with sha256 (7.0p1+)', function (t) { var cert = sshpk.parseCertificate( fs.readFileSync(path.join(testDir, 'openssh-rsa256.pub')), 'openssh'); t.strictEqual(cert.subjectKey.type, 'rsa'); t.ok(cert.isSignedByKey(cert.subjectKey)); t.strictEqual(cert.signatures.openssh.signature.hashAlgorithm, 'sha256'); t.end(); }); test('example cert: ed25519 cert from curdle-pkix-04', function (t) { var cert = sshpk.parseCertificate( fs.readFileSync(path.join(testDir, 'ed25519-pkix-cert.pem')), 'pem'); t.strictEqual(cert.subjectKey.type, 'curve25519'); t.strictEqual(cert.subjects[0].type, 'user'); t.strictEqual(cert.subjects[0].cn, 'IETF Test Demo'); var key = sshpk.parsePrivateKey( fs.readFileSync(path.join(testDir, 'ed25519-pkix.pem')), 'pem'); t.ok(cert.isSignedByKey(key)); t.end(); }); test('cert with doubled-up DN attribute', function (t) { var cert = sshpk.parseCertificate( fs.readFileSync(path.join(testDir, 'double-title-cert.pem')), 'pem'); var id = cert.subjects[0]; t.throws(function () { id.get('title'); }); t.deepEqual(id.get('title', true), ['in-zone.key', 'in-zone.key']); t.strictEqual(id.get('ou'), 'delegated'); t.strictEqual(id.get('cn'), '2dc79d36-ea01-c855-eab5-e2c7a24abbf4'); t.end(); }); test('example cert: yubikey attestation cert', function (t) { var cert = sshpk.parseCertificate( fs.readFileSync(path.join(testDir, 'yubikey.pem')), 'pem'); t.strictEqual(cert.subjectKey.type, 'ecdsa'); t.strictEqual(cert.subjects[0].cn, 'YubiKey PIV Attestation 9e'); var serialExt = cert.getExtension('1.3.6.1.4.1.41482.3.7'); t.ok(serialExt); var der = new asn1.Ber.Reader(serialExt.data); t.strictEqual(der.readInt(), 5213681); var policyExt = cert.getExtension('1.3.6.1.4.1.41482.3.8'); t.ok(policyExt); t.strictEqual(policyExt.data[0], 0x01); /* never require PIN */ t.strictEqual(policyExt.data[1], 0x01); /* never require touch */ t.end(); }); test('example cert: openssh extensions', function (t) { var cert = sshpk.parseCertificate( fs.readFileSync(path.join(testDir, 'openssh-exts.pub')), 'openssh'); t.strictEqual(cert.subjectKey.type, 'ecdsa'); t.strictEqual(cert.subjects[0].uid, 'foo'); var forceCmdExt = cert.getExtension('force-command'); t.ok(forceCmdExt); t.strictEqual(forceCmdExt.name, 'force-command'); t.strictEqual(forceCmdExt.critical, true); var cmdbuf = new SSHBuffer({ buffer: forceCmdExt.data }); var cmd = cmdbuf.readString(); t.strictEqual(cmd, 'foobarcmd'); t.ok(cmdbuf.atEnd()); t.ok(cert.getExtension('permit-port-forwarding')); t.notOk(cert.getExtension('source-address')); t.notOk(cert.getExtension('permit-pty')); t.end(); }); node-sshpk-1.16.1/test/dhe.js000066400000000000000000000130401342215657600157410ustar00rootroot00000000000000// Copyright 2015 Joyent, Inc. All rights reserved. var test = require('tape').test; var sshpk = require('../lib/index'); var fs = require('fs'); var path = require('path'); var crypto = require('crypto'); var sinon = require('sinon'); var Buffer = require('safer-buffer').Buffer; var ED_KEY, ED2_KEY, EC_KEY, EC2_KEY, ECOUT_KEY, DS_KEY, DS2_KEY, DSOUT_KEY; var C_KEY, C2_KEY; var NG_KEY; var C_SSH; var testDir = path.join(__dirname, 'assets'); test('setup', function (t) { var k = fs.readFileSync(path.join(testDir, 'id_ed25519')); ED_KEY = sshpk.parsePrivateKey(k); k = fs.readFileSync(path.join(testDir, 'id_ed255192')); ED2_KEY = sshpk.parsePrivateKey(k); k = fs.readFileSync(path.join(testDir, 'id_ecdsa2')); EC_KEY = sshpk.parsePrivateKey(k); k = fs.readFileSync(path.join(testDir, 'id_ecdsa3')); EC2_KEY = sshpk.parsePrivateKey(k); k = fs.readFileSync(path.join(testDir, 'id_ecdsa')); ECOUT_KEY = sshpk.parsePrivateKey(k); k = fs.readFileSync(path.join(testDir, 'id_dsa2')); DS_KEY = sshpk.parsePrivateKey(k); k = fs.readFileSync(path.join(testDir, 'id_dsa3')); DS2_KEY = sshpk.parsePrivateKey(k); k = fs.readFileSync(path.join(testDir, 'id_dsa')); DSOUT_KEY = sshpk.parsePrivateKey(k); k = fs.readFileSync(path.join(testDir, 'ed25519-negative')); NG_KEY = sshpk.parsePrivateKey(k); t.end(); }); test('derive ed25519 -> curve25519', function (t) { C_KEY = ED_KEY.derive('curve25519'); t.strictEqual(C_KEY.type, 'curve25519'); t.strictEqual(C_KEY.size, 256); C_SSH = C_KEY.toBuffer('ssh'); C2_KEY = ED2_KEY.derive('curve25519'); t.end(); }); test('derive ed25519 -> curve25519 -> back (negative seed)', function (t) { var key = NG_KEY.derive('curve25519'); t.strictEqual(key.type, 'curve25519'); t.strictEqual(key.size, 256); var key2 = key.derive('ed25519'); t.ok(key2.fingerprint().matches(NG_KEY)); t.strictEqual(key2.part.k.toString('base64'), key.part.k.toString('base64')); t.end(); }); test('derive curve25519 -> ed25519', function (t) { var k = sshpk.parsePrivateKey(C_SSH); t.strictEqual(k.type, 'curve25519'); t.strictEqual(k.size, 256); var k2 = k.derive('ed25519'); t.strictEqual(k2.type, 'ed25519'); t.ok(k2.fingerprint().matches(ED_KEY)); t.strictEqual(k2.part.k.toString('base64'), ED_KEY.part.k.toString('base64')); t.end(); }); test('curve25519 shared secret', function (t) { t.throws(function () { ED_KEY.createDH(); }); var secret1 = C_KEY.createDH().computeSecret(C2_KEY.toPublic()); var secret2 = C2_KEY.createDH().computeSecret(C_KEY); t.deepEqual(secret1, secret2); t.end(); }); test('curve25519 generate ephemeral', function (t) { var dh = C_KEY.toPublic().createDH(); t.throws(function () { dh.computeSecret(C2_KEY.toPublic()); }); var ek = dh.generateKeys(); t.ok(ek instanceof sshpk.PrivateKey); t.strictEqual(ek.type, 'curve25519'); t.end(); }); test('curve25519 validation', function (t) { var dh = C_KEY.createDH(); t.throws(function () { dh.computeSecret(EC_KEY.toPublic()); }); t.throws(function () { dh.setKey(EC_KEY); }); dh.setKey(C2_KEY); t.strictEqual(dh.getKey().fingerprint().toString(), C2_KEY.fingerprint().toString()); t.end(); }); test('ecdhe shared secret', function (t) { var dh1 = EC_KEY.createDH(); var secret1 = dh1.computeSecret(EC2_KEY.toPublic()); t.ok(Buffer.isBuffer(secret1)); t.deepEqual(secret1, Buffer.from( 'UoKiio/gnWj4BdV41YvoHu9yhjynGBmphZ1JFbpk30o=', 'base64')); var dh2 = EC2_KEY.createDH(); var secret2 = dh2.computeSecret(EC_KEY.toPublic()); t.deepEqual(secret1, secret2); t.end(); }); test('ecdhe generate ephemeral', function (t) { var dh = EC_KEY.createDH(); var ek = dh.generateKey(); t.ok(ek instanceof sshpk.PrivateKey); t.strictEqual(ek.type, 'ecdsa'); t.strictEqual(ek.curve, 'nistp256'); var secret1 = dh.computeSecret(EC_KEY); var secret2 = EC_KEY.createDH().computeSecret(ek); t.deepEqual(secret1, secret2); t.end(); }); test('ecdhe reject diff curves', function (t) { var dh = EC_KEY.createDH(); t.throws(function () { dh.computeSecret(ECOUT_KEY.toPublic()); }); t.throws(function () { dh.setKey(ECOUT_KEY); }); dh.setKey(EC2_KEY); t.strictEqual(dh.getKey().fingerprint().toString(), EC2_KEY.fingerprint().toString()); var dh2 = ECOUT_KEY.createDH(); t.throws(function () { dh2.setKey(EC_KEY); }); dh2 = EC_KEY.createDH(); t.throws(function () { dh2.setKey(C_KEY); }); t.end(); }); /* node 0.10 and earlier do not support DHE properly */ if (process.version.match(/^v0\.10\./)) return; test('dhe shared secret', function (t) { var dh1 = DS_KEY.createDiffieHellman(); var secret1 = dh1.computeSecret(DS2_KEY.toPublic()); t.ok(Buffer.isBuffer(secret1)); var dh2 = DS2_KEY.createDiffieHellman(); var secret2 = dh2.computeSecret(DS_KEY.toPublic()); t.deepEqual(secret1, secret2); t.end(); }); test('dhe reject diff primes', function (t) { var dh = DS_KEY.createDH(); t.throws(function () { dh.computeSecret(DSOUT_KEY.toPublic()); }); t.throws(function () { dh.setKey(DSOUT_KEY); }); dh.setKey(DS2_KEY); t.strictEqual(dh.getKey().fingerprint().toString(), DS2_KEY.fingerprint().toString()); var dh2 = DSOUT_KEY.createDH(); t.throws(function () { dh2.setKey(DS_KEY); }); t.end(); }); test('dhe generate ephemeral', function (t) { var dh = DS_KEY.toPublic().createDH(); t.throws(function () { dh.computeSecret(DS2_KEY); }); var ek = dh.generateKey(); t.ok(ek instanceof sshpk.PrivateKey); t.strictEqual(ek.type, 'dsa'); t.strictEqual(ek.size, 2048); var secret1 = dh.computeSecret(DS_KEY); var secret2 = DS_KEY.createDH().computeSecret(ek); t.deepEqual(secret1, secret2); t.end(); }); node-sshpk-1.16.1/test/dhe_compat.js000066400000000000000000000061451342215657600173140ustar00rootroot00000000000000// Copyright 2017 Joyent, Inc. All rights reserved. var test = require('tape').test; var sshpk = require('../lib/index'); var sshpk_dhe; var fs = require('fs'); var path = require('path'); var crypto = require('crypto'); var sinon = require('sinon'); var Buffer = require('safer-buffer').Buffer; /* No need to do these on an older node */ if (crypto.createECDH === undefined) return; var ED_KEY, ED2_KEY, EC_KEY, EC2_KEY, ECOUT_KEY, DS_KEY, DS2_KEY, DSOUT_KEY; var C_KEY, C2_KEY; var C_SSH; var testDir = path.join(__dirname, 'assets'); var sandbox; test('set up sandbox', function (t) { sandbox = sinon.sandbox.create(); sandbox.stub(crypto, 'createECDH'); t.ok(crypto.createECDH('prime256v1') === undefined); var name = require.resolve('../lib/dhe'); delete (require.cache[name]); sshpk_dhe = require('../lib/dhe'); t.end(); }); test('setup', function (t) { var k = fs.readFileSync(path.join(testDir, 'id_ed25519')); ED_KEY = sshpk.parsePrivateKey(k); k = fs.readFileSync(path.join(testDir, 'id_ed255192')); ED2_KEY = sshpk.parsePrivateKey(k); k = fs.readFileSync(path.join(testDir, 'id_ecdsa2')); EC_KEY = sshpk.parsePrivateKey(k); k = fs.readFileSync(path.join(testDir, 'id_ecdsa3')); EC2_KEY = sshpk.parsePrivateKey(k); k = fs.readFileSync(path.join(testDir, 'id_ecdsa')); ECOUT_KEY = sshpk.parsePrivateKey(k); k = fs.readFileSync(path.join(testDir, 'id_dsa2')); DS_KEY = sshpk.parsePrivateKey(k); k = fs.readFileSync(path.join(testDir, 'id_dsa3')); DS2_KEY = sshpk.parsePrivateKey(k); k = fs.readFileSync(path.join(testDir, 'id_dsa')); DSOUT_KEY = sshpk.parsePrivateKey(k); t.end(); }); test('ecdhe shared secret', function (t) { var dh1 = new sshpk_dhe.DiffieHellman(EC_KEY); var secret1 = dh1.computeSecret(EC2_KEY.toPublic()); t.ok(Buffer.isBuffer(secret1)); t.deepEqual(secret1, Buffer.from( 'UoKiio/gnWj4BdV41YvoHu9yhjynGBmphZ1JFbpk30o=', 'base64')); var dh2 = new sshpk_dhe.DiffieHellman(EC2_KEY); var secret2 = dh2.computeSecret(EC_KEY.toPublic()); t.deepEqual(secret1, secret2); t.end(); }); test('ecdhe generate ephemeral', function (t) { var dh = new sshpk_dhe.DiffieHellman(EC_KEY); var ek = dh.generateKey(); t.ok(ek instanceof sshpk.PrivateKey); t.strictEqual(ek.type, 'ecdsa'); t.strictEqual(ek.curve, 'nistp256'); var secret1 = dh.computeSecret(EC_KEY); var secret2 = (new sshpk_dhe.DiffieHellman(EC_KEY)).computeSecret(ek); t.deepEqual(secret1, secret2); t.end(); }); test('ecdhe reject diff curves', function (t) { var dh = new sshpk_dhe.DiffieHellman(EC_KEY); t.throws(function () { dh.computeSecret(ECOUT_KEY.toPublic()); }); t.throws(function () { dh.setKey(ECOUT_KEY); }); dh.setKey(EC2_KEY); t.strictEqual(dh.getKey().fingerprint().toString(), EC2_KEY.fingerprint().toString()); t.strictEqual(dh.getPublicKey().fingerprint().toString(), EC2_KEY.fingerprint().toString()); var dh2 = new sshpk_dhe.DiffieHellman(ECOUT_KEY); t.throws(function () { dh2.setKey(EC_KEY); }); dh2 = new sshpk_dhe.DiffieHellman(EC_KEY); t.throws(function () { dh2.setKey(C_KEY); }); t.end(); }); test('tear down sandbox', function (t) { sandbox.restore(); t.end(); }); node-sshpk-1.16.1/test/dnssec.js000066400000000000000000000076221342215657600164710ustar00rootroot00000000000000// Copyright 2017 Joyent, Inc. All rights reserved. var test = require('tape').test; var fs = require('fs'); var path = require('path'); var sshpk = require('../lib/index'); var testDir = path.join(__dirname, 'assets'); /* * Generated with: * 'dnssec-keygen -T KEY -a rsasha1 -b 1024 -n USER rsatest' * * which outputs two files named 'Krsatest.+005+57206.private' and * 'Krsatest.+005+57206.key' */ var DNSSEC_RSA, DNSSEC_RSA_PUB, PEM_RSA, PEM_RSA_PUB; /* * Generated with: * 'dnssec-keygen -T KEY -a ECDSAP256SHA256 -n USER ecdsatest' * * which outputs two files named 'Kecdsatest.+013+43896.private' and * 'Kecdsatest.+013+43896.key' */ var DNSSEC_ECDSA, DNSSEC_ECDSA_PUB, PEM_ECDSA, PEM_ECDSA_PUB; function readAsString(f) { var s = fs.readFileSync(path.join(testDir, f)); return s.toString('utf8'); } test('setup', function (t) { DNSSEC_RSA = readAsString('Krsatest.+005+57206.private'); DNSSEC_RSA_PUB = readAsString('Krsatest.+005+57206.key'); PEM_RSA = readAsString('Krsatest.+005+57206.pem'); PEM_RSA_PUB = readAsString('Krsatest.+005+57206_pub.pem'); DNSSEC_ECDSA = readAsString('Kecdsatest.+013+43896.private'); DNSSEC_ECDSA_PUB = readAsString('Kecdsatest.+013+43896.key'); PEM_ECDSA = readAsString('Kecdsatest.+013+43896.pem'); PEM_ECDSA_PUB = readAsString('Kecdsatest.+013+43896_pub.pem'); t.end(); }); // --- Tests // read tests test('1024b dnssec to pem private key', function(t) { var k = sshpk.parsePrivateKey(DNSSEC_RSA, 'dnssec'); t.strictEqual(k.toString('pem'), PEM_RSA); t.end(); }); test('1024b dnssec to pem public key', function(t) { var k = sshpk.parsePrivateKey(DNSSEC_RSA, 'dnssec'); t.strictEqual(k.toPublic().toString('pem'), PEM_RSA_PUB); t.end(); }); test('1024b dnssec public key to pem', function(t) { var k = sshpk.parseKey(DNSSEC_RSA_PUB, 'dnssec'); t.strictEqual(k.toString('pem'), PEM_RSA_PUB); t.end(); }); test('1024b auto dnssec to pem private key', function(t) { var k = sshpk.parsePrivateKey(DNSSEC_RSA, 'auto'); t.strictEqual(k.toString('pem'), PEM_RSA); t.end(); }); test('1024b auto dnssec public key to pem', function(t) { var k = sshpk.parseKey(DNSSEC_RSA_PUB, 'auto'); t.strictEqual(k.toString('pem'), PEM_RSA_PUB); t.end(); }); test('ecdsa dnssec to pem private key', function(t) { var k = sshpk.parsePrivateKey(DNSSEC_ECDSA, 'dnssec'); t.strictEqual(k.toString('pem'), PEM_ECDSA); t.end(); }); test('ecdsa dnssec to pem public key', function(t) { var k = sshpk.parsePrivateKey(DNSSEC_ECDSA, 'dnssec'); t.strictEqual(k.toPublic().toString('pem'), PEM_ECDSA_PUB); t.end(); }); // write tests //--- Tests function stripDNSSECTimestamp(m) { var out = [] var lines = m.split('\n'); lines.forEach(function(line) { if (line.match(/^Created.*/) || line.match(/^Publish.*/) || line.match(/^Activate.*/)) { return; } else { if (line.length > 1) out.push(line); } }); return (out.join('\n')); } // DNSSEC keys have timestamps -- for the comparison we'll strip them. test('1024b pem private key to dnssec', function(t) { var k = sshpk.parsePrivateKey(PEM_RSA, 'pem'); k = stripDNSSECTimestamp(k.toString('dnssec')); t.strictEqual(k, stripDNSSECTimestamp(DNSSEC_RSA)); t.end(); }); test('1024b auto pem private key to dnssec', function(t) { var k = sshpk.parsePrivateKey(PEM_RSA, 'auto'); k = stripDNSSECTimestamp(k.toString('dnssec')); t.strictEqual(k, stripDNSSECTimestamp(DNSSEC_RSA)); t.end(); }); test('ecdsa pem private key to dnssec', function(t) { var k = sshpk.parsePrivateKey(PEM_RSA, 'pem'); k = stripDNSSECTimestamp(k.toString('dnssec')); t.strictEqual(k, stripDNSSECTimestamp(DNSSEC_RSA)); t.end(); }); test('ecdsa auto pem private key to dnssec', function(t) { var k = sshpk.parsePrivateKey(DNSSEC_ECDSA, 'auto'); k = stripDNSSECTimestamp(k.toString('dnssec')); t.strictEqual(k, stripDNSSECTimestamp(DNSSEC_ECDSA)); t.end(); }); node-sshpk-1.16.1/test/fingerprint.js000066400000000000000000000130501342215657600175310ustar00rootroot00000000000000// Copyright 2018 Joyent, Inc. All rights reserved. var test = require('tape').test; var fs = require('fs'); var path = require('path'); var sshpk = require('../lib/index'); var testDir = path.join(__dirname, 'assets'); var SSH_1024 = 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvad19ePSDckmgmo6Unqmd8' + 'n2G7o1794VN3FazVhV09yooXIuUhA+7OmT7ChiHueayxSubgL2MrO/HvvF/GGVUs/t3e0u4' + '5YwRC51EVhyDuqthVJWjKrYxgDMbHru8fc1oV51l0bKdmvmJWbA/VyeJvstoX+eiSGT3Jge' + 'egSMVtc= mark@foo.local'; var SSH_2048 = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDrm0RN90tGM0/vcJgzJ4uW9' + 'aT9iRzNQXYq4OQvsVgb2xRZ0mLwjmTOY4MJ2qWk8ENptY5yQBolpjjI0ziWaFfgo56fe' + 'XC1iRN/FkBQw+JJSjOwzTWw8JWU5HF+mt9BPzj6hC2dVniCHt+9lRLDqqYd14bhDMHE0' + 'XdRtX7Fv6bRkE+XxHdo8ITh1fZVShV3ukKC0KJbFBlNu8+Uu9bl8ZioyyFjwiw6bzQNY' + '3NXYFotzA9qDgHl+V0sldJLBCB+uilW1dns6pAfH2FxX3euZwnm+FGSKi9tI2wAW1EoV' + 'SoBmUZAYAs+BqffNJHnIv1dexMmwdJdlZUeRK1Q1ES15gxx '+ 'mark@foo.local'; var SSH_MPNORM = 'ssh-rsa AAAAB3NzaC1yc2EAAAAEAAEAAQAAAQEAjb4zpS1Sl1m4szYzV/o' + 'GgHmYM5zI/yvWESgltLZVpSY6i3UDljPEPJSRdCiDnPl8qgyWtU4YbRwctmZUqA9DvKA' + 'GCcFSZ9OLkhBruPvKFi0Q+fgBEbR/tlLgXppi1EXEZwtUe97axsrp7DSrgbUYfNNRTtO' + 'eVnAlosM+KkER8xIqNWJ4aQEPBE2MA0YcC4PYT/KdD1ap8Xdxucsy9YPVrqKT0Zql0Dy' + 'SPt8hTmtJe78KjWsbAjaQvUbNg6lUxCGf6A/qym8smu9fGaYg2MUReVyhvxavBS64IV7' + 'FrKCE76+lDQfM4UQqszW+ZtSv9EwbUPF7SyAHzKB4HRSgBLDViw== token-key'; var ED_SSH = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEi0pkfPe/+kbmnTSH0mfr0J4' + 'Fq7M7bshFAKB6uCyLDm foo@bar'; var ED2_SSH = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPu+h5Zu8GHgh8seZ9GittT' + 'WHfpbi0vkNksH77yaMKqD'; var ED2_PEM = '-----BEGIN PUBLIC KEY-----\n' + 'MCowBQYDK2VwAyEA+76Hlm7wYeCHyx5n0aK21NYd+luLS+Q2SwfvvJowqoM=\n' + '-----END PUBLIC KEY-----\n'; test('fingerprint', function(t) { var k = sshpk.parseKey(SSH_1024, 'ssh'); var fp = k.fingerprint('md5').toString(); t.equal(fp, '59:a4:61:0e:38:18:9f:0f:28:58:2a:27:f7:65:c5:87'); t.end(); }); test('fingerprint of key w/non-normalized mpint', function(t) { var k = sshpk.parseKey(SSH_MPNORM, 'ssh'); var fp = k.fingerprint('sha256').toString(); t.equal(fp, 'SHA256:uOCmXUwfjh90NlLAxI9/vGG9ewUqcHlM5dYYFLJlZyc'); t.end(); }); test('sha1 fingerprint', function(t) { var k = sshpk.parseKey(SSH_1024, 'ssh'); var fp = k.fingerprint('sha1').toString(); t.equal(fp, 'SHA1:3JP2y/wCv8KnvAunLz7EjcEhKeE'); t.end(); }); test('sha256 fingerprint', function(t) { var k = sshpk.parseKey(SSH_1024, 'ssh'); var fp = k.fingerprint('sha256').toString(); t.equal(fp, 'SHA256:n0akL6ACGYcTARqym7TL4DStmNFpxMkSlFwuCfqNP9M'); t.end(); }); test('spki sha256 fingerprint', function (t) { var k = sshpk.parseKey(SSH_1024, 'ssh'); var fp2 = k.fingerprint('sha256', 'spki').toString(); t.equal(fp2, 'c8f710c0a469a5e0cad31b10175e672665b926f4e75aad5447e9f1005a2aec93'); var fp = sshpk.parseFingerprint(fp2); t.ok(fp.matches(k)); var fp3 = k.fingerprint('sha1', 'spki').toString('base64'); t.equal(fp3, 'HleMUmn/a1NRW5iUZsEKCe+ojTw='); t.end(); }); test('fingerprints of a private key', function (t) { var pem = fs.readFileSync(path.join(testDir, 'id_ecdsa')); var k = sshpk.parsePrivateKey(pem, 'pem'); var pk = k.toPublic(); var fp1 = k.fingerprint('sha512'); t.ok(fp1.matches(pk)); var fp2 = pk.fingerprint('sha512'); t.ok(fp2.matches(k)); t.equal(fp1.toString(), fp2.toString()); var fp3 = k.fingerprint('sha256', 'spki'); t.ok(fp3.matches(pk)); var fp4 = pk.fingerprint('sha256', 'spki'); t.ok(fp4.matches(k)); t.equal(fp3.toString(), fp4.toString()); t.end(); }); test('fingerprint with invalid algo', function(t) { var k = sshpk.parseKey(SSH_1024, 'ssh'); t.throws(function() { k.fingerprint('foo1234'); }, sshpk.InvalidAlgorithmError); t.end(); }); test('parse fingerprint with invalid algo', function(t) { t.throws(function () { sshpk.parseFingerprint('FOO1234:aaaaaaa'); }); t.end(); }); test('fingerprint matches', function(t) { var k1 = sshpk.parseKey(SSH_1024, 'ssh'); var k2 = sshpk.parseKey(SSH_2048, 'ssh'); var f = sshpk.parseFingerprint( 'SHA256:PYC9kPVC6J873CSIbfp0LwYeczP/W4ffObNCuDJ1u5w'); t.ok(f.matches(k2)); t.ok(!f.matches(k1)); var f2 = sshpk.parseFingerprint( '59:a4:61:0e:38:18:9f:0f:28:58:2a:27:f7:65:c5:87'); t.ok(f2.matches(k1)); t.ok(!f2.matches(k2)); var f3 = sshpk.parseFingerprint( 'MD5:59:a4:61:e:38:18:9f:f:28:58:2a:27:f7:65:c5:87'); t.ok(f3.matches(k1)); t.ok(!f3.matches(k2)); var f4 = sshpk.parseFingerprint( 'SHA1:3JP2y/wCv8KnvAunLz7EjcEhKeE'); t.ok(f4.matches(k1)); t.ok(!f4.matches(k2)); t.end(); }); test('fingerprint of ed25519 key', function(t) { var k = sshpk.parseKey(ED_SSH, 'ssh'); var f = sshpk.parseFingerprint( 'SHA256:2UeFLCUKw2lvd8O1zfINNVzE0kUcu2HJHXQr/TGHt60'); t.ok(f.matches(k)); t.end(); }); test('fingerprint of non-normalized ed25519 key', function(t) { var k = sshpk.parseKey(ED2_SSH, 'ssh'); var f = sshpk.parseFingerprint( 'SHA256:k1NS4bL2M1fG3JKd8WI9t6ETq+6VeRtvLAxt8DC0exE'); t.ok(f.matches(k)); k = sshpk.parseKey(ED2_PEM, 'pem'); t.ok(f.matches(k)); t.end(); }); test('invalid fingerprints', function(t) { t.throws(function () { var fp = sshpk.parseFingerprint( 'zzzzz!!!'); }, sshpk.FingerprintFormatError); t.throws(function () { var fp = sshpk.parseFingerprint( 'SHA256:XXX%!@!#!@#!*'); }, sshpk.FingerprintFormatError); t.throws(function () { var fp = sshpk.parseFingerprint( '59:a4:61:0e:38:18:9f:0f:28:58:2a:27:f7:65:c5:878'); }, sshpk.FingerprintFormatError); t.throws(function () { var fp = sshpk.parseFingerprint( '59:a46:1:0e:38:18:9f:0f:28:58:2a:27:f7:65:c5:87'); }, sshpk.FingerprintFormatError); t.end(); }); node-sshpk-1.16.1/test/horrors.js000066400000000000000000000135011342215657600167010ustar00rootroot00000000000000// Copyright 2015 Joyent, Inc. All rights reserved. var test = require('tape').test; var sshpk = require('../lib/index'); var KEY_LOST_WEQ = 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvad19ePSDckmgmo6Unqmd8' + 'n2G7o1794VN3FazVhV09yooXIuUhA+7OmT7ChiHueayxSubgL2MrO/HvvF/GGVUs/t3e0u4' + '5YwRC51EVhyDuqthVJWjKrYxgDMbHru8fc1oV51l0bKdmvmJWbA/VyeJvstoX+eiSGT3Jge' + 'egSMVtc=mark@foo.local'; test('lost whitespace before comment', function (t) { var k = sshpk.parseKey(KEY_LOST_WEQ, 'ssh'); t.strictEqual(k.type, 'rsa'); t.strictEqual(k.fingerprint('sha256').toString(), 'SHA256:n0akL6ACGYcTARqym7TL4DStmNFpxMkSlFwuCfqNP9M'); t.strictEqual(k.comment, 'mark@foo.local'); t.end(); }); var KEY_LOST_EQ = 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvad19ePSDckmgmo6Unqmd8' + 'n2G7o1794VN3FazVhV09yooXIuUhA+7OmT7ChiHueayxSubgL2MrO/HvvF/GGVUs/t3e0u4' + '5YwRC51EVhyDuqthVJWjKrYxgDMbHru8fc1oV51l0bKdmvmJWbA/VyeJvstoX+eiSGT3Jge' + 'egSMVtcmark@foo.local'; test('lost whitespace and equals before comment', function (t) { var k = sshpk.parseKey(KEY_LOST_EQ, 'ssh'); t.strictEqual(k.type, 'rsa'); t.strictEqual(k.fingerprint('sha256').toString(), 'SHA256:n0akL6ACGYcTARqym7TL4DStmNFpxMkSlFwuCfqNP9M'); t.strictEqual(k.comment, 'mark@foo.local'); t.end(); }); var KEY_LOST = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDSNsN/sEEwzcDfKwi1aJwAb' + 'f8lTkOSvC6JujRlWzmI7HjWmBephEGyFOY3FAYLRHNLNDDL/NSGcWTp08zLGbCeOey3hCGwm' + 'msr5zH9sQIslD1ruGlXNWdV2hIF1VHfGPGlX5Sx1vz6ARKyp1jvMVWyhJNsH4lCEkl+5R8Y7' + 'op+YwhjOyMqOmxhzQ8I6npXgo8JRsSZs0ikfUpORoMg+G2G62uDgYsRFYNZhHo5zv/1dV4rz' + 'x9Tn6sgjgZ99sEymPLL1o8i53MjH31CMW8//SR4xgIVSABI831wsJIz0dj3khcSIrLbT3qOT' + 'QtMcXDKBpk9+5AfNtHlCN5Ba68bU+W7alex@Alexs-MacBook-Pro-7.local'; test('lost whitespace, no equals', function (t) { var k = sshpk.parseKey(KEY_LOST, 'ssh'); t.strictEqual(k.type, 'rsa'); t.strictEqual(k.fingerprint('sha256').toString(), 'SHA256:+lMZah1Mq1FnDRtPpiz6kxpx7nrqQe5okKakQOvLEZE'); t.strictEqual(k.comment, 'alex@Alexs-MacBook-Pro-7.local'); t.end(); }); var KEY_NEWLINE = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEi0pkfPe/+kbmnTSH0mfr0J4' + 'Fq7M7bshFAKB6uCyLDm\nfoo@bar'; test('newline before comment instead of space', function (t) { var k = sshpk.parseKey(KEY_NEWLINE, 'ssh'); t.strictEqual(k.type, 'ed25519'); t.strictEqual(k.comment, 'foo@bar'); t.strictEqual(k.fingerprint('sha256').toString(), 'SHA256:2UeFLCUKw2lvd8O1zfINNVzE0kUcu2HJHXQr/TGHt60'); t.end(); }); var KEY_LINES = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDSNsN/sEEwzcDfKwi1aJwAb\n' + 'f8lTkOSvC6JujRlWzmI7HjWmBephEGyFOY3FAYLRHNLNDDL/NSGcWTp08zLGbCeOey3hCGwm\r\n' + 'msr5zH9sQIslD1ruGlXNWdV2hIF1VHfGPGlX5Sx1vz6ARKyp1jvMVWyhJNsH4lCEkl+5R8Y7\n' + 'op+YwhjOyMqOmxhzQ8I6npXgo8JRsSZs0ikfUpORoMg+G2G62uDgYsRFYNZhHo5zv/1dV4rz\r\n' + 'x9Tn6sgjgZ99sEymPLL1o8i53MjH31CMW8//SR4xgIVSABI831wsJIz0dj3khcSIrLbT3qOT\n' + 'QtMcXDKBpk9+5AfNtHlCN5Ba68bU+W7\r\nalex@Alexs-MacBook-Pro-7.local'; test('newlines everywhere', function (t) { var k = sshpk.parseKey(KEY_LINES, 'ssh'); t.strictEqual(k.type, 'rsa'); t.strictEqual(k.fingerprint('sha256').toString(), 'SHA256:+lMZah1Mq1FnDRtPpiz6kxpx7nrqQe5okKakQOvLEZE'); t.strictEqual(k.comment, 'alex@Alexs-MacBook-Pro-7.local'); t.end(); }); var KEY_CONTINU = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDSNsN/sEEwzcDfKwi1aJwAb\\\n' + 'f8lTkOSvC6JujRlWzmI7HjWmBephEGyFOY3FAYLRHNLNDDL/NSGcWTp08zLGbCeOey3hCGwm \\\r\n' + 'msr5zH9sQIslD1ruGlXNWdV2hIF1VHfGPGlX5Sx1vz6ARKyp1jvMVWyhJNsH4lCEkl+5R8Y7\\\n' + 'op+YwhjOyMqOmxhzQ8I6npXgo8JRsSZs0ikfUpORoMg+G2G62uDgYsRFYNZhHo5zv/1dV4rz\\\r\n' + 'x9Tn6sgjgZ99sEymPLL1o8i53MjH31CMW8//SR4xgIVSABI831wsJIz0dj3khcSIrLbT3qOT \\\n' + 'QtMcXDKBpk9+5AfNtHlCN5Ba68bU+W7 \\\r\nalex@Alexs-MacBook-Pro-7.local'; test('line continuations, key from hell', function (t) { var k = sshpk.parseKey(KEY_CONTINU, 'ssh'); t.strictEqual(k.type, 'rsa'); t.strictEqual(k.fingerprint('sha256').toString(), 'SHA256:+lMZah1Mq1FnDRtPpiz6kxpx7nrqQe5okKakQOvLEZE'); t.strictEqual(k.comment, 'alex@Alexs-MacBook-Pro-7.local'); t.end(); }); var KEY_NO_COMMENT = 'ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAA' + 'IbmlzdHAyNTYAAABBBK9+hFGVZ9RT61pg8t7EGgkvduhPr/CBYfx+5rQFEROj8EjkoGIH2xy' + 'pHOHBz0WikK5hYcwTM5YMvnNxuU0h4+c='; test('normal key, no comment', function (t) { var k = sshpk.parseKey(KEY_NO_COMMENT, 'ssh'); t.strictEqual(k.type, 'ecdsa'); t.strictEqual(k.fingerprint('sha256').toString(), 'SHA256:Kyu0EMqH8fzfp9RXKJ6kmsk9qKGBqVRtlOuk6bXfCEU'); t.strictEqual(k.comment, '(unnamed)'); t.end(); }); var KEY_COMMENT_EQ = 'ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAA' + 'IbmlzdHAyNTYAAABBBK9+hFGVZ9RT61pg8t7EGgkvduhPr/CBYfx+5rQFEROj8EjkoGIH2xy' + 'pHOHBz0WikK5hYcwTM5YMvnNxuU0h4+c= abc=def=a\n'; test('comment contains =, trailing newline', function (t) { var k = sshpk.parseKey(KEY_COMMENT_EQ, 'ssh'); t.strictEqual(k.type, 'ecdsa'); t.strictEqual(k.fingerprint('sha256').toString(), 'SHA256:Kyu0EMqH8fzfp9RXKJ6kmsk9qKGBqVRtlOuk6bXfCEU'); t.strictEqual(k.comment, 'abc=def=a'); t.end(); }); var KEY_BREAK = 'ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzd' + 'HAyNTYAAABBBK9+hFGVZ9RT61pg8t7\nEGgkvduhPr/CBYfx+5rQFEROj8EjkoGIH2xypHOH' + 'Bz0WikK5hYcwTM5YMvnNxuU0h4+c='; test('line broken in the middle, no comment', function (t) { var k = sshpk.parseKey(KEY_BREAK, 'ssh'); t.strictEqual(k.type, 'ecdsa'); t.strictEqual(k.fingerprint('sha256').toString(), 'SHA256:Kyu0EMqH8fzfp9RXKJ6kmsk9qKGBqVRtlOuk6bXfCEU'); t.strictEqual(k.comment, '(unnamed)'); t.end(); }); var KEY_WOOPS = 'ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoTItbmlzdHAyNTYAAAAIbmlzd' + 'HAyNTYAAABBBK9+hFGVZ9RT61pg8t7\nEGgkvduhPr/CBYfx+5rQFEROj8EjkoGIH2xypHOH' + 'Bz0WikK5hYcwTM5YMvnNxuU0h4+c='; test('missing character in middle', function (t) { t.throws(function () { sshpk.parseKey(KEY_WOOPS, 'ssh'); }); t.end(); }); node-sshpk-1.16.1/test/identity.js000066400000000000000000000023141342215657600170340ustar00rootroot00000000000000// Copyright 2016 Joyent, Inc. All rights reserved. var test = require('tape').test; var sshpk = require('../lib/index'); var fs = require('fs'); var path = require('path'); var crypto = require('crypto'); var sinon = require('sinon'); test('parsedn', function (t) { var id = sshpk.Identity.parseDN('cn=Blah Corp, s=CA, c=US'); t.strictEqual(id.type, 'user'); t.strictEqual(id.cn, 'Blah Corp'); t.end(); }); test('parsedn escapes', function (t) { var id = sshpk.Identity.parseDN('cn=what\\,something,o=b==a,c=\\US'); t.strictEqual(id.get('cn'), 'what,something'); t.strictEqual(id.get('o'), 'b==a'); t.strictEqual(id.get('c'), '\\US'); id = sshpk.Identity.parseDN('cn\\=foo=bar'); t.strictEqual(id.get('cn=foo'), 'bar'); t.throws(function () { sshpk.Identity.parseDN('cn\\\\=foo'); }); t.end(); }); test('fromarray', function (t) { var arr = [ { name: 'ou', value: 'foo' }, { name: 'ou', value: 'bar' }, { name: 'cn', value: 'foobar,g=' } ]; var id = sshpk.identityFromArray(arr); t.throws(function () { id.get('ou'); }); t.deepEqual(id.get('ou', true), ['foo', 'bar']); t.strictEqual(id.get('cn'), 'foobar,g='); t.strictEqual(id.toString(), 'OU=foo, OU=bar, CN=foobar\\,g='); t.end(); }); node-sshpk-1.16.1/test/metadata.js000066400000000000000000000054761342215657600167770ustar00rootroot00000000000000// Copyright 2011 Joyent, Inc. All rights reserved. var test = require('tape').test; var sshpk = require('../lib/index'); var SSH_1024 = 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvad19ePSDckmgmo6Unqmd8' + 'n2G7o1794VN3FazVhV09yooXIuUhA+7OmT7ChiHueayxSubgL2MrO/HvvF/GGVUs/t3e0u4' + '5YwRC51EVhyDuqthVJWjKrYxgDMbHru8fc1oV51l0bKdmvmJWbA/VyeJvstoX+eiSGT3Jge' + 'egSMVtc= mark@foo.local'; var SSH_1133 = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAjhShSqMBQvr+UtupcZj+l15' + 'W9LKZ5NDKlUY5af6sGQTaaKCg1Ag5tsi3TrQeAqykdrz7Ugu3BPkLlgk2NvqziX6FdFKjw' + 'hEEOsHPDFy5Z3ak4oYicHYZVg34pUYvps7dVbYE8D4Ba70txpMEgB3YIS+hUdqiHCIxZKW' + 'V0PCXTAjjhDyN7I9KI7F4bSAGNf0='; var PEM_2048 = '-----BEGIN PUBLIC KEY-----\n' + 'MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAr+isTwMYqwCAcY0Yb2F0\n' + 'pF+/F4/wxGzcrLR2PrgoBXwjj/TnEA3tJ7v08Rru3lAd/O59B6TbXOsYbQ+2Syd8\n' + '2Dm8L3SJRNlZJ6DZUOAwnTOoNgkfH2CsbGS84aTPTeXjmMsw52GvQ9yWFDUglHzM\n' + 'IzK2iSHWNl1dAaBEiddifGmrpUTPJ5Tt7l8YS4jdaBf6klS+3CvL6xET/RjZhKGt\n' + 'rrgsRRYUB2XVtgQhKDu7PtDdlpy4+VISdVhZSlXFnBhya/1KxLS5UFHSAdOjdxzW\n' + '1bh3cPzNtuPXZaiWUHvyIWpGVCzj5NyeDXcc7n0E20yx9ZDkAITuI8X49rnQzuCN\n' + '5QIBIw==\n' + '-----END PUBLIC KEY-----\n'; var ECDSA_256 = 'ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIb' + 'mlzdHAyNTYAAABBBDxYMQuEL51ja1vNXsH8gFXmOjJhVEI9Osv+rvt8vHjJK4FyIc' + '46H2406iAGE/rZcqeSjPbmcORXgCNNBlLJ0QQ= ' + 'alex.wilson@awilson-mbp.local'; var DSA_1024 = 'ssh-dss AAAAB3NzaC1kc3MAAACBAKK5sckoM05sOPajUcTWG0zPTvyRmj6' + 'YQ1g2IgezUUrXgY+2PPy07+JrQi8SN9qr/CBP+0q0Ec48qVFf9LlkUBwu9Jf5HTUVNiKNj3c' + 'SRPFH8HqZn+nxhVsOLhnHWxgDQ8OOm48Ma61NcYVo2B0Ne8cUs8xSqLqba2EG9ze87FQZAAA' + 'AFQCVP/xpiAofZRD8L4QFwxOW9krikQAAAIACNv0EmKr+nIA13fjhpiqbYYyVXYOiWM4cmOD' + 'G/d1J8/vR4YhWHWPbAEw7LD0DEwDIHLlRZr/1jsHbFcwt4tzRs95fyHzpucpGhocmjWx43qt' + 'xEhDeJrxPlkIXHakciAEhoo+5YeRSSgRse5PrZDosdr5fA+DADs8tnto5Glf5owAAAIBHcEF' + '5ytvCRiKbsWKOgeMZ7JT/XGX+hMhS7aaJ2IspKj7YsWada1yBwoM6yYHtlpnGsq/PoPaZU8K' + '40f47psV6OhSh+/O/jgqLS/Ur2c0mQQqIb7vvkc7he/SPOQAqyDmyYFBuazuSf2s9Uy2hfvj' + 'Wgb6X+vN9W8SOb2668IL7Vg== mark@bluesnoop.local'; test('rsa1024 key metadata', function(t) { var k = sshpk.parseKey(SSH_1024, 'ssh'); t.equal(k.type, 'rsa'); t.equal(k.size, 1024); t.end(); }); test('rsa1133 key metadata', function(t) { var k = sshpk.parseKey(SSH_1133, 'ssh'); t.equal(k.type, 'rsa'); t.equal(k.size, 1133); t.end(); }); test('dsa1024 key metadata', function(t) { var k = sshpk.parseKey(DSA_1024, 'ssh'); t.equal(k.type, 'dsa'); t.equal(k.size, 1024); t.end(); }); test('rsa2048 pem key metadata', function(t) { var k = sshpk.parseKey(PEM_2048, 'pem'); t.equal(k.type, 'rsa'); t.equal(k.size, 2048); t.end(); }); test('ecdsa256 key metadata', function(t) { var k = sshpk.parseKey(ECDSA_256, 'ssh'); t.equal(k.type, 'ecdsa'); t.equal(k.curve, 'nistp256'); t.equal(k.size, 256); t.end(); }); node-sshpk-1.16.1/test/openssl-cmd.js000066400000000000000000000460711342215657600174370ustar00rootroot00000000000000// Copyright 2018 Joyent, Inc. All rights reserved. var test = require('tape').test; var sshpk = require('../lib/index'); var path = require('path'); var fs = require('fs'); var temp = require('temp'); var testDir = path.join(__dirname, 'assets'); var spawn = require('child_process').spawn; var FPS = {}; FPS.rsa = sshpk.parseFingerprint( 'SHA256:tT5wcGMJkBzNu+OoJYEgDCwIcDAIFCUahAmuTT4qC3s'); FPS.dsa = sshpk.parseFingerprint( 'SHA256:PCfwpK62grBWrAJceLetSNv9CTrX8yoD0miKf11DBG8'); FPS.ecdsa = sshpk.parseFingerprint( 'SHA256:e34c67Npv31uMtfVUEBJln5aOcJugzDaYGsj1Uph5DE'); FPS.ecdsa2 = sshpk.parseFingerprint( 'SHA256:Kyu0EMqH8fzfp9RXKJ6kmsk9qKGBqVRtlOuk6bXfCEU'); var ASN1PARSE_LINE = /^\s*([0-9]*):d=([0-9]+)\s+hl=([0-9]+)\s+l=\s*([0-9]+)\s*([a-z]+):\s*([^:\[]+)\s*(\[[^\]]+\])?\s*(:.+)?$/; function asn1parse_line2obj(line) { var m = line.match(ASN1PARSE_LINE); if (!m) throw (new Error('Not a valid asn1parse output line')); var obj = { offset: parseInt(m[1], 10), depth: parseInt(m[2], 10), headerLength: parseInt(m[3], 10), length: parseInt(m[4], 10), type: m[5], tag: m[6].trim() }; if (m[7]) obj.valueType = m[7].slice(1, m[7].length - 1); if (m[8]) obj.value = m[8].slice(1); return (obj); } temp.track(); test('openssl version', function (t) { var kid = spawn('openssl', ['version']); var buf = ''; var verLine; kid.stdout.on('data', function (data) { buf += data.toString(); var parts = buf.split('\n'); if (parts.length > 1) { verLine = parts[0]; buf = parts[1]; } }); kid.on('close', function (rc) { if (rc !== 0 || verLine === undefined) { console.log('warning: failed to find openssl command'); t.end(); return; } var parts = verLine.split(' '); if (parts[0] === 'OpenSSL') { var ver = parts[1].split('.').map(function (p) { return (parseInt(p)); }); if (ver[0] > 1 || (ver[0] == 1 && (ver[1] > 0 || (ver[1] == 0 && ver[2] >= 1)))) { /* we're ok */ genTests(); } } else { genTests(); } t.end(); }); }); function genTests() { ['rsa', 'dsa', 'ecdsa'].forEach(function (algo) { var tmp; test('make temp dir', function (t) { temp.mkdir('sshpk.test.openssl-cmd.' + algo, function (err, tmpDir) { t.error(err); tmp = tmpDir; t.end(); }); }); test('pkcs8 '+algo+' public key parses', function (t) { var kid = spawn('openssl', [ 'pkey', '-in', path.join(testDir, 'id_' +algo), '-pubout']); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0); var pem = Buffer.concat(bufs); var key = sshpk.parseKey(pem, 'pkcs8'); t.strictEqual(key.type, algo); if (algo === 'ecdsa') t.strictEqual(key.size, 384); else t.strictEqual(key.size, 1024); t.ok(FPS[algo].matches(key)); t.end(); }); }); test('pkcs8 '+algo+' private key parses', function (t) { var kid = spawn('openssl', [ 'pkey', '-in', path.join(testDir, 'id_' +algo)]); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0); var pem = Buffer.concat(bufs); var key = sshpk.parsePrivateKey(pem, 'pkcs8'); t.strictEqual(key.type, algo); if (algo === 'ecdsa') t.strictEqual(key.size, 384); else t.strictEqual(key.size, 1024); t.ok(FPS[algo].matches(key)); t.end(); }); }); test('pkcs8 '+algo+' public key output', function (t) { var pem = fs.readFileSync(path.join(testDir, 'id_' + algo)); var key = sshpk.parsePrivateKey(pem, 'pkcs1'); var pkcs8 = key.toPublic().toBuffer('pkcs8'); t.ok(pkcs8, 'output produced'); var kid = spawn('openssl', ['pkey', '-in', path.join(testDir, 'id_' + algo), '-pubout']); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0); var output = Buffer.concat(bufs); t.strictEqual(pkcs8.toString('base64'), output.toString('base64')); t.end(); }); }); test('pkcs8 '+algo+' private key output', function (t) { var pem = fs.readFileSync(path.join(testDir, 'id_' + algo)); var key = sshpk.parsePrivateKey(pem, 'pkcs1'); var pkcs8 = key.toBuffer('pkcs8'); t.ok(pkcs8, 'output produced'); var kid = spawn('openssl', ['pkey', '-in', path.join(testDir, 'id_' + algo)]); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0); var output = Buffer.concat(bufs); t.strictEqual(pkcs8.toString('base64'), output.toString('base64')); t.end(); }); }); test('sign with sshpk, openssl dgst verify', function (t) { var pem = fs.readFileSync(path.join(testDir, 'id_' + algo)); var key = sshpk.parsePrivateKey(pem, 'pkcs1'); var pkcs8 = key.toPublic().toBuffer('pkcs8'); var data = 'foobartest'; var sig = key.createSign('sha256').update(data).sign(). toBuffer(); fs.writeFileSync(path.join(tmp, 'signature'), sig); fs.writeFileSync(path.join(tmp, 'pubkey'), pkcs8); var kid = spawn('openssl', ['dgst', '-binary', '-sha256', '-verify', path.join(tmp, 'pubkey'), '-signature', path.join(tmp, 'signature')]); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.stderr.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0); var output = Buffer.concat(bufs).toString('ascii'); t.strictEqual(output, 'Verified OK\n'); t.end(); }); kid.stdin.write(data); kid.stdin.end(); }); test('sign with openssl, verify with sshpk', function (t) { var pem = fs.readFileSync(path.join(testDir, 'id_' + algo)); var key = sshpk.parsePrivateKey(pem, 'pkcs1'); var data = 'foobartest'; var kid = spawn('openssl', ['dgst', '-binary', '-sha256', '-sign', path.join(testDir, 'id_' + algo)]); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0, 'openssl exited 0'); if (bufs.length === 0) { t.fail('"openssl dgst" wrote no output'); t.end(); return; } var output = Buffer.concat(bufs); var sig = sshpk.parseSignature(output, algo, 'asn1'); t.ok(sig); t.ok(key.createVerify('sha256').update(data). verify(sig)); t.end(); }); kid.stdin.write(data); kid.stdin.end(); }); test('make a self-signed cert, parse with openssh', function (t) { var pem = fs.readFileSync(path.join(testDir, 'id_' + algo)); var key = sshpk.parsePrivateKey(pem, 'pkcs1'); var ids = [ sshpk.identityFromDN('cn=' + algo + ', c=US'), sshpk.identityFromDN('cn=' + algo + '.test, c=AU') ]; var cert = sshpk.createSelfSignedCertificate(ids, key); var certPem = cert.toBuffer('pem'); var kid = spawn('openssl', ['x509', '-text']); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0); var output = Buffer.concat(bufs).toString(); var m = output.match(/Issuer: (.*)$/m); t.strictEqual(m[1].replace(/ = /g, '='), 'CN=' + algo + ', C=US'); m = output.match(/Subject: (.*)$/m); t.strictEqual(m[1].replace(/ = /g, '='), 'CN=' + algo + ', C=US'); var re = /DNS:([^, \n]+)([, ]+|$)/gm; m = re.exec(output); t.strictEqual(m[1], algo); m = re.exec(output); t.strictEqual(m[1], algo + '.test'); t.end(); }); kid.stdin.write(certPem); kid.stdin.end(); }); test('make a self-signed cert, verify with openssh', function (t) { var pem = fs.readFileSync(path.join(testDir, 'id_' + algo)); var key = sshpk.parsePrivateKey(pem, 'pkcs1'); var id = sshpk.identityFromDN('cn=' + algo); var cert = sshpk.createSelfSignedCertificate(id, key, { purposes: ['ca'] }); var certPem = cert.toBuffer('pem'); fs.writeFileSync(path.join(tmp, 'ca.pem'), certPem); var kid = spawn('openssl', ['verify', '-CAfile', path.join(tmp, 'ca.pem')]); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0); var output = Buffer.concat(bufs).toString(); t.strictEqual(output.trim(), 'stdin: OK'); t.end(); }); kid.stdin.write(certPem); kid.stdin.end(); }); test('make a self-signed cert with utf8 chars', function (t) { var pem = fs.readFileSync(path.join(testDir, 'id_' + algo)); var key = sshpk.parsePrivateKey(pem, 'pkcs1'); var id = sshpk.identityFromDN('cn=ãŠã¯ã‚ˆã†'); var cert = sshpk.createSelfSignedCertificate(id, key); var certPem = cert.toBuffer('pem'); fs.writeFileSync(path.join(tmp, 'ca.pem'), certPem); var kid = spawn('openssl', ['verify', '-CAfile', path.join(tmp, 'ca.pem')]); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0); var output = Buffer.concat(bufs).toString(); t.strictEqual(output.trim(), 'stdin: OK'); t.end(); }); kid.stdin.write(certPem); kid.stdin.end(); }); test('verify a self-signed cert with utf8 chars', function (t) { var pem = fs.readFileSync(path.join(testDir, 'id_' + algo)); var key = sshpk.parsePrivateKey(pem, 'pkcs1'); var id = sshpk.identityFromDN('cn=ãŠã¯ã‚ˆã†'); var cert = sshpk.createSelfSignedCertificate(id, key); var certPem = cert.toBuffer('pem'); var kid = spawn('openssl', ['asn1parse']); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0); var output = Buffer.concat(bufs).toString('utf8'); var lines = output.split('\n'); var foundString = false; for (var i = 0; i < lines.length; ++i) { if (!lines[i]) continue; var line = asn1parse_line2obj(lines[i]); if (line.tag === 'OBJECT' && line.value === 'commonName') { var nline = asn1parse_line2obj( lines[i + 1]); t.strictEqual(nline.value, 'ãŠã¯ã‚ˆã†', 'CN should be set'); t.strictEqual(nline.tag, 'UTF8STRING', 'CN should be a utf8string'); foundString = true; } } t.ok(foundString); t.end(); }); kid.stdin.write(certPem); kid.stdin.end(); }); test('make a self-signed cert with non-printable chars', function (t) { var pem = fs.readFileSync(path.join(testDir, 'id_' + algo)); var key = sshpk.parsePrivateKey(pem, 'pkcs1'); var id = sshpk.identityFromDN('cn=foo_bar@'); var cert = sshpk.createSelfSignedCertificate(id, key); var certPem = cert.toBuffer('pem'); var kid = spawn('openssl', ['asn1parse']); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0); var output = Buffer.concat(bufs).toString('utf8'); var lines = output.split('\n'); var foundString = false; for (var i = 0; i < lines.length; ++i) { if (!lines[i]) continue; var line = asn1parse_line2obj(lines[i]); if (line.tag === 'OBJECT' && line.value === 'commonName') { var nline = asn1parse_line2obj( lines[i + 1]); t.strictEqual(nline.value, 'foo_bar@', 'CN should be set'); t.strictEqual(nline.tag, 'IA5STRING', 'CN should be a ia5string'); foundString = true; } } t.ok(foundString); t.end(); }); kid.stdin.write(certPem); kid.stdin.end(); }); test('make a self-signed cert, openssl x509 -text parse', function (t) { var pem = fs.readFileSync(path.join(testDir, 'id_' + algo)); var key = sshpk.parsePrivateKey(pem, 'pkcs1'); var ids = [ sshpk.identityFromDN('cn=' + algo + ', c=US'), sshpk.identityFromDN('cn=' + algo + '.test, c=AU') ]; var cert = sshpk.createSelfSignedCertificate(ids, key); var certPem = cert.toBuffer('pem'); var kid = spawn('openssl', ['x509', '-text']); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0); var output = Buffer.concat(bufs).toString(); var cert2 = sshpk.parseCertificate(output, 'pem'); t.ok(cert2.fingerprint('sha512').matches(cert)); t.end(); }); kid.stdin.write(certPem); kid.stdin.end(); }); test('make a self-signed cert with generated key', function (t) { if (algo !== 'ecdsa') { t.end(); return; } var key = sshpk.generatePrivateKey(algo); var id = sshpk.identityFromDN('cn=' + algo); var cert = sshpk.createSelfSignedCertificate(id, key, { purposes: ['ca'] }); var certPem = cert.toBuffer('pem'); fs.writeFileSync(path.join(tmp, 'ca.pem'), certPem); var kid = spawn('openssl', ['verify', '-CAfile', path.join(tmp, 'ca.pem')]); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0); var output = Buffer.concat(bufs).toString(); t.strictEqual(output.trim(), 'stdin: OK'); t.end(); }); kid.stdin.write(certPem); kid.stdin.end(); }); }); test('nulls in x509 rsa certs (#39)', function (t) { var pem = fs.readFileSync(path.join(testDir, 'id_rsa')); var key = sshpk.parsePrivateKey(pem, 'pkcs1'); var id = sshpk.identityFromDN('cn=foobar'); var cert = sshpk.createSelfSignedCertificate(id, key); var certPem = cert.toBuffer('pem'); var kid = spawn('openssl', ['asn1parse']); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0, 'openssl command exit status 0'); var output = Buffer.concat(bufs).toString('utf8'); var lines = output.split('\n'); var found = false; for (var i = 0; i < lines.length; ++i) { if (lines[i].length < 1) continue; var line = asn1parse_line2obj(lines[i]); if (line.type === 'prim' && line.tag === 'OBJECT' && line.value === 'sha256WithRSAEncryption') { var nline = asn1parse_line2obj(lines[i + 1]); t.strictEqual(nline.tag, 'NULL', 'null value must follow RSA OID'); t.strictEqual(nline.type, 'prim', 'null should be primitive'); t.strictEqual(nline.depth, line.depth, 'null should be at same depth as RSA OID'); found = true; } } t.ok(found, 'should have an RSA OID'); t.end(); }); kid.stdin.write(certPem); kid.stdin.end(); }); test('utf8string in issuer DN (#40)', function (t) { var pem = fs.readFileSync(path.join(testDir, 'id_rsa')); var ikey = sshpk.parsePrivateKey(pem, 'pkcs1'); var certpem = fs.readFileSync(path.join(testDir, 'jim-x509-utf8.pem')); var issucert = sshpk.parseCertificate(certpem, 'pem'); var issuid = issucert.subjects[0]; var id = sshpk.identityFromDN('cn=foo_bar@'); var key = sshpk.generatePrivateKey('ecdsa'); var cert = sshpk.createCertificate(issuid, ikey, id, key); var certPem = cert.toBuffer('pem'); var kid = spawn('openssl', ['asn1parse']); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0, 'openssl exited with 0 status'); var output = Buffer.concat(bufs).toString('utf8'); var lines = output.split('\n'); var foundString = false; lines.forEach(function (line) { if (line.indexOf('foo_bar@') !== -1) { t.strictEqual( line.indexOf('PRINTABLESTRING'), -1, 'subject CN is printablestring'); t.strictEqual( line.indexOf('UTF8STRING'), -1, 'subject CN is not utf8string'); t.notStrictEqual( line.indexOf('IA5STRING'), -1, 'subject CN is not ia5string'); } if (line.indexOf('a test string') !== -1) { t.notStrictEqual( line.indexOf('UTF8STRING'), -1, 'issuer CN is utf8string'); t.strictEqual( line.indexOf('PRINTABLESTRING'), -1, 'issuer CN is not printablestring'); t.strictEqual( line.indexOf('IA5STRING'), -1, 'issuer CN is not ia5string'); foundString = true; } }); t.ok(foundString, 'found the issuer CN'); t.end(); }); kid.stdin.write(certPem); kid.stdin.end(); }); test('certs with <2050 dates should use UTCTime', function (t) { var pem = fs.readFileSync(path.join(testDir, 'id_rsa')); var key = sshpk.parsePrivateKey(pem, 'pkcs1'); var id = sshpk.identityFromDN('cn=foobar'); var opts = {}; opts.validFrom = new Date('1990-01-02T03:04:05Z'); opts.validUntil = new Date('2010-01-02T03:04:05Z'); var cert = sshpk.createSelfSignedCertificate(id, key, opts); var certPem = cert.toBuffer('pem'); var kid = spawn('openssl', ['asn1parse']); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0); var output = Buffer.concat(bufs).toString('utf8'); var lines = output.split('\n'); var found = 0; for (var i = 0; i < lines.length; ++i) { if (!lines[i]) continue; var line = asn1parse_line2obj(lines[i]); if (line.tag === 'UTCTIME') { if (line.value === '900102030405Z' || line.value === '100102030405Z') { ++found; } else { t.fail('unexpected utctime: ' + line.value); } } } t.equal(found, 2); t.end(); }); kid.stdin.write(certPem); kid.stdin.end(); }); test('certs with >=2050 dates should use GeneralizedTime', function (t) { var pem = fs.readFileSync(path.join(testDir, 'id_rsa')); var key = sshpk.parsePrivateKey(pem, 'pkcs1'); var id = sshpk.identityFromDN('cn=foobar'); var opts = {}; opts.validFrom = new Date('2050-01-02T03:04:05Z'); opts.validUntil = new Date('2051-01-02T03:04:05Z'); var cert = sshpk.createSelfSignedCertificate(id, key, opts); var certPem = cert.toBuffer('pem'); var kid = spawn('openssl', ['asn1parse']); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0); var output = Buffer.concat(bufs).toString('utf8'); var lines = output.split('\n'); var found = 0; for (var i = 0; i < lines.length; ++i) { if (!lines[i]) continue; var line = asn1parse_line2obj(lines[i]); if (line.tag === 'UTCTIME') { t.fail('unexpected utctime: ' + line.value); } if (line.tag === 'GENERALIZEDTIME') { if (line.value === '20500102030405Z') { ++found; } else if (line.value === '20510102030405Z') { ++found; } else { t.fail('bad gentime: ' + line.value); } } } t.equal(found, 2); t.end(); }); kid.stdin.write(certPem); kid.stdin.end(); }); test('certs with <1950 dates should use GeneralizedTime', function (t) { var pem = fs.readFileSync(path.join(testDir, 'id_rsa')); var key = sshpk.parsePrivateKey(pem, 'pkcs1'); var id = sshpk.identityFromDN('cn=foobar'); var opts = {}; opts.validFrom = new Date('1949-01-02T03:04:05Z'); opts.validUntil = new Date('1950-01-02T03:04:05Z'); var cert = sshpk.createSelfSignedCertificate(id, key, opts); var certPem = cert.toBuffer('pem'); var kid = spawn('openssl', ['asn1parse']); var bufs = []; kid.stdout.on('data', bufs.push.bind(bufs)); kid.on('close', function (rc) { t.equal(rc, 0); var output = Buffer.concat(bufs).toString('utf8'); var lines = output.split('\n'); var found = 0; for (var i = 0; i < lines.length; ++i) { if (!lines[i]) continue; var line = asn1parse_line2obj(lines[i]); if (line.tag === 'UTCTIME') { if (line.value === '500102030405Z') { ++found; } else { t.fail('unexpected utctime: ' + line.value); } } if (line.tag === 'GENERALIZEDTIME') { if (line.value === '19490102030405Z') { ++found; } else { t.fail('unexpected gentime: ' + line.value); } } } t.equal(found, 2); t.end(); }); kid.stdin.write(certPem); kid.stdin.end(); }); test('teardown', function (t) { temp.cleanup(function () { t.end(); }); }); } node-sshpk-1.16.1/test/pem.js000066400000000000000000000413571342215657600157760ustar00rootroot00000000000000// Copyright 2011 Joyent, Inc. All rights reserved. var test = require('tape').test; var path = require('path'); var fs = require('fs'); var sshpk = require('../lib/index'); var Buffer = require('safer-buffer').Buffer; ///--- Globals var SSH_1024 = 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvad19ePSDckmgmo6Unqmd8' + 'n2G7o1794VN3FazVhV09yooXIuUhA+7OmT7ChiHueayxSubgL2MrO/HvvF/GGVUs/t3e0u4' + '5YwRC51EVhyDuqthVJWjKrYxgDMbHru8fc1oV51l0bKdmvmJWbA/VyeJvstoX+eiSGT3Jge' + 'egSMVtc= mark@foo.local'; var SSH_1024_WS = 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvad19ePSDckmgmo6Unqmd8' + 'n2G7o1794VN3FazVhV09yooXIuUhA+7OmT7ChiHueayxSubgL2MrO/HvvF/GGVUs/t3e0u4' + '5YwRC51EVhyDuqthVJWjKrYxgDMbHru8fc1oV51l0bKdmvmJWbA/VyeJvstoX+eiSGT3Jge' + 'egSMVtc=\tmark@foo.local\n'; var SSH_1024_WSC = 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvad19ePSDckmgmo6Unqmd8' + 'n2G7o1794VN3FazVhV09yooXIuUhA+7OmT7ChiHueayxSubgL2MrO/HvvF/GGVUs/t3e0u4' + '5YwRC51EVhyDuqthVJWjKrYxgDMbHru8fc1oV51l0bKdmvmJWbA/VyeJvstoX+eiSGT3Jge' + 'egSMVtc=\tthis is a test comment\n'; var PEM_1024 = '-----BEGIN PUBLIC KEY-----\n' + 'MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC9p3X149INySaCajpSeqZ3yfYb\n' + 'ujXv3hU3cVrNWFXT3Kihci5SED7s6ZPsKGIe55rLFK5uAvYys78e+8X8YZVSz+3d\n' + '7S7jljBELnURWHIO6q2FUlaMqtjGAMxseu7x9zWhXnWXRsp2a+YlZsD9XJ4m+y2h\n' + 'f56JIZPcmB56BIxW1wIBIw==\n' + '-----END PUBLIC KEY-----\n'; var SSH_2048 = 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAr+isTwMYqwCAcY0Yb2F0pF' + '+/F4/wxGzcrLR2PrgoBXwjj/TnEA3tJ7v08Rru3lAd/O59B6TbXOsYbQ+2Syd82Dm8L3SJR' + 'NlZJ6DZUOAwnTOoNgkfH2CsbGS84aTPTeXjmMsw52GvQ9yWFDUglHzMIzK2iSHWNl1dAaBE' + 'iddifGmrpUTPJ5Tt7l8YS4jdaBf6klS+3CvL6xET/RjZhKGtrrgsRRYUB2XVtgQhKDu7PtD' + 'dlpy4+VISdVhZSlXFnBhya/1KxLS5UFHSAdOjdxzW1bh3cPzNtuPXZaiWUHvyIWpGVCzj5N' + 'yeDXcc7n0E20yx9ZDkAITuI8X49rnQzuCN5Q== mark@bluesnoop.local'; var PEM_2048 = '-----BEGIN PUBLIC KEY-----\n' + 'MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAr+isTwMYqwCAcY0Yb2F0\n' + 'pF+/F4/wxGzcrLR2PrgoBXwjj/TnEA3tJ7v08Rru3lAd/O59B6TbXOsYbQ+2Syd8\n' + '2Dm8L3SJRNlZJ6DZUOAwnTOoNgkfH2CsbGS84aTPTeXjmMsw52GvQ9yWFDUglHzM\n' + 'IzK2iSHWNl1dAaBEiddifGmrpUTPJ5Tt7l8YS4jdaBf6klS+3CvL6xET/RjZhKGt\n' + 'rrgsRRYUB2XVtgQhKDu7PtDdlpy4+VISdVhZSlXFnBhya/1KxLS5UFHSAdOjdxzW\n' + '1bh3cPzNtuPXZaiWUHvyIWpGVCzj5NyeDXcc7n0E20yx9ZDkAITuI8X49rnQzuCN\n' + '5QIBIw==\n' + '-----END PUBLIC KEY-----\n'; var PEM_PRIVATE_2048 = '-----BEGIN RSA PRIVATE KEY-----\n' + 'MIIEpAIBAAKCAQEAyGTB7EAD1/MCDFNmQa6WybEJkzWF1jswrIcZ1IN+T363Hv1+\n' + 'qtFhjiY1JcIeJxOEEEhkSlRiiHnFs6Q25XZ80mXWiKeLEE1IF5nOVcNgxtSMRr61\n' + 'qt0DD9/c1xWzHkQjnw6Q6SvLVzkkcLpDJnfLc1MsTGBzkSW1zdtfS8pf6rlZpa/l\n' + '0Tc0zI72ywN+9Lio2pDeXaJlNMfsiV78b47zDzt1AZhHba5pV8XQMAudhiIJI6jK\n' + 'jN1HfUxV62wD5PrrU9xtDGUhVLSwhhOuBt9yvxcTyRvdWVwKN8d91shY+XCs4pVD\n' + 'jG1IzoBviNvWPT5GwWx+rwb1vDFdd/SvDUdOzQIDAQABAoIBAA/LCRGCdgsV5spr\n' + '5Do29UFOB5AnfrXEknB2cU2zU0gWl34Ewm/Z8pNOZY/lPZUcz6Ks4eKNxfo1hqRC\n' + 'w+TPssSuK/s3IRmWzaC2iXFu5XimFawZqZ2er3gXz4LP/f7bpecKMdd+kRb9tOaB\n' + 'd3tXo5wiKPKYA2OkEjD4IgmKGIcaEq2rxQEg872OSHamd5JPtGmLPBIwiird6d3K\n' + 'U15nWZVwTL8rPGBYN1I5pBERYCephBwXqzBE1BiK9FZbevEIoSOI057WTAuAy/DB\n' + '8/svhLNEF6w2X5CiCRw9Cw9dKRtpaY3kGhOzBiXkwJH9CTaw/8w7uEmQI//NWrvP\n' + '9S8YW2ECgYEA9GadWhRLZQYF0R7e3zIr3GyL9FQoVNLpba4Mpf68QO0yrmAZU5gt\n' + 'ibUWVO/tDGD7tQCaFax+kwF/paGemvsBoiGFeJOSqj/3D5/89sSyd45p44AyjKWU\n' + 'a8bLhaEm1W9pfYBwYrMxkQxz877s7V1hD3baVf0j8DHGQa0A9PgH+dkCgYEA0ed4\n' + 'UU5+bfW4SCwr2XbAm2X1K/x17rU7fdSe9M/zdWCjzdgRMJ7nVvbyYP7rmo97SxYI\n' + 'co/5xhwv+NXH/hPHHkQJLkfbSyCYL3fQMt18VuUZ4uZTWC+pMvjh1Zfn+JT0v7Mm\n' + 'N9gJ6cXFYp954M8ZzxhviYeWUVPUmsS45OdsUBUCgYEAp0BF9GwpAFRzzJ1Upede\n' + 'rrS1vhmNlCbVydIvI7XEvKXWZhCrpFJi73c2dh/O2AbSmhZ0W9q0sAN5iC6nLKYT\n' + 'gxFvlole+BVYDKBO68zF2R1jh2Wmsitp+6uKgcM7oRpiVZl8z36TsBCWlTqWRwX9\n' + 'MykB15CpdGmLpEwxeHL4elkCgYBK3pU76xONhSfGFntNhd4Nj8BzgAlQq7QcncpU\n' + '6Beetmm28mqvPP6nNk4d6s9+wc7oaWN5+YDN+R/jUd2T8toDIaFksJy3n1ipFcNd\n' + 'YUMIe49QL3dq7RUc6UkkNpq3P+pMtknbgWOHztMo6lk+pqA+Dik6lPI47/3VdnW8\n' + 'sA8iQQKBgQCfH5+366HCY6uz/JQwaw4SPQTe87ZcnoGBbsAva9qJETJKhaWl1/nZ\n' + '9bjw9KrARxlYGfYajarKa2Tkt6/KFBzTAOmp1rg3Q45vohMoY0BmtQDz9sdGGv/k\n' + 'rVbcyNIUocjTUJgVr2PK9jFBYssEQRpPMRHlwoyC7WTeiwQTcDgO1g==\n' + '-----END RSA PRIVATE KEY-----\n'; var SSH_PRIVATE_2048 = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDIZMHsQA' + 'PX8wIMU2ZBrpbJsQmTNYXWOzCshxnUg35Pfrce/X6q0WGOJjUlwh4nE4QQSGRKVGKIe' + 'cWzpDbldnzSZdaIp4sQTUgXmc5Vw2DG1IxGvrWq3QMP39zXFbMeRCOfDpDpK8tXOSRw' + 'ukMmd8tzUyxMYHORJbXN219Lyl/quVmlr+XRNzTMjvbLA370uKjakN5domU0x+yJXvx' + 'vjvMPO3UBmEdtrmlXxdAwC52GIgkjqMqM3Ud9TFXrbAPk+utT3G0MZSFUtLCGE64G33' + 'K/FxPJG91ZXAo3x33WyFj5cKzilUOMbUjOgG+I29Y9PkbBbH6vBvW8MV139K8NR07N ' + 'mark@bluesnoop.local'; var SSH_4096 = 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAsWUdvcKBBjW4GJ8Uyo0S8U' + 'FFZbg5bqeRWPHcR2eIbo/k7M54PmWFqNL3YCIR8cRsvsFuYObnVaY01p1p/9+tpN4ezaHS5' + '9glhADTSva3uLrYuWA1FCKFi6/rXn9WkM5diSVrrTXzaQE8ZsVRA5QG6AeWhC3x/HNbiJOG' + 'd9u0xrzYnyjrhO6x7eCnSz/AtNURLyWHbZ9Q0VEY5UVQsfAmmAAownMTth1m7KRG/KgM1Oz' + '9Dc+IUHYf0pjxFLQVQgqPnOLsj8OIJEt9SbZR33n66UJezbsbm0uJ+ophA3W/OacvHzCmoL' + 'm9PaCwYEZ2pIlYlhkGGu6CFpfXhYUne61WAV8xR8pDXaIL7BqLRJZKlxPzrg9Iu278V9XeL' + 'CnandXIGpaKwC5p7N/K6JoLB+nI1xd4X1NIftaBouxmYTXJy1VK2DKkD+KyvUPtN7EXnC4G' + 'E4eDn9nibIj35GjfiDXrxcPPaJhSVzqvIIt55XcAnUEEVtiKtxICKwTSbvsojML5hL/gdeu' + 'MWnMxj1nsZzTgSurD2OFaQ22k5HGu9aC+duNvvgjXWou7BsS/vH1QbP8GbIvYKlO5xNIj9z' + 'kjINP3nCX4K1+IpW3PDkgS/DleUhUlvhxb10kc4af+9xViAGkV71WqNcoY+PAETvEbDbYpg' + 'VEBd4mwFJLl/DT2Nlbj9q0= mark@bluesnoop.local'; var PEM_4096 = '-----BEGIN PUBLIC KEY-----\n' + 'MIICIDANBgkqhkiG9w0BAQEFAAOCAg0AMIICCAKCAgEAsWUdvcKBBjW4GJ8Uyo0S\n' + '8UFFZbg5bqeRWPHcR2eIbo/k7M54PmWFqNL3YCIR8cRsvsFuYObnVaY01p1p/9+t\n' + 'pN4ezaHS59glhADTSva3uLrYuWA1FCKFi6/rXn9WkM5diSVrrTXzaQE8ZsVRA5QG\n' + '6AeWhC3x/HNbiJOGd9u0xrzYnyjrhO6x7eCnSz/AtNURLyWHbZ9Q0VEY5UVQsfAm\n' + 'mAAownMTth1m7KRG/KgM1Oz9Dc+IUHYf0pjxFLQVQgqPnOLsj8OIJEt9SbZR33n6\n' + '6UJezbsbm0uJ+ophA3W/OacvHzCmoLm9PaCwYEZ2pIlYlhkGGu6CFpfXhYUne61W\n' + 'AV8xR8pDXaIL7BqLRJZKlxPzrg9Iu278V9XeLCnandXIGpaKwC5p7N/K6JoLB+nI\n' + '1xd4X1NIftaBouxmYTXJy1VK2DKkD+KyvUPtN7EXnC4GE4eDn9nibIj35GjfiDXr\n' + 'xcPPaJhSVzqvIIt55XcAnUEEVtiKtxICKwTSbvsojML5hL/gdeuMWnMxj1nsZzTg\n' + 'SurD2OFaQ22k5HGu9aC+duNvvgjXWou7BsS/vH1QbP8GbIvYKlO5xNIj9zkjINP3\n' + 'nCX4K1+IpW3PDkgS/DleUhUlvhxb10kc4af+9xViAGkV71WqNcoY+PAETvEbDbYp\n' + 'gVEBd4mwFJLl/DT2Nlbj9q0CASM=\n' + '-----END PUBLIC KEY-----\n'; var DSA_1024 = 'ssh-dss AAAAB3NzaC1kc3MAAACBAKK5sckoM05sOPajUcTWG0zPTvyRmj6' + 'YQ1g2IgezUUrXgY+2PPy07+JrQi8SN9qr/CBP+0q0Ec48qVFf9LlkUBwu9Jf5HTUVNiKNj3c' + 'SRPFH8HqZn+nxhVsOLhnHWxgDQ8OOm48Ma61NcYVo2B0Ne8cUs8xSqLqba2EG9ze87FQZAAA' + 'AFQCVP/xpiAofZRD8L4QFwxOW9krikQAAAIACNv0EmKr+nIA13fjhpiqbYYyVXYOiWM4cmOD' + 'G/d1J8/vR4YhWHWPbAEw7LD0DEwDIHLlRZr/1jsHbFcwt4tzRs95fyHzpucpGhocmjWx43qt' + 'xEhDeJrxPlkIXHakciAEhoo+5YeRSSgRse5PrZDosdr5fA+DADs8tnto5Glf5owAAAIBHcEF' + '5ytvCRiKbsWKOgeMZ7JT/XGX+hMhS7aaJ2IspKj7YsWada1yBwoM6yYHtlpnGsq/PoPaZU8K' + '40f47psV6OhSh+/O/jgqLS/Ur2c0mQQqIb7vvkc7he/SPOQAqyDmyYFBuazuSf2s9Uy2hfvj' + 'Wgb6X+vN9W8SOb2668IL7Vg== mark@bluesnoop.local'; var DSA_1024_PEM = '-----BEGIN PUBLIC KEY-----\n' + 'MIIBtjCCASsGByqGSM44BAEwggEeAoGBAKK5sckoM05sOPajUcTWG0zPTvyRmj6Y\n' + 'Q1g2IgezUUrXgY+2PPy07+JrQi8SN9qr/CBP+0q0Ec48qVFf9LlkUBwu9Jf5HTUV\n' + 'NiKNj3cSRPFH8HqZn+nxhVsOLhnHWxgDQ8OOm48Ma61NcYVo2B0Ne8cUs8xSqLqb\n' + 'a2EG9ze87FQZAhUAlT/8aYgKH2UQ/C+EBcMTlvZK4pECgYACNv0EmKr+nIA13fjh\n' + 'piqbYYyVXYOiWM4cmODG/d1J8/vR4YhWHWPbAEw7LD0DEwDIHLlRZr/1jsHbFcwt\n' + '4tzRs95fyHzpucpGhocmjWx43qtxEhDeJrxPlkIXHakciAEhoo+5YeRSSgRse5Pr\n' + 'ZDosdr5fA+DADs8tnto5Glf5owOBhAACgYBHcEF5ytvCRiKbsWKOgeMZ7JT/XGX+\n' + 'hMhS7aaJ2IspKj7YsWada1yBwoM6yYHtlpnGsq/PoPaZU8K40f47psV6OhSh+/O/\n' + 'jgqLS/Ur2c0mQQqIb7vvkc7he/SPOQAqyDmyYFBuazuSf2s9Uy2hfvjWgb6X+vN9\n' + 'W8SOb2668IL7Vg==\n' + '-----END PUBLIC KEY-----\n'; var ENC_PRIVATE = '-----BEGIN RSA PRIVATE KEY-----\n' + 'Proc-Type: 4,ENCRYPTED\n' + 'DEK-Info: AES-128-CBC,B3095F1FAF29BE6554540D24F17D14DB\n\n' + '1OJdgfzsXazrhPZ7pO9Q27Pr97+OsU8FUxiCrDrEP71piJMJrmifue9KfOoAmC1L\n' + 'FhaKXGSmRnP1/odgG7KBJ8ybIkZ5gVMz/dU4hR0SyA3zLMx+sV68oqYYw4s0EjrA\n' + 'KYzQmMc78ouC6yQA4r+psgJ2sgK5VwwB48c0J5lO60HUeyEsno6iGY7VW/Kmt76O\n' + 'Kl8/LwA9qE2U/1u6pRsoaD34CD2E+m/IwCUIyLeri04tiMfyE0RKTL9EacvxExCu\n' + 'ucwBlvtGIcQcChw1JJqGxTXBeCrz8Kb3uWNrZ+MME3OEh4qWFPgT6XqeE/gociym\n' + 'rhyKffZKsnJts0TqxqSuxtpLM5+WaYAGbkEHzuC/chOsynFRKxZomV65ddufmO3N\n' + 'Kb8B3H+2+Fo9x5iucEBhj4MBLHlZ7ZkQ8yEP+E0d0PuPRIFZ3aRcKPuaoZIc/AiQ\n' + '8w1GGAU1TZWWHs1L4pF7OWyWwuq3NkzWLzL7MkNx++zmxXpIPMKDnFTLuBu24nCk\n' + 'gBx85sgirfSJBwx1mpQzsD1PSE7krAzlA4DRfgPChAWJnlUn89aPJ52uokHneJIK\n' + 'z8/ApT6HCd3EnH9VHEtXp116ZVk4PhRiiOMY/ek2uhFK57wgMxOrRM3OgODrd+5A\n' + '-----END RSA PRIVATE KEY-----\n'; var ENC_ECDSA = '-----BEGIN EC PRIVATE KEY-----\n' + 'Proc-Type: 4,ENCRYPTED\n' + 'DEK-Info: AES-128-CBC,04BA2E1B464A88F180CD33D2B7A652E5\n\n' + 'VHUwZwMseYfvZuO523B32r/SEq8W5sV76ptbUJh/EsfLYkBhKaiU0tshp9mvfm4s\n' + '1VuVixfrFppGJ0UfVFls10I9wYVR2PWHsOLOGTq28jgE6k94kX5R3NjeXMUZCr5B\n' + 'lZLoKRFcQu8IzuJrm+qYCvwa4Uyn0O7xB3xGlNlSDHs=\n' + '-----END EC PRIVATE KEY-----\n'; var ED_SSH = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEi0pkfPe/+kbmnTSH0mfr0J4' + 'Fq7M7bshFAKB6uCyLDm foo@bar'; var ED_PKCS8 = '-----BEGIN PUBLIC KEY-----\n' + 'MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE=\n' + '-----END PUBLIC KEY-----\n'; var ED_PKIX_SSH = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIQAZv0QJaYTN/oVBusFn3' + 'DuWyFCGqjC2tssMXDitcDFm4Q== test'; var ED_PKIX_NORM = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBm/RAlphM3+hUG6wWfc' + 'O5bIUIaqMLa2ywxcOK1wMWbh test'; var OAKLEY_PEM = '-----BEGIN PUBLIC KEY-----\n' + 'MIGpMHsGByqGSM49AgEwcAIBATAdBgcqhkjOPQECMBICAgCbBgkqhkjOPQECAwIC\n' + 'AT4wCAQBAAQDBzOPBCkEAAAAAAAAAAAAAAAAAAAAAAAAAHsAAAAAAAAAAAAAAAAA\n' + 'AAAAAAAByAIUAqqqqqqqqqqqqsfzx4gb0IaPqGwCAQMDKgAEA2uNp3wO2DeYe+wG\n' + 'yTpFhT5/kMAFkxiDsyoac6/uGwqH2r617caOXQ==\n' + '-----END PUBLIC KEY-----\n'; var ECDSA_SSH = 'ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlz' + 'dHAyNTYAAABBBDkhU/ikG5wiz0qUpJsZiF8U1JAPEP2jD9kCdm2OnEw23oIPNWKPzyjLWCpJ' + '9U7vrw/GY1QS/INqo2zKXNMq8iE='; var ECDSA_PEM = '-----BEGIN PUBLIC KEY-----\n' + 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOSFT+KQbnCLPSpSkmxmIXxTUkA8Q\n' + '/aMP2QJ2bY6cTDbegg81Yo/PKMtYKkn1Tu+vD8ZjVBL8g2qjbMpc0yryIQ==\n' + '-----END PUBLIC KEY-----\n'; var RFC_AUTO = Buffer.from('AAAAC3NzaC1lZDI1NTE5AAAAIEi0pkfPe/+kbmnTSH0mfr0J' + '4Fq7M7bshFAKB6uCyLDm', 'base64'); var testDir = path.join(__dirname, 'assets'); ///--- Tests test('1024b pem to rsa ssh key', function(t) { var k = sshpk.parseKey(PEM_1024, 'pem'); k.comment = 'mark@foo.local'; t.equal(k.toString('ssh'), SSH_1024); t.end(); }); test('1024b pem trimmed', function(t) { var k = sshpk.parseKey(PEM_1024.trim(), 'pem'); k.comment = 'mark@foo.local'; t.equal(k.toString('ssh'), SSH_1024); t.end(); }); test('1024b pem with whitespace', function(t) { var k = sshpk.parseKey(' \t\n ' + PEM_1024 + '\n\n', 'pem'); k.comment = 'mark@foo.local'; t.equal(k.toString('ssh'), SSH_1024); t.end(); }); test('1024b pem with auto', function(t) { var k = sshpk.parseKey(PEM_1024, 'auto'); k.comment = 'mark@foo.local'; t.equal(k.toString('ssh'), SSH_1024); t.end(); }); test('2048b pem to rsa ssh key', function(t) { var k = sshpk.parseKey(PEM_2048, 'pem'); k.comment = 'mark@bluesnoop.local'; t.equal(k.toString('ssh'), SSH_2048); t.end(); }); test('2048b pem private to rsa ssh key', function(t) { var k = sshpk.parseKey(PEM_PRIVATE_2048, 'pem'); k.comment = 'mark@bluesnoop.local'; t.equal(k.toString('ssh'), SSH_PRIVATE_2048); t.end(); }); test('4096b pem to rsa ssh key', function(t) { var k = sshpk.parseKey(PEM_4096, 'pem'); k.comment = 'mark@bluesnoop.local'; t.equal(k.toString('ssh'), SSH_4096); t.end(); }); test('1024b rsa ssh key', function(t) { var k = sshpk.parseKey(SSH_1024, 'ssh'); t.equal(k.toString('pem'), PEM_1024); t.end(); }); test('1024b rsa ssh key with whitespace', function(t) { var k = sshpk.parseKey('\n\t \n' + SSH_1024 + '\n', 'ssh'); t.equal(k.toString('pem'), PEM_1024); t.end(); }); test('1024b rsa ssh key with whitespace auto', function(t) { var k = sshpk.parseKey('\n\t \n' + SSH_1024 + '\n', 'auto'); t.equal(k.toString('pem'), PEM_1024); t.end(); }); test('oakley curve ecdsa key', function(t) { t.throws(function() { var k = sshpk.parseKey(OAKLEY_PEM, 'auto'); }); t.end(); }); test('256bit ecdsa as auto from string', function(t) { var k = sshpk.parseKey(ECDSA_SSH, 'auto'); t.equal(k.toString('pem'), ECDSA_PEM); t.end(); }); test('256bit ecdsa as auto from buffer', function(t) { var k = sshpk.parseKey(Buffer.from(' ' + ECDSA_SSH), 'auto'); t.equal(k.toString('pem'), ECDSA_PEM); t.end(); }); test('rfc4253 auto fallback', function(t) { var k = sshpk.parseKey(RFC_AUTO, 'auto'); t.equal(k.type, 'ed25519'); t.end(); }); test('1024b rsa ssh key with inner whitespace', function(t) { var k = sshpk.parseKey(SSH_1024_WS, 'ssh'); t.equal(k.comment, 'mark@foo.local'); t.equal(k.toString('pem'), PEM_1024); t.end(); }); test('1024b rsa ssh key with whitespace in comment', function(t) { var k = sshpk.parseKey(SSH_1024_WSC, 'ssh'); t.equal(k.comment, 'this is a test comment'); t.equal(k.toString('pem'), PEM_1024); t.end(); }); test('2048b rsa ssh key', function(t) { var k = sshpk.parseKey(SSH_2048, 'ssh'); t.equal(k.toString('pem'), PEM_2048); t.end(); }); test('4096b rsa ssh key', function(t) { var k = sshpk.parseKey(SSH_4096, 'ssh'); t.equal(k.toString('pem'), PEM_4096); t.end(); }); test('1024b dsa ssh key', function(t) { var k = sshpk.parseKey(DSA_1024, 'ssh'); t.equal(k.toString('pem'), DSA_1024_PEM); t.end(); }); test('1024b dsa ssh key with auto', function(t) { var k = sshpk.parseKey(DSA_1024, 'auto'); t.equal(k.toString('pem'), DSA_1024_PEM); t.end(); }); test('ed25519 ssh key', function(t) { var k = sshpk.parseKey(ED_SSH, 'ssh'); t.equal(k.type, 'ed25519'); t.end(); }); test('ed25519 ssh key with auto', function(t) { var k = sshpk.parseKey(ED_SSH, 'auto'); t.equal(k.type, 'ed25519'); t.end(); }); test('ed25519 key from pkcs8', function(t) { var k = sshpk.parseKey(ED_PKCS8, 'auto'); t.equal(k.type, 'ed25519'); k.comment = 'test'; t.equal(k.toString('ssh'), ED_PKIX_NORM); t.end(); }); test('encrypted rsa private key', function(t) { t.throws(function () { var k = sshpk.parseKey(ENC_PRIVATE, 'pem'); }); t.end(); }); test('encrypted ecdsa private key with pw', function(t) { var k = sshpk.parseKey(ENC_ECDSA, 'pem', { passphrase: 'asdfasdf' }); t.equal(k.type, 'ecdsa'); t.end(); }); test('encrypted rsa private key (3des)', function (t) { var keyPem = fs.readFileSync(path.join(testDir, '3des.pem')); var key = sshpk.parsePrivateKey(keyPem, 'pem', { passphrase: 'testing123' }); t.equal(key.type, 'rsa'); key.comment = 'test'; var keySsh = fs.readFileSync(path.join(testDir, '3des.pub'), 'ascii'); t.equal(key.toPublic().toString('ssh'), keySsh.trim()); t.end(); }); test('encrypted pkcs8 ecdsa private key (3des, pbkdf2 sha256)', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'id_ecdsa_pkcs8_enc')); var key = sshpk.parsePrivateKey(keyPem, 'pem', { passphrase: 'foobar' }); t.equal(key.type, 'ecdsa'); t.equal(key.fingerprint('sha256').toString(), 'SHA256:e34c67Npv31uMtfVUEBJln5aOcJugzDaYGsj1Uph5DE'); t.end(); }); test('encrypted pkcs8 ecdsa private key (aes256, pbkdf2 sha256)', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'id_ecdsa_pkcs8_enc2')); var key = sshpk.parsePrivateKey(keyPem, 'pem', { passphrase: 'testing123' }); t.equal(key.type, 'ecdsa'); t.equal(key.fingerprint('sha256').toString(), 'SHA256:e34c67Npv31uMtfVUEBJln5aOcJugzDaYGsj1Uph5DE'); t.end(); }); test('encrypted pkcs8 ecdsa private key (aes256, pbkdf2 sha1)', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'id_ecdsa_pkcs8_enc3')); var key = sshpk.parsePrivateKey(keyPem, 'pem', { passphrase: 'foobar123' }); t.equal(key.type, 'ecdsa'); t.equal(key.fingerprint('sha256').toString(), 'SHA256:e34c67Npv31uMtfVUEBJln5aOcJugzDaYGsj1Uph5DE'); t.end(); }); test('bad encrypted pkcs8 keys', function (t) { var keyPem = fs.readFileSync( path.join(testDir, 'pkcs8-enc-bad-scheme')); t.throws(function () { sshpk.parsePrivateKey(keyPem, 'pem', { passphrase: 'foobar' }); }, /unsupported pem\/pkcs8 encryption scheme/i); keyPem = fs.readFileSync(path.join(testDir, 'pkcs8-enc-bad-kdf')); t.throws(function () { sshpk.parsePrivateKey(keyPem, 'pem', { passphrase: 'foobar' }); }, /unsupported pbes2 kdf/i); keyPem = fs.readFileSync(path.join(testDir, 'pkcs8-enc-bad-hash')); t.throws(function () { sshpk.parsePrivateKey(keyPem, 'pem', { passphrase: 'foobar' }); }, /unsupported pbkdf2 hash/i); keyPem = fs.readFileSync(path.join(testDir, 'pkcs8-enc-bad-iters')); t.throws(function () { sshpk.parsePrivateKey(keyPem, 'pem', { passphrase: 'foobar' }); }, /incorrect passphrase/i); t.end(); }); node-sshpk-1.16.1/test/private-key.js000066400000000000000000000312231342215657600174440ustar00rootroot00000000000000// Copyright 2017 Joyent, Inc. All rights reserved. var test = require('tape').test; var sshpk = require('../lib/index'); var path = require('path'); var fs = require('fs'); var testDir = path.join(__dirname, 'assets'); var ID_RSA_FP = sshpk.parseFingerprint( 'SHA256:tT5wcGMJkBzNu+OoJYEgDCwIcDAIFCUahAmuTT4qC3s'); var ID_DSA_FP = sshpk.parseFingerprint( 'SHA256:PCfwpK62grBWrAJceLetSNv9CTrX8yoD0miKf11DBG8'); var ID_ECDSA_FP = sshpk.parseFingerprint( 'SHA256:e34c67Npv31uMtfVUEBJln5aOcJugzDaYGsj1Uph5DE'); var ID_ECDSA2_FP = sshpk.parseFingerprint( 'SHA256:Kyu0EMqH8fzfp9RXKJ6kmsk9qKGBqVRtlOuk6bXfCEU'); var ID_ED25519_FP = sshpk.parseFingerprint( 'SHA256:2UeFLCUKw2lvd8O1zfINNVzE0kUcu2HJHXQr/TGHt60'); var ID_RSA_O_FP = sshpk.parseFingerprint( 'SHA256:sfZqx0wyXwuXhsza0Ld99+/YNEMFyubTD8fPJ1Jo7Xw'); var ID_ECDSA_ENC_FP = sshpk.parseFingerprint( 'SHA256:n2/53LRiEy+DBbKltRHQC36vwRndRJve+912b8zDvow'); test('PrivateKey load RSA key', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'id_rsa')); var key = sshpk.parsePrivateKey(keyPem, 'pem'); t.strictEqual(key.type, 'rsa'); t.strictEqual(key.size, 1024); t.ok(ID_RSA_FP.matches(key)); t.end(); }); test('PrivateKey load DSA key', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'id_dsa')); var key = sshpk.parsePrivateKey(keyPem, 'pem'); t.strictEqual(key.type, 'dsa'); t.strictEqual(key.size, 1024); t.ok(ID_DSA_FP.matches(key)); t.end(); }); test('PrivateKey load ECDSA 384 key', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'id_ecdsa')); var key = sshpk.parsePrivateKey(keyPem, 'pem'); t.strictEqual(key.type, 'ecdsa'); t.strictEqual(key.size, 384); t.ok(ID_ECDSA_FP.matches(key)); t.end(); }); test('PrivateKey load ECDSA 256 key', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'id_ecdsa2')); var key = sshpk.parsePrivateKey(keyPem, 'pem'); t.strictEqual(key.type, 'ecdsa'); t.strictEqual(key.size, 256); t.ok(ID_ECDSA2_FP.matches(key)); t.end(); }); test('PrivateKey can\'t load a secp224r1 key', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'secp224r1_key.pem')); t.throws(function() { sshpk.parsePrivateKey(keyPem, 'pem'); }); t.end(); }); test('PrivateKey load ECDSA 256 key explicit curve', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'id_ecdsa_exp')); var key = sshpk.parsePrivateKey(keyPem, 'pem'); t.strictEqual(key.type, 'ecdsa'); t.strictEqual(key.size, 256); t.strictEqual(key.curve, 'nistp256'); t.end(); }); test('PrivateKey load ED25519 256 key', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'id_ed25519')); var key = sshpk.parsePrivateKey(keyPem, 'pem'); t.strictEqual(key.type, 'ed25519'); t.strictEqual(key.size, 256); t.ok(ID_ED25519_FP.matches(key)); keyPem = key.toBuffer('openssh'); var key2 = sshpk.parsePrivateKey(keyPem, 'openssh'); t.ok(ID_ED25519_FP.matches(key2)); keyPem = key.toBuffer('pkcs1'); var realKeyPem = fs.readFileSync(path.join(testDir, 'id_ed25519.pem')); t.strictEqual(keyPem.toString('base64'), realKeyPem.toString('base64')); t.end(); }); test('PrivateKey load ed25519 pem key', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'id_ed25519.pem')); var key = sshpk.parsePrivateKey(keyPem, 'pem'); t.strictEqual(key.type, 'ed25519'); t.strictEqual(key.size, 256); t.ok(ID_ED25519_FP.matches(key)); t.end(); }); test('PrivateKey load ed25519 key (ex. from curdle-pkix-04)', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'ed25519-pkix.pem')); var key = sshpk.parsePrivateKey(keyPem, 'pem'); t.strictEqual(key.type, 'ed25519'); t.strictEqual(key.size, 256); t.end(); }); test('PrivateKey load ed25519 key (no public curdle-pkix-05)', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'curdle-pkix-privonly.pem')); var key = sshpk.parsePrivateKey(keyPem, 'pem'); t.strictEqual(key.type, 'ed25519'); t.strictEqual(key.size, 256); t.end(); }); test('PrivateKey load ed25519 key (w/ public curdle-pkix-05)', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'curdle-pkix-withpub.pem')); var key = sshpk.parsePrivateKey(keyPem, 'pem'); t.strictEqual(key.type, 'ed25519'); t.strictEqual(key.size, 256); t.end(); }); test('PrivateKey invalid ed25519 key (not DER)', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'ed25519-invalid-ber.pem')); t.throws(function () { sshpk.parsePrivateKey(keyPem, 'pem'); }); t.end(); }); test('PrivateKey invalid ed25519 key (invalid curve point)', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'ed25519-invalid-mask.pem')); t.throws(function () { sshpk.parsePrivateKey(keyPem, 'pem'); }); t.end(); }); test('PrivateKey invalid ed25519 key (elided zero)', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'ed25519-invalid-zero.pem')); /* * We're actually more forgiving of this kind of invalid input than * the RFC says we need to be. Since this is purely about the format of * the data, and not about the validity of the point itself this should * be safe. */ var key = sshpk.parsePrivateKey(keyPem, 'pem'); t.end(); }); test('PrivateKey convert ssh-private rsa to pem', function (t) { var keySsh = fs.readFileSync(path.join(testDir, 'id_rsa_o')); var key = sshpk.parsePrivateKey(keySsh, 'ssh-private'); t.strictEqual(key.type, 'rsa'); t.strictEqual(key.size, 1044); t.ok(ID_RSA_O_FP.matches(key)); var keyPem = key.toBuffer('pkcs8'); var key2 = sshpk.parsePrivateKey(keyPem, 'pem'); t.ok(ID_RSA_O_FP.matches(key2)); var signer = key2.createSign('sha1'); signer.update('foobar'); var sig = signer.sign(); /* * Compare this to a known good signature from this key, generated by * the openssh agent */ t.strictEqual(sig.toString(), 'CiMwFuHYzmiRY70E5XC5LqoSBItMUmpWkAUvf' + 'mx0T63WnX22ir+072EcMQkLDdrjWPwVHx0Cw52uA88FiC4BX74/PzB2Chi4pgTx' + 'p8RVRLKYY54ze+XT12iQPBU7oVRkr+ZoM3INZshZ3MhomvEQuVUQuAWlek6LLXp' + 'x+mVg8XlMS8g='); t.end(); }); test('parse pkcs8 unencrypted private keys', function (t) { var keyPkcs8 = fs.readFileSync(path.join(testDir, 'id_rsa8')); var key = sshpk.parsePrivateKey(keyPkcs8, 'pkcs8'); t.strictEqual(key.type, 'rsa'); t.ok(ID_RSA_FP.matches(key)); var newPkcs8 = key.toBuffer('pkcs8'); t.strictEqual(keyPkcs8.toString(), newPkcs8.toString()); keyPkcs8 = fs.readFileSync(path.join(testDir, 'id_ecdsa8')); key = sshpk.parsePrivateKey(keyPkcs8, 'pkcs8'); t.strictEqual(key.type, 'ecdsa'); t.ok(ID_ECDSA_FP.matches(key)); newPkcs8 = key.toBuffer('pkcs8'); t.strictEqual(keyPkcs8.toString(), newPkcs8.toString()); keyPkcs8 = fs.readFileSync(path.join(testDir, 'id_dsa8')); key = sshpk.parsePrivateKey(keyPkcs8, 'pkcs8'); t.strictEqual(key.type, 'dsa'); t.ok(ID_DSA_FP.matches(key)); newPkcs8 = key.toBuffer('pkcs8'); t.strictEqual(keyPkcs8.toString(), newPkcs8.toString()); t.end(); }); test('parse and produce encrypted ssh-private ecdsa', function (t) { var keySsh = fs.readFileSync(path.join(testDir, 'id_ecdsa_enc')); t.throws(function () { sshpk.parsePrivateKey(keySsh, 'ssh-private'); }); t.throws(function () { sshpk.parsePrivateKey(keySsh, 'ssh-private', { passphrase: 'incorrect' }); }); var key = sshpk.parsePrivateKey(keySsh, 'ssh-private', { passphrase: 'foobar' }); t.strictEqual(key.type, 'ecdsa'); t.strictEqual(key.size, 256); t.ok(ID_ECDSA_ENC_FP.matches(key)); var keySsh2 = key.toBuffer('ssh-private', { passphrase: 'foobar2' }); t.throws(function () { sshpk.parsePrivateKey(keySsh2, 'ssh-private', { passphrase: 'foobar' }); }); var key2 = sshpk.parsePrivateKey(keySsh2, 'ssh-private', { passphrase: 'foobar2' }); t.strictEqual(key.type, 'ecdsa'); t.strictEqual(key.size, 256); t.ok(ID_ECDSA_ENC_FP.matches(key)); t.end(); }); test('pem pkcs#5 encrypted with aes-256-cbc', function (t) { var keyPem = fs.readFileSync(path.join(testDir, 'p50key.pem')); t.throws(function () { sshpk.parsePrivateKey(keyPem, 'pem'); }); t.throws(function () { sshpk.parsePrivateKey(keyPem, 'pem', { passphrase: 'incorrect' }); }); var key = sshpk.parsePrivateKey(keyPem, 'pem', { passphrase: 'pass' }); t.strictEqual(key.type, 'rsa'); t.strictEqual(key.size, 2048); t.end(); }); var KEY_RSA, KEY_DSA, KEY_ECDSA, KEY_ECDSA2, KEY_ED25519; test('setup keys', function (t) { KEY_RSA = sshpk.parsePrivateKey(fs.readFileSync( path.join(testDir, 'id_rsa')), 'pem'); KEY_DSA = sshpk.parsePrivateKey(fs.readFileSync( path.join(testDir, 'id_dsa')), 'pem'); KEY_ECDSA = sshpk.parsePrivateKey(fs.readFileSync( path.join(testDir, 'id_ecdsa')), 'pem'); KEY_ECDSA2 = sshpk.parsePrivateKey(fs.readFileSync( path.join(testDir, 'id_ecdsa2')), 'pem'); KEY_ED25519 = sshpk.parsePrivateKey(fs.readFileSync( path.join(testDir, 'id_ed25519')), 'pem'); t.end(); }); test('PrivateKey#toPublic on RSA key', function (t) { var pubKey = KEY_RSA.toPublic(); t.strictEqual(KEY_RSA.type, pubKey.type); t.strictEqual(KEY_RSA.size, pubKey.size); t.strictEqual(KEY_RSA.hash('sha256').toString('base64'), pubKey.hash('sha256').toString('base64')); t.notStrictEqual(KEY_RSA.toString('pem'), pubKey.toString('pem')); t.end(); }); test('PrivateKey#createSign on RSA key', function (t) { var s = KEY_RSA.createSign('sha256'); s.update('foobar'); var sig = s.sign(); t.ok(sig); t.ok(sig instanceof sshpk.Signature); var v = KEY_RSA.createVerify('sha256'); v.update('foobar'); t.ok(v.verify(sig)); t.end(); }); test('PrivateKey#createSign on DSA key', function (t) { var s = KEY_DSA.createSign('sha256'); s.update('foobar'); var sig = s.sign(); t.ok(sig); t.ok(sig instanceof sshpk.Signature); var v = KEY_DSA.createVerify('sha256'); v.update('foobar'); t.ok(v.verify(sig)); t.end(); }); test('PrivateKey#createSign on ECDSA 384 key', function (t) { var s = KEY_ECDSA.createSign('sha256'); s.update('foobar'); var sig = s.sign(); t.ok(sig); t.ok(sig instanceof sshpk.Signature); var v = KEY_ECDSA.createVerify('sha256'); v.update('foobar'); t.ok(v.verify(sig)); t.end(); }); test('PrivateKey#createSign on ECDSA 256 key', function (t) { var s = KEY_ECDSA2.createSign('sha256'); s.update('foobar'); var sig = s.sign(); t.ok(sig); t.ok(sig instanceof sshpk.Signature); var v = KEY_ECDSA2.createVerify('sha256'); v.update('foobar'); t.ok(v.verify(sig)); t.end(); }); test('PrivateKey.generate ecdsa default', function (t) { var key = sshpk.generatePrivateKey('ecdsa'); t.ok(sshpk.PrivateKey.isPrivateKey(key)); t.strictEqual(key.type, 'ecdsa'); t.strictEqual(key.curve, 'nistp256'); t.strictEqual(key.size, 256); var s = key.createSign('sha256'); s.update('foobar'); var sig = s.sign(); t.ok(sig); t.ok(sig instanceof sshpk.Signature); var key2 = sshpk.parsePrivateKey(key.toBuffer('pem')); var v = key2.createVerify('sha256'); v.update('foobar'); t.ok(v.verify(sig)); var key3 = sshpk.generatePrivateKey('ecdsa'); t.ok(!key3.fingerprint().matches(key)); t.end(); }); test('PrivateKey.generate ecdsa p-384', function (t) { var key = sshpk.generatePrivateKey('ecdsa', { curve: 'nistp384' }); t.ok(sshpk.PrivateKey.isPrivateKey(key)); t.strictEqual(key.type, 'ecdsa'); t.strictEqual(key.curve, 'nistp384'); t.strictEqual(key.size, 384); t.end(); }); test('pkcs8 PrivateKey without public part', function (t) { var pem = fs.readFileSync(path.join(testDir, 'pkcs8-nopub.pem')); var key = sshpk.parsePrivateKey(pem, 'pem'); t.strictEqual(key.type, 'ecdsa'); t.strictEqual(key.curve, 'nistp256'); var fp = sshpk.parseFingerprint( 'SHA256:wU/JTqlHV21vv0tcaNOFUZD2FXciO2KwImEOW1+AH50'); t.ok(fp.matches(key)); t.end(); }); if (process.version.match(/^v0\.[0-9]\./)) return; test('PrivateKey.generate ed25519', function (t) { var key = sshpk.generatePrivateKey('ed25519'); t.ok(sshpk.PrivateKey.isPrivateKey(key)); t.strictEqual(key.type, 'ed25519'); t.strictEqual(key.size, 256); var s = key.createSign('sha512'); s.update('foobar'); var sig = s.sign(); t.ok(sig); t.ok(sig instanceof sshpk.Signature); var sshPub = key.toPublic().toBuffer('ssh'); var key2 = sshpk.parseKey(sshPub); t.ok(key2.fingerprint().matches(key)); var v = key2.createVerify('sha512'); v.update('foobar'); t.ok(v.verify(sig)); t.end(); }); test('PrivateKey#createSign on ED25519 key', function (t) { var s = KEY_ED25519.createSign('sha512'); s.write('foobar'); var sig = s.sign(); t.ok(sig); t.ok(sig instanceof sshpk.Signature); var v = KEY_ED25519.createVerify('sha512'); v.write('foobar'); t.ok(v.verify(sig)); var v2 = KEY_ECDSA2.createVerify('sha512'); v2.write('foobar'); t.notOk(v2.verify(sig)); /* ED25519 always uses SHA-512 */ t.throws(function() { KEY_ED25519.createSign('sha1'); }); t.throws(function() { KEY_ED25519.createVerify('sha256'); }); t.end(); }); node-sshpk-1.16.1/test/putty.js000066400000000000000000000045241342215657600163750ustar00rootroot00000000000000// Copyright 2018 Joyent, Inc. All rights reserved. var test = require('tape').test; var fs = require('fs'); var path = require('path'); var sshpk = require('../lib/index'); var testDir = path.join(__dirname, 'assets'); var PUTTY_DSA, PUTTY_DSA_PUB, PUTTY_RSA, PUTTY_DSA_SSH, PUTTY_DSA_LONG; test('setup', function (t) { PUTTY_DSA = fs.readFileSync(path.join(testDir, 'dsa.ppk')); PUTTY_DSA_PUB = fs.readFileSync(path.join(testDir, 'dsa-pub.ppk')); PUTTY_RSA = fs.readFileSync(path.join(testDir, 'rsa.ppk')); PUTTY_DSA_SSH = fs.readFileSync(path.join(testDir, 'dsa-ppk.pub')); PUTTY_DSA_LONG = fs.readFileSync(path.join(testDir, 'dsa-pub-err.ppk')); t.end(); }); test('parse DSA ppk file', function (t) { var k = sshpk.parseKey(PUTTY_DSA, 'putty'); t.strictEqual(k.type, 'dsa'); t.strictEqual(k.fingerprint('sha256').toString(), 'SHA256:wWAQNw7Px2Hymk7kimFL35jzdLqRt9V9hB5RH20YX8s'); t.strictEqual(k.comment, 'dsa-key-20170331'); var pub = k.toString('ssh'); t.strictEqual(pub, PUTTY_DSA_SSH.toString('ascii').trim()); t.end(); }); test('parse DSA ppk file pub-only truncated', function (t) { var k = sshpk.parseKey(PUTTY_DSA_PUB, 'putty'); t.strictEqual(k.type, 'dsa'); t.strictEqual(k.fingerprint('sha256').toString(), 'SHA256:wWAQNw7Px2Hymk7kimFL35jzdLqRt9V9hB5RH20YX8s'); t.strictEqual(k.comment, 'dsa-key-20170331'); t.end(); }); test('parse RSA ppk file', function (t) { var k = sshpk.parseKey(PUTTY_RSA, 'putty'); t.strictEqual(k.type, 'rsa'); t.strictEqual(k.fingerprint('sha256').toString(), 'SHA256:WqDr0IdKUPtbitHUtWGGsA/xV/JhxPbVJG+E0SLWEig'); t.strictEqual(k.comment, 'rsa-key-20170331'); t.end(); }); test('parse garbage as putty', function (t) { t.throws(function () { sshpk.parseKey('asdflkasdjflasjf', 'putty'); }, /first line/i); t.throws(function () { sshpk.parseKey(PUTTY_DSA_LONG, 'putty'); }, /public-lines/i); t.throws(function () { var data = PUTTY_DSA.toString('ascii'). replace(/: ssh-dss/, ': ssh-rsa'); sshpk.parseKey(data, 'putty'); }, /algorithm mismatch/i); t.end(); }); test('parse RSA ppk file with auto', function (t) { var k = sshpk.parseKey(PUTTY_RSA, 'auto'); t.strictEqual(k.type, 'rsa'); t.end(); }); test('generate dsa', function (t) { var k = sshpk.parseKey(PUTTY_DSA_SSH); var ppk = k.toString('putty'); t.strictEqual(ppk, PUTTY_DSA_PUB.toString('ascii')); t.end(); }); node-sshpk-1.16.1/test/signature.js000066400000000000000000000172461342215657600172160ustar00rootroot00000000000000// Copyright 2011 Joyent, Inc. All rights reserved. var test = require('tape').test; var sshpk = require('../lib/index'); var fs = require('fs'); var path = require('path'); var crypto = require('crypto'); var testDir = path.join(__dirname, 'assets'); var RSA_PEM = fs.readFileSync(path.join(testDir, 'id_rsa')); var DSA_PEM = fs.readFileSync(path.join(testDir, 'id_dsa')); var ECDSA_PEM = fs.readFileSync(path.join(testDir, 'id_ecdsa')); var ED25519_PEM = fs.readFileSync(path.join(testDir, 'id_ed25519')); var RSA_KEY, DSA_KEY, ECDSA_KEY, ED25519_KEY; var DSA_SIG_ASN1 = 'MC0CFQCMhYhmerSHEK8h3Dd6DkWQggzY9QIUZ0sK0YNM9X3XfXo+jHiW' + 'cp7D1zU='; var ECDSA_SIG_ASN1 = 'MGUCMHkr2PgfR6vhLvXcY9bJOZN1AJAq9+YGmca95AC6iaNy3vqihq' + 'fuYQMaH5xO7HRdUQIxAN9BGGg2TQ8VL1kIfBzHUXA4eEbhEWStxeHKwscfxr5oj5yh5dI5F' + 'Fz5o4JnQzaqkQ==' var RSA_SIG = 'XSnn5R/INegb91WFY29K/oI0LEqEBFMmr6JkeTgw19yD9KsBhnMW5v7XvizWk' + 'oWYfnpO+LjJMMpYEMVayleexjuYH88EihViCF/VciqSCK0lHpfPQ9NHiKlK+KRdtzNezHta' + 'YlqCAbk2OAJF/mr/y+0SSm5jrDeJcz/a21gRuf4='; var DSA_SIG_HEX = '00000007' + '7373682d647373' + '00000028' + '8c8588667ab48710af21dc377a0e4590820cd8f5' + '674b0ad1834cf57dd77d7a3e8c7896729ec3d735'; var RSA_SIG_SSH = 'AAAAB3NzaC1yc2EAAACAXSnn5R/INegb91WFY29K/oI0LEqEBFMmr6Jke' + 'Tgw19yD9KsBhnMW5v7XvizWkoWYfnpO+LjJMMpYEMVayleexjuYH88EihViCF/VciqSCK0l' + 'HpfPQ9NHiKlK+KRdtzNezHtaYlqCAbk2OAJF/mr/y+0SSm5jrDeJcz/a21gRuf4='; var DSA_SIG2_SSH = 'IcR83A4YPEn22Vnh09S9RHRhVD5fol0BoLbC1wcRpvoR46OZQguEzQ=='; var ECDSA_SIG2_SSH = 'AAAAMHs/mn99fHqPG3YsD5WOcZtLxmKwTvII1zzKKIZCgzmtgw9ttg' + '0i5W0yNCEJFc9eMQAAADEA1glXKGoiWzQKaVg0r2RQjnwtioaSV2a0WJFmRdxUi6UzNKbBQ' + 'PanBc1MjwLVFnck'; var ECDSA2_SIG_SSH = 'AAAAIQCI1U+x3NzeTwPtISDGhGrPaqURX/NiCCbRzrtghOTaewAAAC' + 'EAvL6M14xBYD1DHACgO+rkZqA+IbN5jcdCUx858CEoz9c='; var ECDSA_SIG3_SSH = 'AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAABoAAAAMEfV+/DfXI5bYq' + 'niW7H+KQSBQTqT4ChUtHfCd0AYH+QzwBf16R+H2JjAxuKzIhjjggAAADAlmHXEs07JDWzO+' + 'cPy1k/gec3OQaKv7UOCcThjA5QQT840JgFbaoR7q71ZdU1Te0o='; var ED25519_SIG_SSH = 'AAAAC3NzaC1lZDI1NTE5AAAAQI9k67LtavkMlKZgw/vvlY9NfkVGU' + '/Vln+nFWvs0Xc0Bkew6FTaR4IZo0q2C4bOsN9jlYSNu3CsMtlrjvQcR9w8='; test('setup', function(t) { RSA_KEY = sshpk.parseKey(RSA_PEM, 'pem'); DSA_KEY = sshpk.parseKey(DSA_PEM, 'pem'); ECDSA_KEY = sshpk.parseKey(ECDSA_PEM, 'pem'); ED25519_KEY = sshpk.parsePrivateKey(ED25519_PEM, 'pem'); t.end(); }); test('convert RSA sig to SSH format', function(t) { var sig = sshpk.parseSignature(RSA_SIG, 'rsa', 'asn1'); t.strictEqual(sig.toString('ssh'), RSA_SIG_SSH); t.end(); }); test('parse an invalid signature', function(t) { t.throws(function() { sshpk.parseSignature('AAAAA', 'dsa', 'asn1'); }, sshpk.SignatureParseError); t.throws(function() { sshpk.parseSignature('AAAAA', 'ecdsa', 'ssh'); }, sshpk.SignatureParseError); t.throws(function() { sshpk.parseSignature('', 'rsa', 'ssh'); }, sshpk.SignatureParseError); t.end(); }); test('parse RSA sig in full wire SSH format and verify', function(t) { var sig = sshpk.parseSignature(RSA_SIG_SSH, 'rsa', 'ssh'); var key = sshpk.parseKey( fs.readFileSync(path.join(testDir, 'id_rsa')), 'pem'); var s = key.createVerify('sha1'); s.update('foobar'); t.ok(s.verify(sig)); t.end(); }); test('convert DSA sig to SSH format and back', function(t) { var sig = sshpk.parseSignature(DSA_SIG_ASN1, 'dsa', 'asn1'); t.strictEqual(sig.toString('asn1'), DSA_SIG_ASN1); t.strictEqual(sig.toBuffer('ssh').toString('hex'), DSA_SIG_HEX); var sig2 = sshpk.parseSignature(sig.toString('ssh'), 'dsa', 'ssh'); t.strictEqual(sig2.toString('asn1'), DSA_SIG_ASN1); t.end(); }); test('convert ECDSA sig to SSH format and back', function(t) { var sig = sshpk.parseSignature(ECDSA_SIG_ASN1, 'ecdsa', 'asn1'); t.strictEqual(sig.toString('asn1'), ECDSA_SIG_ASN1); var sig2 = sshpk.parseSignature(sig.toString('ssh'), 'ecdsa', 'ssh'); t.strictEqual(sig2.toString('asn1'), ECDSA_SIG_ASN1); t.end(); }); test('convert SSH DSA sig and verify', function(t) { var key = sshpk.parseKey( fs.readFileSync(path.join(testDir, 'id_dsa')), 'pem'); var sig = sshpk.parseSignature(DSA_SIG2_SSH, 'dsa', 'ssh'); var s = key.createVerify(); s.update('foobar'); t.ok(s.verify(sig)); t.end(); }); test('sign with DSA and loopback ssh', function(t) { var key = sshpk.parsePrivateKey( fs.readFileSync(path.join(testDir, 'id_dsa')), 'pem'); var signer = key.createSign(); signer.update('foobar'); var sig = signer.sign(); var data = sig.toBuffer('ssh'); sig = sshpk.parseSignature(data, 'dsa', 'ssh'); var s = key.createVerify(); s.update('foobar'); t.ok(s.verify(sig)); t.end(); }); test('sign with RSA and loopback ssh', function(t) { var key = sshpk.parsePrivateKey( fs.readFileSync(path.join(testDir, 'id_rsa')), 'pem'); var signer = key.createSign(); signer.update('foobar'); var sig = signer.sign(); var data = sig.toBuffer('ssh'); sig = sshpk.parseSignature(data, 'rsa', 'ssh'); var s = key.createVerify(); s.update('foobar'); t.ok(s.verify(sig)); t.end(); }); test('sign with ECDSA-256 and loopback ssh', function(t) { var key = sshpk.parsePrivateKey( fs.readFileSync(path.join(testDir, 'id_ecdsa2')), 'pem'); var signer = key.createSign(); signer.update('foobar'); var sig = signer.sign(); var data = sig.toBuffer('ssh'); sig = sshpk.parseSignature(data, 'ecdsa', 'ssh'); var s = key.createVerify(); s.update('foobar'); t.ok(s.verify(sig)); t.end(); }); test('convert SSH ECDSA-256 sig and verify', function(t) { var key = sshpk.parseKey( fs.readFileSync(path.join(testDir, 'id_ecdsa2')), 'pem'); var sig = sshpk.parseSignature(ECDSA2_SIG_SSH, 'ecdsa', 'ssh'); var s = key.createVerify(); s.update('foobar'); t.ok(s.verify(sig)); t.end(); }); test('signature of wrong type fails verification', function(t) { var key = sshpk.parseKey( fs.readFileSync(path.join(testDir, 'id_ecdsa')), 'pem'); var sig = sshpk.parseSignature(ECDSA_SIG_ASN1, 'rsa', 'asn1'); var s = key.createVerify(); s.update('foobar'); t.notOk(s.verify(sig)); t.end(); }); test('signature on wrong data fails verification', function(t) { var key = sshpk.parseKey( fs.readFileSync(path.join(testDir, 'id_ecdsa2')), 'pem'); var sig = sshpk.parseSignature(ECDSA2_SIG_SSH, 'ecdsa', 'ssh'); var s = key.createVerify(); s.update('foonotbar'); t.ok(!s.verify(sig)); t.end(); }); test('signature with wrong key fails verification', function(t) { var key = sshpk.parseKey( fs.readFileSync(path.join(testDir, 'id_ecdsa')), 'pem'); var sig = sshpk.parseSignature(ECDSA2_SIG_SSH, 'ecdsa', 'ssh'); var s = key.createVerify(); s.update('foobar'); t.ok(!s.verify(sig)); t.end(); }); test('convert SSH ECDSA-384 sig and verify', function(t) { var key = sshpk.parseKey( fs.readFileSync(path.join(testDir, 'id_ecdsa')), 'pem'); var sig = sshpk.parseSignature(ECDSA_SIG2_SSH, 'ecdsa', 'ssh'); var s = key.createVerify(); s.update('foobar'); t.ok(s.verify(sig)); t.end(); }); test('convert full wire SSH ECDSA-384 sig and verify', function(t) { var key = sshpk.parseKey( fs.readFileSync(path.join(testDir, 'id_ecdsa')), 'pem'); var sig = sshpk.parseSignature(ECDSA_SIG3_SSH, 'ecdsa', 'ssh'); var s = key.createVerify(); s.update('foobar'); t.ok(s.verify(sig)); t.end(); }); if (process.version.match(/^v0\.[0-9]\./)) return; test('parse ED25519 sig in full wire SSH format and verify', function(t) { var sig = sshpk.parseSignature(ED25519_SIG_SSH, 'ed25519', 'ssh'); var s = ED25519_KEY.createVerify(); s.update('foobar'); t.ok(s.verify(sig)); t.end(); }); test('sign with ED25519 key and convert to SSH format', function(t) { var s = ED25519_KEY.createSign(); s.update('foobar'); var sig = s.sign(); t.strictEqual(sig.toString('ssh'), ED25519_SIG_SSH); t.end(); }); node-sshpk-1.16.1/test/ssh-buffer.js000066400000000000000000000012041342215657600172440ustar00rootroot00000000000000// Copyright 2015 Joyent, Inc. All rights reserved. var test = require('tape').test; var SSHBuffer = require('../lib/ssh-buffer'); var Buffer = require('safer-buffer').Buffer; test('expands on write', function(t) { var buf = new SSHBuffer({buffer: Buffer.alloc(8)}); buf.writeCString('abc123'); buf.writeInt(42); buf.writeString('hi there what is up'); var out = buf.toBuffer(); t.ok(out.length > 8); var buf2 = new SSHBuffer({buffer: out}); t.strictEqual(buf2.readChar(), 97); t.strictEqual(buf2.readCString(), 'bc123'); t.strictEqual(buf2.readInt(), 42); t.strictEqual(buf2.readString(), 'hi there what is up'); t.end(); }); node-sshpk-1.16.1/test/utils.js000066400000000000000000000050511342215657600163440ustar00rootroot00000000000000// Copyright 2011 Joyent, Inc. All rights reserved. var test = require('tape').test; var Buffer = require('safer-buffer').Buffer; var utils = require('../lib/utils'); test('bufferSplit single char', function(t) { var b = Buffer.from('abc 123 xyz ttt'); var r = utils.bufferSplit(b, ' '); t.equal(r.length, 4); t.equal(r[0].toString(), 'abc'); t.equal(r[1].toString(), '123'); t.equal(r[2].toString(), 'xyz'); t.end(); }); test('bufferSplit single char double sep', function(t) { var b = Buffer.from('abc 123 xyz ttt'); var r = utils.bufferSplit(b, ' '); t.equal(r.length, 6); t.equal(r[0].toString(), 'abc'); t.equal(r[1].toString(), '123'); t.equal(r[4].toString(), ''); t.equal(r[5].toString(), 'ttt'); t.end(); }); test('bufferSplit multi char', function(t) { var b = Buffer.from('abc 123 xyz ttt '); var r = utils.bufferSplit(b, '123'); t.equal(r.length, 2); t.equal(r[0].toString(), 'abc '); t.equal(r[1].toString(), ' xyz ttt '); t.end(); }); /* These taken from RFC6070 */ test('pbkdf2 test vector 1', function (t) { var hashAlg = 'sha1'; var salt = Buffer.from('salt'); var iterations = 1; var size = 20; var passphrase = Buffer.from('password'); var key = utils.pbkdf2(hashAlg, salt, iterations, size, passphrase); t.equal(key.toString('hex').toLowerCase(), '0c60c80f961f0e71f3a9b524af6012062fe037a6'); t.end(); }); test('pbkdf2 test vector 2', function (t) { var hashAlg = 'sha1'; var salt = Buffer.from('salt'); var iterations = 2; var size = 20; var passphrase = Buffer.from('password'); var key = utils.pbkdf2(hashAlg, salt, iterations, size, passphrase); t.equal(key.toString('hex').toLowerCase(), 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'); t.end(); }); test('pbkdf2 test vector 5', function (t) { var hashAlg = 'sha1'; var salt = Buffer.from('saltSALTsaltSALTsaltSALTsaltSALTsalt'); var iterations = 4096; var size = 25; var passphrase = Buffer.from('passwordPASSWORDpassword'); var key = utils.pbkdf2(hashAlg, salt, iterations, size, passphrase); t.equal(key.toString('hex').toLowerCase(), '3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038'); t.end(); }); test('pbkdf2 wiki test', function (t) { var hashAlg = 'sha1'; var salt = Buffer.from('A009C1A485912C6AE630D3E744240B04', 'hex'); var iterations = 1000; var size = 16; var passphrase = Buffer.from( 'plnlrtfpijpuhqylxbgqiiyipieyxvfsavzgxbbcfusqkozwpngsyejqlmjsytrmd'); var key = utils.pbkdf2(hashAlg, salt, iterations, size, passphrase); t.equal(key.toString('hex').toUpperCase(), '17EB4014C8C461C300E9B61518B9A18B'); t.end(); }); node-sshpk-1.16.1/tools/000077500000000000000000000000001342215657600150265ustar00rootroot00000000000000node-sshpk-1.16.1/tools/jsl.node.conf000066400000000000000000000161051342215657600174140ustar00rootroot00000000000000# # Configuration File for JavaScript Lint # # This configuration file can be used to lint a collection of scripts, or to enable # or disable warnings for scripts that are linted via the command line. # ### Warnings # Enable or disable warnings based on requirements. # Use "+WarningName" to display or "-WarningName" to suppress. # +ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent +ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity +ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement +anon_no_return_value # anonymous function does not always return value +assign_to_function_call # assignment to a function call -block_without_braces # block statement without curly braces +comma_separated_stmts # multiple statements separated by commas (use semicolons?) +comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==) +default_not_at_end # the default case is not at the end of the switch statement +dup_option_explicit # duplicate "option explicit" control comment +duplicate_case_in_switch # duplicate case in switch statement +duplicate_formal # duplicate formal argument {name} +empty_statement # empty statement or extra semicolon +identifier_hides_another # identifer {name} hides an identifier in a parent scope -inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement +incorrect_version # Expected /*jsl:content-type*/ control comment. The script was parsed with the wrong version. +invalid_fallthru # unexpected "fallthru" control comment +invalid_pass # unexpected "pass" control comment +jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax +leading_decimal_point # leading decimal point may indicate a number or an object member +legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax +meaningless_block # meaningless block; curly braces have no impact +mismatch_ctrl_comments # mismatched control comment; "ignore" and "end" control comments must have a one-to-one correspondence +misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma +missing_break # missing break statement +missing_break_for_last_case # missing break statement for last case in switch +missing_default_case # missing default case in switch statement +missing_option_explicit # the "option explicit" control comment is missing +missing_semicolon # missing semicolon +missing_semicolon_for_lambda # missing semicolon for lambda assignment +multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs +nested_comment # nested comment +no_return_value # function {name} does not always return a value +octal_number # leading zeros make an octal number +parseint_missing_radix # parseInt missing radix parameter +partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag +redeclared_var # redeclaration of {name} +trailing_comma_in_array # extra comma is not recommended in array initializers +trailing_decimal_point # trailing decimal point may indicate a number or an object member +undeclared_identifier # undeclared identifier: {name} +unreachable_code # unreachable code -unreferenced_argument # argument declared but never referenced: {name} -unreferenced_function # function is declared but never referenced: {name} +unreferenced_variable # variable is declared but never referenced: {name} +unsupported_version # JavaScript {version} is not supported +use_of_label # use of label +useless_assign # useless assignment +useless_comparison # useless comparison; comparing identical expressions -useless_quotes # the quotation marks are unnecessary +useless_void # use of the void type may be unnecessary (void is always undefined) +var_hides_arg # variable {name} hides argument +want_assign_or_call # expected an assignment or function call +with_statement # with statement hides undeclared variables; use temporary variable instead ### Output format # Customize the format of the error message. # __FILE__ indicates current file path # __FILENAME__ indicates current file name # __LINE__ indicates current line # __COL__ indicates current column # __ERROR__ indicates error message (__ERROR_PREFIX__: __ERROR_MSG__) # __ERROR_NAME__ indicates error name (used in configuration file) # __ERROR_PREFIX__ indicates error prefix # __ERROR_MSG__ indicates error message # # For machine-friendly output, the output format can be prefixed with # "encode:". If specified, all items will be encoded with C-slashes. # # Visual Studio syntax (default): +output-format __FILE__(__LINE__): __ERROR__ # Alternative syntax: #+output-format __FILE__:__LINE__: __ERROR__ ### Context # Show the in-line position of the error. # Use "+context" to display or "-context" to suppress. # +context ### Control Comments # Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for # the /*@keyword@*/ control comments and JScript conditional comments. (The latter is # enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason, # although legacy control comments are enabled by default for backward compatibility. # -legacy_control_comments ### Defining identifiers # By default, "option explicit" is enabled on a per-file basis. # To enable this for all files, use "+always_use_option_explicit" -always_use_option_explicit # Define certain identifiers of which the lint is not aware. # (Use this in conjunction with the "undeclared identifier" warning.) # # Common uses for webpages might be: +define __dirname +define clearInterval +define clearTimeout +define console +define exports +define global +define module +define process +define require +define setInterval +define setTimeout +define Buffer +define JSON +define Math # ES6 Typed Arrays +define ArrayBuffer +define DataView +define Int8Array +define Uint8Array +define Uint8ClampedArray +define Int16Array +define Uint16Array +define Int32Array +define Uint32Array +define Float32Array +define Float64Array ### JavaScript Version # To change the default JavaScript version: #+default-type text/javascript;version=1.5 #+default-type text/javascript;e4x=1 ### Files # Specify which files to lint # Use "+recurse" to enable recursion (disabled by default). # To add a set of files, use "+process FileName", "+process Folder\Path\*.js", # or "+process Folder\Path\*.htm". # node-sshpk-1.16.1/tools/jsstyle.conf000066400000000000000000000000471342215657600173730ustar00rootroot00000000000000indent=tab blank-after-start-comment=0 node-sshpk-1.16.1/tools/mk/000077500000000000000000000000001342215657600154355ustar00rootroot00000000000000node-sshpk-1.16.1/tools/mk/Makefile.defs000066400000000000000000000027361342215657600200250ustar00rootroot00000000000000# -*- mode: makefile -*- # # Copyright (c) 2012, Joyent, Inc. All rights reserved. # # Makefile.defs: common defines. # # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped # into other repos as-is without requiring any modifications. If you find # yourself changing this file, you should instead update the original copy in # eng.git and then update your repo to use the new version. # # This makefile defines some useful defines. Include it at the top of # your Makefile. # # Definitions in this Makefile: # # TOP The absolute path to the project directory. The top dir. # BRANCH The current git branch. # TIMESTAMP The timestamp for the build. This can be set via # the TIMESTAMP envvar (used by MG-based builds). # STAMP A build stamp to use in built package names. # TOP := $(shell pwd) # # Mountain Gorilla-spec'd versioning. # See "Package Versioning" in MG's README.md: # # # Need GNU awk for multi-char arg to "-F". _AWK := $(shell (which gawk >/dev/null && echo gawk) \ || (which nawk >/dev/null && echo nawk) \ || echo awk) BRANCH := $(shell git symbolic-ref HEAD | $(_AWK) -F/ '{print $$3}') ifeq ($(TIMESTAMP),) TIMESTAMP := $(shell date -u "+%Y%m%dT%H%M%SZ") endif _GITDESCRIBE := g$(shell git describe --all --long --dirty | $(_AWK) -F'-g' '{print $$NF}') STAMP := $(BRANCH)-$(TIMESTAMP)-$(_GITDESCRIBE) # node-gyp will print build info useful for debugging with V=1 export V=1 node-sshpk-1.16.1/tools/mk/Makefile.deps000066400000000000000000000021741342215657600200330ustar00rootroot00000000000000# -*- mode: makefile -*- # # Copyright (c) 2012, Joyent, Inc. All rights reserved. # # Makefile.deps: Makefile for including common tools as dependencies # # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped # into other repos as-is without requiring any modifications. If you find # yourself changing this file, you should instead update the original copy in # eng.git and then update your repo to use the new version. # # This file is separate from Makefile.targ so that teams can choose # independently whether to use the common targets in Makefile.targ and the # common tools here. # # # javascriptlint # JSL_EXEC ?= deps/javascriptlint/build/install/jsl JSL ?= $(JSL_EXEC) $(JSL_EXEC): | deps/javascriptlint/.git cd deps/javascriptlint && make install distclean:: if [[ -f deps/javascriptlint/Makefile ]]; then \ cd deps/javascriptlint && make clean; \ fi # # jsstyle # JSSTYLE_EXEC ?= deps/jsstyle/jsstyle JSSTYLE ?= $(JSSTYLE_EXEC) $(JSSTYLE_EXEC): | deps/jsstyle/.git # # restdown # RESTDOWN_EXEC ?= deps/restdown/bin/restdown RESTDOWN ?= python $(RESTDOWN_EXEC) $(RESTDOWN_EXEC): | deps/restdown/.git node-sshpk-1.16.1/tools/mk/Makefile.node_deps.defs000066400000000000000000000026231342215657600217570ustar00rootroot00000000000000# -*- mode: makefile -*- # # Copyright (c) 2012, Joyent, Inc. All rights reserved. # # Makefile.node_deps.defs: Makefile for including npm modules whose sources # reside inside the repo. This should NOT be used for modules in the npm # public repo or modules that could be specified with git SHAs. # # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped # into other repos as-is without requiring any modifications. If you find # yourself changing this file, you should instead update the original copy in # eng.git and then update your repo to use the new version. # # # This Makefile takes as input the following make variable: # # REPO_MODULES List of relative paths to node modules (i.e., npm # packages) inside this repo. For example: # src/node-canative, where there's a binary npm package # in src/node-canative. # # Based on the above, this Makefile defines the following new variables: # # REPO_DEPS List of relative paths to the installed modules. For # example: "node_modules/canative". # # The accompanying Makefile.node_deps.targ defines a target that will install # each of REPO_MODULES into REPO_DEPS and remove REPO_DEPS with "make clean". # The top-level Makefile is responsible for depending on REPO_DEPS where # appropriate (usually the "deps" or "all" target). # REPO_DEPS := $(REPO_MODULES:src/node-%=node_modules/%) CLEAN_FILES += $(REPO_DEPS) node-sshpk-1.16.1/tools/mk/Makefile.node_deps.targ000066400000000000000000000011031342215657600217630ustar00rootroot00000000000000# -*- mode: makefile -*- # # Copyright (c) 2012, Joyent, Inc. All rights reserved. # # Makefile.node_deps.targ: targets for Makefile.node_deps.defs. # # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped # into other repos as-is without requiring any modifications. If you find # yourself changing this file, you should instead update the original copy in # eng.git and then update your repo to use the new version. # NPM_EXEC ?= $(error NPM_EXEC must be defined for Makefile.node_deps.targ) node_modules/%: src/node-% | $(NPM_EXEC) $(NPM) install $< node-sshpk-1.16.1/tools/mk/Makefile.targ000066400000000000000000000212511342215657600200320ustar00rootroot00000000000000# -*- mode: makefile -*- # # Copyright (c) 2012, Joyent, Inc. All rights reserved. # # Makefile.targ: common targets. # # NOTE: This makefile comes from the "eng" repo. It's designed to be dropped # into other repos as-is without requiring any modifications. If you find # yourself changing this file, you should instead update the original copy in # eng.git and then update your repo to use the new version. # # This Makefile defines several useful targets and rules. You can use it by # including it from a Makefile that specifies some of the variables below. # # Targets defined in this Makefile: # # check Checks JavaScript files for lint and style # Checks bash scripts for syntax # Checks SMF manifests for validity against the SMF DTD # # clean Removes built files # # docs Builds restdown documentation in docs/ # # prepush Depends on "check" and "test" # # test Does nothing (you should override this) # # xref Generates cscope (source cross-reference index) # # For details on what these targets are supposed to do, see the Joyent # Engineering Guide. # # To make use of these targets, you'll need to set some of these variables. Any # variables left unset will simply not be used. # # BASH_FILES Bash scripts to check for syntax # (paths relative to top-level Makefile) # # CLEAN_FILES Files to remove as part of the "clean" target. Note # that files generated by targets in this Makefile are # automatically included in CLEAN_FILES. These include # restdown-generated HTML and JSON files. # # DOC_FILES Restdown (documentation source) files. These are # assumed to be contained in "docs/", and must NOT # contain the "docs/" prefix. # # JSL_CONF_NODE Specify JavaScriptLint configuration files # JSL_CONF_WEB (paths relative to top-level Makefile) # # Node.js and Web configuration files are separate # because you'll usually want different global variable # configurations. If no file is specified, none is given # to jsl, which causes it to use a default configuration, # which probably isn't what you want. # # JSL_FILES_NODE JavaScript files to check with Node config file. # JSL_FILES_WEB JavaScript files to check with Web config file. # # You can also override these variables: # # BASH Path to bash (default: bash) # # CSCOPE_DIRS Directories to search for source files for the cscope # index. (default: ".") # # JSL Path to JavaScriptLint (default: "jsl") # # JSL_FLAGS_NODE Additional flags to pass through to JSL # JSL_FLAGS_WEB # JSL_FLAGS # # JSSTYLE Path to jsstyle (default: jsstyle) # # JSSTYLE_FLAGS Additional flags to pass through to jsstyle # # # Defaults for the various tools we use. # BASH ?= bash BASHSTYLE ?= tools/bashstyle CP ?= cp CSCOPE ?= cscope CSCOPE_DIRS ?= . JSL ?= jsl JSSTYLE ?= jsstyle MKDIR ?= mkdir -p MV ?= mv RESTDOWN_FLAGS ?= RMTREE ?= rm -rf JSL_FLAGS ?= --nologo --nosummary ifeq ($(shell uname -s),SunOS) TAR ?= gtar else TAR ?= tar endif # # Defaults for other fixed values. # BUILD = build DISTCLEAN_FILES += $(BUILD) DOC_BUILD = $(BUILD)/docs/public # # Configure JSL_FLAGS_{NODE,WEB} based on JSL_CONF_{NODE,WEB}. # ifneq ($(origin JSL_CONF_NODE), undefined) JSL_FLAGS_NODE += --conf=$(JSL_CONF_NODE) endif ifneq ($(origin JSL_CONF_WEB), undefined) JSL_FLAGS_WEB += --conf=$(JSL_CONF_WEB) endif # # Targets. For descriptions on what these are supposed to do, see the # Joyent Engineering Guide. # # # Instruct make to keep around temporary files. We have rules below that # automatically update git submodules as needed, but they employ a deps/*/.git # temporary file. Without this directive, make tries to remove these .git # directories after the build has completed. # .SECONDARY: $($(wildcard deps/*):%=%/.git) # # This rule enables other rules that use files from a git submodule to have # those files depend on deps/module/.git and have "make" automatically check # out the submodule as needed. # deps/%/.git: git submodule update --init deps/$* # # These recipes make heavy use of dynamically-created phony targets. The parent # Makefile defines a list of input files like BASH_FILES. We then say that each # of these files depends on a fake target called filename.bashchk, and then we # define a pattern rule for those targets that runs bash in check-syntax-only # mode. This mechanism has the nice properties that if you specify zero files, # the rule becomes a noop (unlike a single rule to check all bash files, which # would invoke bash with zero files), and you can check individual files from # the command line with "make filename.bashchk". # .PHONY: check-bash check-bash: $(BASH_FILES:%=%.bashchk) $(BASH_FILES:%=%.bashstyle) %.bashchk: % $(BASH) -n $^ %.bashstyle: % $(BASHSTYLE) $^ # # The above approach can be slow when there are many files to check because it # requires that "make" invoke the check tool once for each file, rather than # passing in several files at once. For the JavaScript check targets, we define # a variable for the target itself *only if* the list of input files is # non-empty. This avoids invoking the tool if there are no files to check. # JSL_NODE_TARGET = $(if $(JSL_FILES_NODE), check-jsl-node) .PHONY: check-jsl-node check-jsl-node: $(JSL_EXEC) $(JSL) $(JSL_FLAGS) $(JSL_FLAGS_NODE) $(JSL_FILES_NODE) JSL_WEB_TARGET = $(if $(JSL_FILES_WEB), check-jsl-web) .PHONY: check-jsl-web check-jsl-web: $(JSL_EXEC) $(JSL) $(JSL_FLAGS) $(JSL_FLAGS_WEB) $(JSL_FILES_WEB) .PHONY: check-jsl check-jsl: $(JSL_NODE_TARGET) $(JSL_WEB_TARGET) JSSTYLE_TARGET = $(if $(JSSTYLE_FILES), check-jsstyle) .PHONY: check-jsstyle check-jsstyle: $(JSSTYLE_EXEC) $(JSSTYLE) $(JSSTYLE_FLAGS) $(JSSTYLE_FILES) .PHONY: check check: check-jsl $(JSSTYLE_TARGET) check-bash @echo check ok .PHONY: clean clean:: -$(RMTREE) $(CLEAN_FILES) .PHONY: distclean distclean:: clean -$(RMTREE) $(DISTCLEAN_FILES) CSCOPE_FILES = cscope.in.out cscope.out cscope.po.out CLEAN_FILES += $(CSCOPE_FILES) .PHONY: xref xref: cscope.files $(CSCOPE) -bqR .PHONY: cscope.files cscope.files: find $(CSCOPE_DIRS) -name '*.c' -o -name '*.h' -o -name '*.cc' \ -o -name '*.js' -o -name '*.s' -o -name '*.cpp' > $@ # # The "docs" target is complicated because we do several things here: # # (1) Use restdown to build HTML and JSON files from each of DOC_FILES. # # (2) Copy these files into $(DOC_BUILD) (build/docs/public), which # functions as a complete copy of the documentation that could be # mirrored or served over HTTP. # # (3) Then copy any directories and media from docs/media into # $(DOC_BUILD)/media. This allows projects to include their own media, # including files that will override same-named files provided by # restdown. # # Step (3) is the surprisingly complex part: in order to do this, we need to # identify the subdirectories in docs/media, recreate them in # $(DOC_BUILD)/media, then do the same with the files. # DOC_MEDIA_DIRS := $(shell find docs/media -type d 2>/dev/null | grep -v "^docs/media$$") DOC_MEDIA_DIRS := $(DOC_MEDIA_DIRS:docs/media/%=%) DOC_MEDIA_DIRS_BUILD := $(DOC_MEDIA_DIRS:%=$(DOC_BUILD)/media/%) DOC_MEDIA_FILES := $(shell find docs/media -type f 2>/dev/null) DOC_MEDIA_FILES := $(DOC_MEDIA_FILES:docs/media/%=%) DOC_MEDIA_FILES_BUILD := $(DOC_MEDIA_FILES:%=$(DOC_BUILD)/media/%) # # Like the other targets, "docs" just depends on the final files we want to # create in $(DOC_BUILD), leveraging other targets and recipes to define how # to get there. # .PHONY: docs docs: \ $(DOC_FILES:%.restdown=$(DOC_BUILD)/%.html) \ $(DOC_FILES:%.restdown=$(DOC_BUILD)/%.json) \ $(DOC_MEDIA_FILES_BUILD) # # We keep the intermediate files so that the next build can see whether the # files in DOC_BUILD are up to date. # .PRECIOUS: \ $(DOC_FILES:%.restdown=docs/%.html) \ $(DOC_FILES:%.restdown=docs/%json) # # We do clean those intermediate files, as well as all of DOC_BUILD. # CLEAN_FILES += \ $(DOC_BUILD) \ $(DOC_FILES:%.restdown=docs/%.html) \ $(DOC_FILES:%.restdown=docs/%.json) # # Before installing the files, we must make sure the directories exist. The | # syntax tells make that the dependency need only exist, not be up to date. # Otherwise, it might try to rebuild spuriously because the directory itself # appears out of date. # $(DOC_MEDIA_FILES_BUILD): | $(DOC_MEDIA_DIRS_BUILD) $(DOC_BUILD)/%: docs/% | $(DOC_BUILD) $(CP) $< $@ docs/%.json docs/%.html: docs/%.restdown | $(DOC_BUILD) $(RESTDOWN_EXEC) $(RESTDOWN) $(RESTDOWN_FLAGS) -m $(DOC_BUILD) $< $(DOC_BUILD): $(MKDIR) $@ $(DOC_MEDIA_DIRS_BUILD): $(MKDIR) $@ # # The default "test" target does nothing. This should usually be overridden by # the parent Makefile. It's included here so we can define "prepush" without # requiring the repo to define "test". # .PHONY: test test: .PHONY: prepush prepush: check test