mirror of
				https://github.com/1disk/edp445.git
				synced 2024-08-14 22:47:02 +00:00 
			
		
		
		
	Changed alot of things.
This commit is contained in:
		
							parent
							
								
									a5a0523e5a
								
							
						
					
					
						commit
						3513d5390c
					
				
					 2016 changed files with 336930 additions and 9 deletions
				
			
		
							
								
								
									
										11
									
								
								node_modules/sshpk/.travis.yml
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								node_modules/sshpk/.travis.yml
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| language: node_js | ||||
| node_js: | ||||
|   - "5.10" | ||||
|   - "4.4" | ||||
|   - "4.1" | ||||
|   - "0.12" | ||||
|   - "0.10" | ||||
| before_install: | ||||
|   - "make check" | ||||
| after_success: | ||||
|   - '[ "${TRAVIS_NODE_VERSION}" = "4.4" ] && make codecovio' | ||||
							
								
								
									
										86
									
								
								node_modules/sshpk/Jenkinsfile
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								node_modules/sshpk/Jenkinsfile
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,86 @@ | |||
| @Library('jenkins-joylib@v1.0.8') _ | ||||
| 
 | ||||
| pipeline { | ||||
| 
 | ||||
|     agent none | ||||
| 
 | ||||
|     options { | ||||
|         buildDiscarder(logRotator(numToKeepStr: '30')) | ||||
|         timestamps() | ||||
|     } | ||||
| 
 | ||||
|     stages { | ||||
|         stage('top') { | ||||
|             parallel { | ||||
|                 stage('v0.10.48-zone') { | ||||
|                     agent { | ||||
|                         label joyCommonLabels(image_ver: '15.4.1') | ||||
|                     } | ||||
|                     tools { | ||||
|                         nodejs 'sdcnode-v0.10.48-zone' | ||||
|                     } | ||||
|                     stages { | ||||
|                         stage('check') { | ||||
|                             steps{ | ||||
|                                 sh('make check') | ||||
|                             } | ||||
|                         } | ||||
|                         stage('test') { | ||||
|                             steps{ | ||||
|                                 sh('make test') | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 stage('v4-zone') { | ||||
|                     agent { | ||||
|                         label joyCommonLabels(image_ver: '15.4.1') | ||||
|                     } | ||||
|                     tools { | ||||
|                         nodejs 'sdcnode-v4-zone' | ||||
|                     } | ||||
|                     stages { | ||||
|                         stage('check') { | ||||
|                             steps{ | ||||
|                                 sh('make check') | ||||
|                             } | ||||
|                         } | ||||
|                         stage('test') { | ||||
|                             steps{ | ||||
|                                 sh('make test') | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                  | ||||
|                 stage('v6-zone64') { | ||||
|                     agent { | ||||
|                         label joyCommonLabels(image_ver: '18.4.0') | ||||
|                     } | ||||
|                     tools { | ||||
|                         nodejs 'sdcnode-v6-zone64' | ||||
|                     } | ||||
|                     stages { | ||||
|                         stage('check') { | ||||
|                             steps{ | ||||
|                                 sh('make check') | ||||
|                             } | ||||
|                         } | ||||
|                         stage('test') { | ||||
|                             steps{ | ||||
|                                 sh('make test') | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     post { | ||||
|         always { | ||||
|             joySlackNotifications() | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										18
									
								
								node_modules/sshpk/LICENSE
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								node_modules/sshpk/LICENSE
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| Copyright Joyent, Inc. All rights reserved. | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to | ||||
| deal in the Software without restriction, including without limitation the | ||||
| rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||||
| sell copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in | ||||
| all copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
| IN THE SOFTWARE. | ||||
							
								
								
									
										804
									
								
								node_modules/sshpk/README.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										804
									
								
								node_modules/sshpk/README.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,804 @@ | |||
| sshpk | ||||
| ========= | ||||
| 
 | ||||
| Parse, convert, fingerprint and use SSH keys (both public and private) in pure | ||||
| node -- no `ssh-keygen` or other external dependencies. | ||||
| 
 | ||||
| Supports RSA, DSA, ECDSA (nistp-\*) and ED25519 key types, in PEM (PKCS#1,  | ||||
| PKCS#8) and OpenSSH formats. | ||||
| 
 | ||||
| This library has been extracted from | ||||
| [`node-http-signature`](https://github.com/joyent/node-http-signature) | ||||
| (work by [Mark Cavage](https://github.com/mcavage) and | ||||
| [Dave Eddy](https://github.com/bahamas10)) and | ||||
| [`node-ssh-fingerprint`](https://github.com/bahamas10/node-ssh-fingerprint) | ||||
| (work by Dave Eddy), with additions (including ECDSA support) by | ||||
| [Alex Wilson](https://github.com/arekinath). | ||||
| 
 | ||||
| Install | ||||
| ------- | ||||
| 
 | ||||
| ``` | ||||
| npm install sshpk | ||||
| ``` | ||||
| 
 | ||||
| Examples | ||||
| -------- | ||||
| 
 | ||||
| ```js | ||||
| var sshpk = require('sshpk'); | ||||
| 
 | ||||
| var fs = require('fs'); | ||||
| 
 | ||||
| /* Read in an OpenSSH-format public key */ | ||||
| var keyPub = fs.readFileSync('id_rsa.pub'); | ||||
| var key = sshpk.parseKey(keyPub, 'ssh'); | ||||
| 
 | ||||
| /* Get metadata about the key */ | ||||
| console.log('type => %s', key.type); | ||||
| console.log('size => %d bits', key.size); | ||||
| console.log('comment => %s', key.comment); | ||||
| 
 | ||||
| /* Compute key fingerprints, in new OpenSSH (>6.7) format, and old MD5 */ | ||||
| console.log('fingerprint => %s', key.fingerprint().toString()); | ||||
| console.log('old-style fingerprint => %s', key.fingerprint('md5').toString()); | ||||
| ``` | ||||
| 
 | ||||
| Example output: | ||||
| 
 | ||||
| ``` | ||||
| type => rsa | ||||
| size => 2048 bits | ||||
| comment => foo@foo.com | ||||
| fingerprint => SHA256:PYC9kPVC6J873CSIbfp0LwYeczP/W4ffObNCuDJ1u5w | ||||
| old-style fingerprint => a0:c8:ad:6c:32:9a:32:fa:59:cc:a9:8c:0a:0d:6e:bd | ||||
| ``` | ||||
| 
 | ||||
| More examples: converting between formats: | ||||
| 
 | ||||
| ```js | ||||
| /* Read in a PEM public key */ | ||||
| var keyPem = fs.readFileSync('id_rsa.pem'); | ||||
| var key = sshpk.parseKey(keyPem, 'pem'); | ||||
| 
 | ||||
| /* Convert to PEM PKCS#8 public key format */ | ||||
| var pemBuf = key.toBuffer('pkcs8'); | ||||
| 
 | ||||
| /* Convert to SSH public key format (and return as a string) */ | ||||
| var sshKey = key.toString('ssh'); | ||||
| ``` | ||||
| 
 | ||||
| Signing and verifying: | ||||
| 
 | ||||
| ```js | ||||
| /* Read in an OpenSSH/PEM *private* key */ | ||||
| var keyPriv = fs.readFileSync('id_ecdsa'); | ||||
| var key = sshpk.parsePrivateKey(keyPriv, 'pem'); | ||||
| 
 | ||||
| var data = 'some data'; | ||||
| 
 | ||||
| /* Sign some data with the key */ | ||||
| var s = key.createSign('sha1'); | ||||
| s.update(data); | ||||
| var signature = s.sign(); | ||||
| 
 | ||||
| /* Now load the public key (could also use just key.toPublic()) */ | ||||
| var keyPub = fs.readFileSync('id_ecdsa.pub'); | ||||
| key = sshpk.parseKey(keyPub, 'ssh'); | ||||
| 
 | ||||
| /* Make a crypto.Verifier with this key */ | ||||
| var v = key.createVerify('sha1'); | ||||
| v.update(data); | ||||
| var valid = v.verify(signature); | ||||
| /* => true! */ | ||||
| ``` | ||||
| 
 | ||||
| Matching fingerprints with keys: | ||||
| 
 | ||||
| ```js | ||||
| var fp = sshpk.parseFingerprint('SHA256:PYC9kPVC6J873CSIbfp0LwYeczP/W4ffObNCuDJ1u5w'); | ||||
| 
 | ||||
| var keys = [sshpk.parseKey(...), sshpk.parseKey(...), ...]; | ||||
| 
 | ||||
| keys.forEach(function (key) { | ||||
| 	if (fp.matches(key)) | ||||
| 		console.log('found it!'); | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| Usage | ||||
| ----- | ||||
| 
 | ||||
| ## Public keys | ||||
| 
 | ||||
| ### `parseKey(data[, format = 'auto'[, options]])` | ||||
| 
 | ||||
| Parses a key from a given data format and returns a new `Key` object. | ||||
| 
 | ||||
| Parameters | ||||
| 
 | ||||
| - `data` -- Either a Buffer or String, containing the key | ||||
| - `format` -- String name of format to use, valid options are: | ||||
|   - `auto`: choose automatically from all below | ||||
|   - `pem`: supports both PKCS#1 and PKCS#8 | ||||
|   - `ssh`: standard OpenSSH format, | ||||
|   - `pkcs1`, `pkcs8`: variants of `pem` | ||||
|   - `rfc4253`: raw OpenSSH wire format | ||||
|   - `openssh`: new post-OpenSSH 6.5 internal format, produced by  | ||||
|                `ssh-keygen -o` | ||||
|   - `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` | ||||
							
								
								
									
										243
									
								
								node_modules/sshpk/bin/sshpk-conv
									
										
									
										generated
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										243
									
								
								node_modules/sshpk/bin/sshpk-conv
									
										
									
										generated
									
									
										vendored
									
									
										Executable file
									
								
							|  | @ -0,0 +1,243 @@ | |||
| #!/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); | ||||
| } | ||||
							
								
								
									
										191
									
								
								node_modules/sshpk/bin/sshpk-sign
									
										
									
										generated
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										191
									
								
								node_modules/sshpk/bin/sshpk-sign
									
										
									
										generated
									
									
										vendored
									
									
										Executable file
									
								
							|  | @ -0,0 +1,191 @@ | |||
| #!/usr/bin/env node | ||||
| // -*- mode: js -*- | ||||
| // vim: set filetype=javascript : | ||||
| // Copyright 2015 Joyent, Inc.  All rights reserved. | ||||
| 
 | ||||
| var dashdash = require('dashdash'); | ||||
| var sshpk = require('../lib/index'); | ||||
| var fs = require('fs'); | ||||
| var path = require('path'); | ||||
| var getPassword = require('getpass').getPass; | ||||
| 
 | ||||
| var options = [ | ||||
| 	{ | ||||
| 		names: ['hash', 'H'], | ||||
| 		type: 'string', | ||||
| 		help: 'Hash algorithm (sha1, sha256, sha384, sha512)' | ||||
| 	}, | ||||
| 	{ | ||||
| 		names: ['verbose', 'v'], | ||||
| 		type: 'bool', | ||||
| 		help: 'Display verbose info about key and hash used' | ||||
| 	}, | ||||
| 	{ | ||||
| 		names: ['identity', 'i'], | ||||
| 		type: 'string', | ||||
| 		help: 'Path to key to use' | ||||
| 	}, | ||||
| 	{ | ||||
| 		names: ['file', 'f'], | ||||
| 		type: 'string', | ||||
| 		help: 'Input filename' | ||||
| 	}, | ||||
| 	{ | ||||
| 		names: ['out', 'o'], | ||||
| 		type: 'string', | ||||
| 		help: 'Output filename' | ||||
| 	}, | ||||
| 	{ | ||||
| 		names: ['format', 't'], | ||||
| 		type: 'string', | ||||
| 		help: 'Signature format (asn1, ssh, raw)' | ||||
| 	}, | ||||
| 	{ | ||||
| 		names: ['binary', 'b'], | ||||
| 		type: 'bool', | ||||
| 		help: 'Output raw binary instead of base64' | ||||
| 	}, | ||||
| 	{ | ||||
| 		names: ['help', 'h'], | ||||
| 		type: 'bool', | ||||
| 		help: 'Shows this help text' | ||||
| 	} | ||||
| ]; | ||||
| 
 | ||||
| var parseOpts = {}; | ||||
| 
 | ||||
| if (require.main === module) { | ||||
| 	var parser = dashdash.createParser({ | ||||
| 		options: options | ||||
| 	}); | ||||
| 
 | ||||
| 	try { | ||||
| 		var opts = parser.parse(process.argv); | ||||
| 	} catch (e) { | ||||
| 		console.error('sshpk-sign: error: %s', e.message); | ||||
| 		process.exit(1); | ||||
| 	} | ||||
| 
 | ||||
| 	if (opts.help || opts._args.length > 1) { | ||||
| 		var help = parser.help({}).trimRight(); | ||||
| 		console.error('sshpk-sign: sign data using an SSH key\n'); | ||||
| 		console.error(help); | ||||
| 		process.exit(1); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!opts.identity) { | ||||
| 		var help = parser.help({}).trimRight(); | ||||
| 		console.error('sshpk-sign: the -i or --identity option ' + | ||||
| 		    'is required\n'); | ||||
| 		console.error(help); | ||||
| 		process.exit(1); | ||||
| 	} | ||||
| 
 | ||||
| 	var keyData = fs.readFileSync(opts.identity); | ||||
| 	parseOpts.filename = opts.identity; | ||||
| 
 | ||||
| 	run(); | ||||
| } | ||||
| 
 | ||||
| function run() { | ||||
| 	var key; | ||||
| 	try { | ||||
| 		key = sshpk.parsePrivateKey(keyData, 'auto', parseOpts); | ||||
| 	} catch (e) { | ||||
| 		if (e.name === 'KeyEncryptedError') { | ||||
| 			getPassword(function (err, pw) { | ||||
| 				parseOpts.passphrase = pw; | ||||
| 				run(); | ||||
| 			}); | ||||
| 			return; | ||||
| 		} | ||||
| 		console.error('sshpk-sign: error loading private key "' + | ||||
| 		    opts.identity + '": ' + e.name + ': ' + e.message); | ||||
| 		process.exit(1); | ||||
| 	} | ||||
| 
 | ||||
| 	var hash = opts.hash || key.defaultHashAlgorithm(); | ||||
| 
 | ||||
| 	var signer; | ||||
| 	try { | ||||
| 		signer = key.createSign(hash); | ||||
| 	} catch (e) { | ||||
| 		console.error('sshpk-sign: error creating signer: ' + | ||||
| 		    e.name + ': ' + e.message); | ||||
| 		process.exit(1); | ||||
| 	} | ||||
| 
 | ||||
| 	if (opts.verbose) { | ||||
| 		console.error('sshpk-sign: using %s-%s with a %d bit key', | ||||
| 		    key.type, hash, key.size); | ||||
| 	} | ||||
| 
 | ||||
| 	var inFile = process.stdin; | ||||
| 	var inFileName = 'stdin'; | ||||
| 
 | ||||
| 	var inFilePath; | ||||
| 	if (opts.file) { | ||||
| 		inFilePath = opts.file; | ||||
| 	} else if (opts._args.length === 1) { | ||||
| 		inFilePath = opts._args[0]; | ||||
| 	} | ||||
| 
 | ||||
| 	if (inFilePath) | ||||
| 		inFileName = path.basename(inFilePath); | ||||
| 
 | ||||
| 	try { | ||||
| 		if (inFilePath) { | ||||
| 			fs.accessSync(inFilePath, fs.R_OK); | ||||
| 			inFile = fs.createReadStream(inFilePath); | ||||
| 		} | ||||
| 	} catch (e) { | ||||
| 		console.error('sshpk-sign: error opening input file' + | ||||
| 		     ': ' + e.name + ': ' + e.message); | ||||
| 		process.exit(1); | ||||
| 	} | ||||
| 
 | ||||
| 	var outFile = process.stdout; | ||||
| 
 | ||||
| 	try { | ||||
| 		if (opts.out && !opts.identify) { | ||||
| 			fs.accessSync(path.dirname(opts.out), fs.W_OK); | ||||
| 			outFile = fs.createWriteStream(opts.out); | ||||
| 		} | ||||
| 	} catch (e) { | ||||
| 		console.error('sshpk-sign: error opening output file' + | ||||
| 		    ': ' + e.name + ': ' + e.message); | ||||
| 		process.exit(1); | ||||
| 	} | ||||
| 
 | ||||
| 	inFile.pipe(signer); | ||||
| 	inFile.on('end', function () { | ||||
| 		var sig; | ||||
| 		try { | ||||
| 			sig = signer.sign(); | ||||
| 		} catch (e) { | ||||
| 			console.error('sshpk-sign: error signing data: ' + | ||||
| 			    e.name + ': ' + e.message); | ||||
| 			process.exit(1); | ||||
| 		} | ||||
| 
 | ||||
| 		var fmt = opts.format || 'asn1'; | ||||
| 		var output; | ||||
| 		try { | ||||
| 			output = sig.toBuffer(fmt); | ||||
| 			if (!opts.binary) | ||||
| 				output = output.toString('base64'); | ||||
| 		} catch (e) { | ||||
| 			console.error('sshpk-sign: error converting signature' + | ||||
| 			    ' to ' + fmt + ' format: ' + e.name + ': ' + | ||||
| 			    e.message); | ||||
| 			process.exit(1); | ||||
| 		} | ||||
| 
 | ||||
| 		outFile.write(output); | ||||
| 		if (!opts.binary) | ||||
| 			outFile.write('\n'); | ||||
| 		outFile.once('drain', function () { | ||||
| 			process.exit(0); | ||||
| 		}); | ||||
| 	}); | ||||
| } | ||||
							
								
								
									
										167
									
								
								node_modules/sshpk/bin/sshpk-verify
									
										
									
										generated
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										167
									
								
								node_modules/sshpk/bin/sshpk-verify
									
										
									
										generated
									
									
										vendored
									
									
										Executable file
									
								
							|  | @ -0,0 +1,167 @@ | |||
| #!/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); | ||||
| 	}); | ||||
| } | ||||
							
								
								
									
										168
									
								
								node_modules/sshpk/lib/algs.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								node_modules/sshpk/lib/algs.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,168 @@ | |||
| // Copyright 2015 Joyent, Inc.
 | ||||
| 
 | ||||
| var 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 | ||||
| }; | ||||
							
								
								
									
										410
									
								
								node_modules/sshpk/lib/certificate.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										410
									
								
								node_modules/sshpk/lib/certificate.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,410 @@ | |||
| // 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]); | ||||
| }; | ||||
							
								
								
									
										397
									
								
								node_modules/sshpk/lib/dhe.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										397
									
								
								node_modules/sshpk/lib/dhe.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,397 @@ | |||
| // 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); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										92
									
								
								node_modules/sshpk/lib/ed-compat.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								node_modules/sshpk/lib/ed-compat.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,92 @@ | |||
| // 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); | ||||
| }; | ||||
							
								
								
									
										84
									
								
								node_modules/sshpk/lib/errors.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								node_modules/sshpk/lib/errors.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,84 @@ | |||
| // Copyright 2015 Joyent, Inc.
 | ||||
| 
 | ||||
| var assert = require('assert-plus'); | ||||
| var util = require('util'); | ||||
| 
 | ||||
| function FingerprintFormatError(fp, format) { | ||||
| 	if (Error.captureStackTrace) | ||||
| 		Error.captureStackTrace(this, FingerprintFormatError); | ||||
| 	this.name = 'FingerprintFormatError'; | ||||
| 	this.fingerprint = fp; | ||||
| 	this.format = format; | ||||
| 	this.message = 'Fingerprint format is not supported, or is invalid: '; | ||||
| 	if (fp !== undefined) | ||||
| 		this.message += ' fingerprint = ' + fp; | ||||
| 	if (format !== undefined) | ||||
| 		this.message += ' format = ' + format; | ||||
| } | ||||
| util.inherits(FingerprintFormatError, Error); | ||||
| 
 | ||||
| function InvalidAlgorithmError(alg) { | ||||
| 	if (Error.captureStackTrace) | ||||
| 		Error.captureStackTrace(this, InvalidAlgorithmError); | ||||
| 	this.name = 'InvalidAlgorithmError'; | ||||
| 	this.algorithm = alg; | ||||
| 	this.message = 'Algorithm "' + alg + '" is not supported'; | ||||
| } | ||||
| util.inherits(InvalidAlgorithmError, Error); | ||||
| 
 | ||||
| function KeyParseError(name, format, innerErr) { | ||||
| 	if (Error.captureStackTrace) | ||||
| 		Error.captureStackTrace(this, KeyParseError); | ||||
| 	this.name = 'KeyParseError'; | ||||
| 	this.format = format; | ||||
| 	this.keyName = name; | ||||
| 	this.innerErr = innerErr; | ||||
| 	this.message = 'Failed to parse ' + name + ' as a valid ' + format + | ||||
| 	    ' format key: ' + innerErr.message; | ||||
| } | ||||
| util.inherits(KeyParseError, Error); | ||||
| 
 | ||||
| function SignatureParseError(type, format, innerErr) { | ||||
| 	if (Error.captureStackTrace) | ||||
| 		Error.captureStackTrace(this, SignatureParseError); | ||||
| 	this.name = 'SignatureParseError'; | ||||
| 	this.type = type; | ||||
| 	this.format = format; | ||||
| 	this.innerErr = innerErr; | ||||
| 	this.message = 'Failed to parse the given data as a ' + type + | ||||
| 	    ' signature in ' + format + ' format: ' + innerErr.message; | ||||
| } | ||||
| util.inherits(SignatureParseError, Error); | ||||
| 
 | ||||
| function CertificateParseError(name, format, innerErr) { | ||||
| 	if (Error.captureStackTrace) | ||||
| 		Error.captureStackTrace(this, CertificateParseError); | ||||
| 	this.name = 'CertificateParseError'; | ||||
| 	this.format = format; | ||||
| 	this.certName = name; | ||||
| 	this.innerErr = innerErr; | ||||
| 	this.message = 'Failed to parse ' + name + ' as a valid ' + format + | ||||
| 	    ' format certificate: ' + innerErr.message; | ||||
| } | ||||
| util.inherits(CertificateParseError, Error); | ||||
| 
 | ||||
| function KeyEncryptedError(name, format) { | ||||
| 	if (Error.captureStackTrace) | ||||
| 		Error.captureStackTrace(this, KeyEncryptedError); | ||||
| 	this.name = 'KeyEncryptedError'; | ||||
| 	this.format = format; | ||||
| 	this.keyName = name; | ||||
| 	this.message = 'The ' + format + ' format key ' + name + ' is ' + | ||||
| 	    'encrypted (password-protected), and no passphrase was ' + | ||||
| 	    'provided in `options`'; | ||||
| } | ||||
| util.inherits(KeyEncryptedError, Error); | ||||
| 
 | ||||
| module.exports = { | ||||
| 	FingerprintFormatError: FingerprintFormatError, | ||||
| 	InvalidAlgorithmError: InvalidAlgorithmError, | ||||
| 	KeyParseError: KeyParseError, | ||||
| 	SignatureParseError: SignatureParseError, | ||||
| 	KeyEncryptedError: KeyEncryptedError, | ||||
| 	CertificateParseError: CertificateParseError | ||||
| }; | ||||
							
								
								
									
										220
									
								
								node_modules/sshpk/lib/fingerprint.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								node_modules/sshpk/lib/fingerprint.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,220 @@ | |||
| // 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]); | ||||
| }; | ||||
							
								
								
									
										124
									
								
								node_modules/sshpk/lib/formats/auto.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								node_modules/sshpk/lib/formats/auto.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,124 @@ | |||
| // 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')); | ||||
| } | ||||
							
								
								
									
										287
									
								
								node_modules/sshpk/lib/formats/dnssec.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										287
									
								
								node_modules/sshpk/lib/formats/dnssec.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,287 @@ | |||
| // 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')); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										352
									
								
								node_modules/sshpk/lib/formats/openssh-cert.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										352
									
								
								node_modules/sshpk/lib/formats/openssh-cert.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,352 @@ | |||
| // 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)); | ||||
| } | ||||
							
								
								
									
										290
									
								
								node_modules/sshpk/lib/formats/pem.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								node_modules/sshpk/lib/formats/pem.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,290 @@ | |||
| // 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)); | ||||
| } | ||||
							
								
								
									
										373
									
								
								node_modules/sshpk/lib/formats/pkcs1.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										373
									
								
								node_modules/sshpk/lib/formats/pkcs1.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,373 @@ | |||
| // 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')); | ||||
| } | ||||
							
								
								
									
										631
									
								
								node_modules/sshpk/lib/formats/pkcs8.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										631
									
								
								node_modules/sshpk/lib/formats/pkcs8.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,631 @@ | |||
| // 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(); | ||||
| } | ||||
							
								
								
									
										194
									
								
								node_modules/sshpk/lib/formats/putty.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								node_modules/sshpk/lib/formats/putty.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,194 @@ | |||
| // 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 SSHBuffer = require('../ssh-buffer'); | ||||
| var crypto = require('crypto'); | ||||
| var PrivateKey = require('../private-key'); | ||||
| 
 | ||||
| var errors = require('../errors'); | ||||
| 
 | ||||
| // https://tartarus.org/~simon/putty-prerel-snapshots/htmldoc/AppendixC.html
 | ||||
| function read(buf, options) { | ||||
| 	var lines = buf.toString('ascii').split(/[\r\n]+/); | ||||
| 	var found = false; | ||||
| 	var parts; | ||||
| 	var si = 0; | ||||
| 	var formatVersion; | ||||
| 	while (si < lines.length) { | ||||
| 		parts = splitHeader(lines[si++]); | ||||
| 		if (parts) { | ||||
| 			formatVersion = { | ||||
| 				'putty-user-key-file-2': 2, | ||||
| 				'putty-user-key-file-3': 3 | ||||
| 			}[parts[0].toLowerCase()]; | ||||
| 			if (formatVersion) { | ||||
| 				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'); | ||||
| 	var encryption = parts[1]; | ||||
| 
 | ||||
| 	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')); | ||||
| 	} | ||||
| 
 | ||||
| 	si += publicLines; | ||||
| 	if (lines[si]) { | ||||
| 		parts = splitHeader(lines[si++]); | ||||
| 		assert.equal(parts[0].toLowerCase(), 'private-lines'); | ||||
| 		var privateLines = parseInt(parts[1], 10); | ||||
| 		if (!isFinite(privateLines) || privateLines < 0 || | ||||
| 		    privateLines > lines.length) { | ||||
| 			throw (new Error('Invalid private-lines count')); | ||||
| 		} | ||||
| 
 | ||||
| 		var privateBuf = Buffer.from( | ||||
| 			lines.slice(si, si + privateLines).join(''), 'base64'); | ||||
| 
 | ||||
| 		if (encryption !== 'none' && formatVersion === 3) { | ||||
| 			throw new Error('Encrypted keys arenot supported for' + | ||||
| 			' PuTTY format version 3'); | ||||
| 		} | ||||
| 
 | ||||
| 		if (encryption === 'aes256-cbc') { | ||||
| 			if (!options.passphrase) { | ||||
| 				throw (new errors.KeyEncryptedError( | ||||
| 					options.filename, 'PEM')); | ||||
| 			} | ||||
| 
 | ||||
| 			var iv = Buffer.alloc(16, 0); | ||||
| 			var decipher = crypto.createDecipheriv( | ||||
| 				'aes-256-cbc', | ||||
| 				derivePPK2EncryptionKey(options.passphrase), | ||||
| 				iv); | ||||
| 			decipher.setAutoPadding(false); | ||||
| 			privateBuf = Buffer.concat([ | ||||
| 				decipher.update(privateBuf), decipher.final()]); | ||||
| 		} | ||||
| 
 | ||||
| 		key = new PrivateKey(key); | ||||
| 		if (key.type !== keyType) { | ||||
| 			throw (new Error('Outer key algorithm mismatch')); | ||||
| 		} | ||||
| 
 | ||||
| 		var sshbuf = new SSHBuffer({buffer: privateBuf}); | ||||
| 		var privateKeyParts; | ||||
| 		if (alg === 'ssh-dss') { | ||||
| 			privateKeyParts = [ { | ||||
| 				name: 'x', | ||||
| 				data: sshbuf.readBuffer() | ||||
| 			}]; | ||||
| 		} else if (alg === 'ssh-rsa') { | ||||
| 			privateKeyParts = [ | ||||
| 				{ name: 'd', data: sshbuf.readBuffer() }, | ||||
| 				{ name: 'p', data: sshbuf.readBuffer() }, | ||||
| 				{ name: 'q', data: sshbuf.readBuffer() }, | ||||
| 				{ name: 'iqmp', data: sshbuf.readBuffer() } | ||||
| 			]; | ||||
| 		} else if (alg.match(/^ecdsa-sha2-nistp/)) { | ||||
| 			privateKeyParts = [ { | ||||
| 				name: 'd', data: sshbuf.readBuffer() | ||||
| 			} ]; | ||||
| 		} else if (alg === 'ssh-ed25519') { | ||||
| 			privateKeyParts = [ { | ||||
| 				name: 'k', data: sshbuf.readBuffer() | ||||
| 			} ]; | ||||
| 		} else { | ||||
| 			throw new Error('Unsupported PPK key type: ' + alg); | ||||
| 		} | ||||
| 
 | ||||
| 		key = new PrivateKey({ | ||||
| 			type: key.type, | ||||
| 			parts: key.parts.concat(privateKeyParts) | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	key.comment = comment; | ||||
| 	return (key); | ||||
| } | ||||
| 
 | ||||
| function derivePPK2EncryptionKey(passphrase) { | ||||
| 	var hash1 = crypto.createHash('sha1').update(Buffer.concat([ | ||||
| 		Buffer.from([0, 0, 0, 0]), | ||||
| 		Buffer.from(passphrase) | ||||
| 	])).digest(); | ||||
| 	var hash2 = crypto.createHash('sha1').update(Buffer.concat([ | ||||
| 		Buffer.from([0, 0, 0, 1]), | ||||
| 		Buffer.from(passphrase) | ||||
| 	])).digest(); | ||||
| 	return (Buffer.concat([hash1, hash2]).slice(0, 32)); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| } | ||||
							
								
								
									
										166
									
								
								node_modules/sshpk/lib/formats/rfc4253.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								node_modules/sshpk/lib/formats/rfc4253.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,166 @@ | |||
| // 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()); | ||||
| } | ||||
							
								
								
									
										262
									
								
								node_modules/sshpk/lib/formats/ssh-private.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								node_modules/sshpk/lib/formats/ssh-private.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,262 @@ | |||
| // 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)); | ||||
| } | ||||
							
								
								
									
										115
									
								
								node_modules/sshpk/lib/formats/ssh.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								node_modules/sshpk/lib/formats/ssh.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,115 @@ | |||
| // 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(' '))); | ||||
| } | ||||
							
								
								
									
										88
									
								
								node_modules/sshpk/lib/formats/x509-pem.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								node_modules/sshpk/lib/formats/x509-pem.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,88 @@ | |||
| // 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)); | ||||
| } | ||||
							
								
								
									
										752
									
								
								node_modules/sshpk/lib/formats/x509.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										752
									
								
								node_modules/sshpk/lib/formats/x509.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,752 @@ | |||
| // 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); | ||||
| } | ||||
							
								
								
									
										373
									
								
								node_modules/sshpk/lib/identity.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										373
									
								
								node_modules/sshpk/lib/identity.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,373 @@ | |||
| // 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]); | ||||
| }; | ||||
							
								
								
									
										40
									
								
								node_modules/sshpk/lib/index.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								node_modules/sshpk/lib/index.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | |||
| // 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 | ||||
| }; | ||||
							
								
								
									
										294
									
								
								node_modules/sshpk/lib/key.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										294
									
								
								node_modules/sshpk/lib/key.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,294 @@ | |||
| // 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]); | ||||
| }; | ||||
							
								
								
									
										247
									
								
								node_modules/sshpk/lib/private-key.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										247
									
								
								node_modules/sshpk/lib/private-key.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,247 @@ | |||
| // 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'); | ||||
| formats['putty'] = require('./formats/putty'); | ||||
| 
 | ||||
| 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]); | ||||
| }; | ||||
							
								
								
									
										314
									
								
								node_modules/sshpk/lib/signature.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								node_modules/sshpk/lib/signature.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,314 @@ | |||
| // 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]); | ||||
| }; | ||||
							
								
								
									
										149
									
								
								node_modules/sshpk/lib/ssh-buffer.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								node_modules/sshpk/lib/ssh-buffer.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,149 @@ | |||
| // 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; | ||||
| }; | ||||
							
								
								
									
										404
									
								
								node_modules/sshpk/lib/utils.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										404
									
								
								node_modules/sshpk/lib/utils.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,404 @@ | |||
| // 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); | ||||
| } | ||||
							
								
								
									
										135
									
								
								node_modules/sshpk/man/man1/sshpk-conv.1
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								node_modules/sshpk/man/man1/sshpk-conv.1
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,135 @@ | |||
| .TH sshpk\-conv 1 "Jan 2016" sshpk "sshpk Commands" | ||||
| .SH NAME | ||||
| .PP | ||||
| sshpk\-conv \- convert between key formats | ||||
| .SH SYNOPSYS | ||||
| .PP | ||||
| \fB\fCsshpk\-conv\fR \-t FORMAT [FILENAME] [OPTIONS...] | ||||
| .PP | ||||
| \fB\fCsshpk\-conv\fR \-i [FILENAME] [OPTIONS...] | ||||
| .SH DESCRIPTION | ||||
| .PP | ||||
| Reads in a public or private key and converts it between different formats, | ||||
| particularly formats used in the SSH protocol and the well\-known PEM PKCS#1/7 | ||||
| formats. | ||||
| .PP | ||||
| In the second form, with the \fB\fC\-i\fR option given, identifies a key and prints to  | ||||
| stderr information about its nature, size and fingerprint. | ||||
| .SH EXAMPLES | ||||
| .PP | ||||
| Assume the following SSH\-format public key in \fB\fCid_ecdsa.pub\fR: | ||||
| .PP | ||||
| .RS | ||||
| .nf | ||||
| ecdsa\-sha2\-nistp256 AAAAE2VjZHNhLXNoYTI...9M/4c4= user@host | ||||
| .fi | ||||
| .RE | ||||
| .PP | ||||
| Identify it with \fB\fC\-i\fR: | ||||
| .PP | ||||
| .RS | ||||
| .nf | ||||
| $ sshpk\-conv \-i id_ecdsa.pub | ||||
| id_ecdsa: a 256 bit ECDSA public key | ||||
| ECDSA curve: nistp256 | ||||
| Comment: user@host | ||||
| Fingerprint: | ||||
|   SHA256:vCNX7eUkdvqqW0m4PoxQAZRv+CM4P4fS8+CbliAvS4k | ||||
|   81:ad:d5:57:e5:6f:7d:a2:93:79:56:af:d7:c0:38:51 | ||||
| .fi | ||||
| .RE | ||||
| .PP | ||||
| Convert it to \fB\fCpkcs8\fR format, for use with e.g. OpenSSL: | ||||
| .PP | ||||
| .RS | ||||
| .nf | ||||
| $ sshpk\-conv \-t pkcs8 id_ecdsa | ||||
| \-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\- | ||||
| MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAsA4R6N6AS3gzaPBeLjG2ObSgUsR | ||||
| zOt+kWJoijLnw3ZMYUKmAx+lD0I5XUxdrPcs1vH5f3cn9TvRvO9L0z/hzg== | ||||
| \-\-\-\-\-END PUBLIC KEY\-\-\-\-\- | ||||
| .fi | ||||
| .RE | ||||
| .PP | ||||
| Retrieve the public half of a private key: | ||||
| .PP | ||||
| .RS | ||||
| .nf | ||||
| $ openssl genrsa 2048 | sshpk\-conv \-t ssh \-c foo@bar | ||||
| ssh\-rsa AAAAB3NzaC1yc2EAAA...koK7 foo@bar | ||||
| .fi | ||||
| .RE | ||||
| .PP | ||||
| Convert a private key to PKCS#1 (OpenSSL) format from a new\-style OpenSSH key | ||||
| format (the \fB\fCssh\-keygen \-o\fR format): | ||||
| .PP | ||||
| .RS | ||||
| .nf | ||||
| $ ssh\-keygen \-o \-f foobar | ||||
| \&... | ||||
| $ sshpk\-conv \-p \-t pkcs1 foobar | ||||
| \-\-\-\-\-BEGIN RSA PRIVATE KEY\-\-\-\-\- | ||||
| MIIDpAIBAAKCAQEA6T/GYJndb1TRH3+NL.... | ||||
| \-\-\-\-\-END RSA PRIVATE KEY\-\-\-\-\- | ||||
| .fi | ||||
| .RE | ||||
| .SH OPTIONS | ||||
| .TP | ||||
| \fB\fC\-i, \-\-identify\fR | ||||
| Instead of converting the key, output identifying information about it to  | ||||
| stderr, including its type, size and fingerprints. | ||||
| .TP | ||||
| \fB\fC\-p, \-\-private\fR | ||||
| Treat the key as a private key instead of a public key (the default). If you | ||||
| supply \fB\fCsshpk\-conv\fR with a private key and do not give this option, it will | ||||
| extract only the public half of the key from it and work with that. | ||||
| .TP | ||||
| \fB\fC\-f PATH, \-\-file=PATH\fR | ||||
| Input file to take the key from instead of stdin. If a filename is supplied | ||||
| as a positional argument, it is equivalent to using this option. | ||||
| .TP | ||||
| \fB\fC\-o PATH, \-\-out=PATH\fR | ||||
| Output file name to use instead of stdout. | ||||
| .PP | ||||
| \fB\fC\-T FORMAT, \-\-informat=FORMAT\fR | ||||
| .TP | ||||
| \fB\fC\-t FORMAT, \-\-outformat=FORMAT\fR | ||||
| Selects the input and output formats to be used (see FORMATS, below). | ||||
| .TP | ||||
| \fB\fC\-c TEXT, \-\-comment=TEXT\fR | ||||
| Sets the key comment for the output file, if supported. | ||||
| .SH FORMATS | ||||
| .PP | ||||
| Currently supported formats: | ||||
| .TP | ||||
| \fB\fCpem, pkcs1\fR | ||||
| The standard PEM format used by older OpenSSH and most TLS libraries such as | ||||
| OpenSSL. The classic \fB\fCid_rsa\fR file is usually in this format. It is an ASN.1 | ||||
| encoded structure, base64\-encoded and placed between PEM headers. | ||||
| .TP | ||||
| \fB\fCssh\fR | ||||
| The SSH public key text format (the format of an \fB\fCid_rsa.pub\fR file). A single | ||||
| line, containing 3 space separated parts: the key type, key body and optional | ||||
| key comment. | ||||
| .TP | ||||
| \fB\fCpkcs8\fR | ||||
| A newer PEM format, usually used only for public keys by TLS libraries such | ||||
| as OpenSSL. The ASN.1 structure is more generic than that of \fB\fCpkcs1\fR\&. | ||||
| .TP | ||||
| \fB\fCopenssh\fR | ||||
| The new \fB\fCssh\-keygen \-o\fR format from OpenSSH. This can be mistaken for a PEM | ||||
| encoding but is actually an OpenSSH internal format. | ||||
| .TP | ||||
| \fB\fCrfc4253\fR | ||||
| The internal binary format of keys when sent over the wire in the SSH | ||||
| protocol. This is also the format that the \fB\fCssh\-agent\fR uses in its protocol. | ||||
| .SH SEE ALSO | ||||
| .PP | ||||
| .BR ssh-keygen (1),  | ||||
| .BR openssl (1) | ||||
| .SH BUGS | ||||
| .PP | ||||
| Encrypted (password\-protected) keys are not supported. | ||||
| .PP | ||||
| Report bugs at Github | ||||
| \[la]https://github.com/arekinath/node-sshpk/issues\[ra] | ||||
							
								
								
									
										81
									
								
								node_modules/sshpk/man/man1/sshpk-sign.1
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								node_modules/sshpk/man/man1/sshpk-sign.1
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,81 @@ | |||
| .TH sshpk\-sign 1 "Jan 2016" sshpk "sshpk Commands" | ||||
| .SH NAME | ||||
| .PP | ||||
| sshpk\-sign \- sign data using an SSH key | ||||
| .SH SYNOPSYS | ||||
| .PP | ||||
| \fB\fCsshpk\-sign\fR \-i KEYPATH [OPTION...] | ||||
| .SH DESCRIPTION | ||||
| .PP | ||||
| Takes in arbitrary bytes, and signs them using an SSH private key. The key can | ||||
| be of any type or format supported by the \fB\fCsshpk\fR library, including the | ||||
| standard OpenSSH formats, as well as PEM PKCS#1 and PKCS#8. | ||||
| .PP | ||||
| The signature is printed out in Base64 encoding, unless the \fB\fC\-\-binary\fR or \fB\fC\-b\fR | ||||
| option is given. | ||||
| .SH EXAMPLES | ||||
| .PP | ||||
| Signing with default settings: | ||||
| .PP | ||||
| .RS | ||||
| .nf | ||||
| $ printf 'foo' | sshpk\-sign \-i ~/.ssh/id_ecdsa | ||||
| MEUCIAMdLS/vXrrtWFepwe... | ||||
| .fi | ||||
| .RE | ||||
| .PP | ||||
| Signing in SSH (RFC 4253) format (rather than the default ASN.1): | ||||
| .PP | ||||
| .RS | ||||
| .nf | ||||
| $ printf 'foo' | sshpk\-sign \-i ~/.ssh/id_ecdsa \-t ssh | ||||
| AAAAFGVjZHNhLXNoYTIt... | ||||
| .fi | ||||
| .RE | ||||
| .PP | ||||
| Saving the binary signature to a file: | ||||
| .PP | ||||
| .RS | ||||
| .nf | ||||
| $ printf 'foo' | sshpk\-sign \-i ~/.ssh/id_ecdsa \\ | ||||
|                             \-o signature.bin \-b | ||||
| $ cat signature.bin | base64 | ||||
| MEUCIAMdLS/vXrrtWFepwe... | ||||
| .fi | ||||
| .RE | ||||
| .SH OPTIONS | ||||
| .TP | ||||
| \fB\fC\-v, \-\-verbose\fR | ||||
| Print extra information about the key and signature to stderr when signing. | ||||
| .TP | ||||
| \fB\fC\-b, \-\-binary\fR | ||||
| Don't base64\-encode the signature before outputting it. | ||||
| .TP | ||||
| \fB\fC\-i KEY, \-\-identity=KEY\fR | ||||
| Select the key to be used for signing. \fB\fCKEY\fR must be a relative or absolute | ||||
| filesystem path to the key file. Any format supported by the \fB\fCsshpk\fR library | ||||
| is supported, including OpenSSH formats and standard PEM PKCS. | ||||
| .TP | ||||
| \fB\fC\-f PATH, \-\-file=PATH\fR | ||||
| Input file to sign instead of stdin. | ||||
| .TP | ||||
| \fB\fC\-o PATH, \-\-out=PATH\fR | ||||
| Output file to save signature in instead of stdout. | ||||
| .TP | ||||
| \fB\fC\-H HASH, \-\-hash=HASH\fR | ||||
| Set the hash algorithm to be used for signing. This should be one of \fB\fCsha1\fR, | ||||
| \fB\fCsha256\fR or \fB\fCsha512\fR\&. Some key types may place restrictions on which hash | ||||
| algorithms may be used (e.g. ED25519 keys can only use SHA\-512). | ||||
| .TP | ||||
| \fB\fC\-t FORMAT, \-\-format=FORMAT\fR | ||||
| Choose the signature format to use, from \fB\fCasn1\fR, \fB\fCssh\fR or \fB\fCraw\fR (only for | ||||
| ED25519 signatures). The \fB\fCasn1\fR format is the default, as it is the format | ||||
| used with TLS and typically the standard in most non\-SSH libraries (e.g. | ||||
| OpenSSL). The \fB\fCssh\fR format is used in the SSH protocol and by the ssh\-agent. | ||||
| .SH SEE ALSO | ||||
| .PP | ||||
| .BR sshpk-verify (1) | ||||
| .SH BUGS | ||||
| .PP | ||||
| Report bugs at Github | ||||
| \[la]https://github.com/arekinath/node-sshpk/issues\[ra] | ||||
							
								
								
									
										68
									
								
								node_modules/sshpk/man/man1/sshpk-verify.1
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								node_modules/sshpk/man/man1/sshpk-verify.1
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,68 @@ | |||
| .TH sshpk\-verify 1 "Jan 2016" sshpk "sshpk Commands" | ||||
| .SH NAME | ||||
| .PP | ||||
| sshpk\-verify \- verify a signature on data using an SSH key | ||||
| .SH SYNOPSYS | ||||
| .PP | ||||
| \fB\fCsshpk\-verify\fR \-i KEYPATH \-s SIGNATURE [OPTION...] | ||||
| .SH DESCRIPTION | ||||
| .PP | ||||
| Takes in arbitrary bytes and a Base64\-encoded signature, and verifies that the | ||||
| signature was produced by the private half of the given SSH public key. | ||||
| .SH EXAMPLES | ||||
| .PP | ||||
| .RS | ||||
| .nf | ||||
| $ printf 'foo' | sshpk\-verify \-i ~/.ssh/id_ecdsa \-s MEUCIQCYp... | ||||
| OK | ||||
| $ printf 'foo' | sshpk\-verify \-i ~/.ssh/id_ecdsa \-s GARBAGE... | ||||
| NOT OK | ||||
| .fi | ||||
| .RE | ||||
| .SH EXIT STATUS | ||||
| .TP | ||||
| \fB\fC0\fR | ||||
| Signature validates and matches the key. | ||||
| .TP | ||||
| \fB\fC1\fR | ||||
| Signature is parseable and the correct length but does not match the key or | ||||
| otherwise is invalid. | ||||
| .TP | ||||
| \fB\fC2\fR | ||||
| The signature or key could not be parsed. | ||||
| .TP | ||||
| \fB\fC3\fR | ||||
| Invalid commandline options were supplied. | ||||
| .SH OPTIONS | ||||
| .TP | ||||
| \fB\fC\-v, \-\-verbose\fR | ||||
| Print extra information about the key and signature to stderr when verifying. | ||||
| .TP | ||||
| \fB\fC\-i KEY, \-\-identity=KEY\fR | ||||
| Select the key to be used for verification. \fB\fCKEY\fR must be a relative or | ||||
| absolute filesystem path to the key file. Any format supported by the \fB\fCsshpk\fR | ||||
| library is supported, including OpenSSH formats and standard PEM PKCS. | ||||
| .TP | ||||
| \fB\fC\-s BASE64, \-\-signature=BASE64\fR | ||||
| Supplies the base64\-encoded signature to be verified. | ||||
| .TP | ||||
| \fB\fC\-f PATH, \-\-file=PATH\fR | ||||
| Input file to verify instead of stdin. | ||||
| .TP | ||||
| \fB\fC\-H HASH, \-\-hash=HASH\fR | ||||
| Set the hash algorithm to be used for signing. This should be one of \fB\fCsha1\fR, | ||||
| \fB\fCsha256\fR or \fB\fCsha512\fR\&. Some key types may place restrictions on which hash | ||||
| algorithms may be used (e.g. ED25519 keys can only use SHA\-512). | ||||
| .TP | ||||
| \fB\fC\-t FORMAT, \-\-format=FORMAT\fR | ||||
| Choose the signature format to use, from \fB\fCasn1\fR, \fB\fCssh\fR or \fB\fCraw\fR (only for | ||||
| ED25519 signatures). The \fB\fCasn1\fR format is the default, as it is the format | ||||
| used with TLS and typically the standard in most non\-SSH libraries (e.g. | ||||
| OpenSSL). The \fB\fCssh\fR format is used in the SSH protocol and by the ssh\-agent. | ||||
| .SH SEE ALSO | ||||
| .PP | ||||
| .BR sshpk-sign (1) | ||||
| .SH BUGS | ||||
| .PP | ||||
| Report bugs at Github | ||||
| \[la]https://github.com/arekinath/node-sshpk/issues\[ra] | ||||
							
								
								
									
										4
									
								
								node_modules/sshpk/node_modules/tweetnacl/.npmignore
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								node_modules/sshpk/node_modules/tweetnacl/.npmignore
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | |||
| .eslintrc | ||||
| .travis.yml | ||||
| bower.json | ||||
| test | ||||
							
								
								
									
										28
									
								
								node_modules/sshpk/node_modules/tweetnacl/AUTHORS.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								node_modules/sshpk/node_modules/tweetnacl/AUTHORS.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| List of TweetNaCl.js authors | ||||
| ============================ | ||||
| 
 | ||||
|     Alphabetical order by first name. | ||||
|     Format: Name (GitHub username or URL) | ||||
| 
 | ||||
| * AndSDev (@AndSDev) | ||||
| * Devi Mandiri (@devi) | ||||
| * Dmitry Chestnykh (@dchest) | ||||
| 
 | ||||
| List of authors of third-party public domain code from which TweetNaCl.js code was derived | ||||
| ========================================================================================== | ||||
| 
 | ||||
| [TweetNaCl](http://tweetnacl.cr.yp.to/) | ||||
| -------------------------------------- | ||||
| 
 | ||||
| * Bernard van Gastel | ||||
| * Daniel J. Bernstein <http://cr.yp.to/djb.html> | ||||
| * Peter Schwabe <http://www.cryptojedi.org/users/peter/> | ||||
| * Sjaak Smetsers <http://www.cs.ru.nl/~sjakie/> | ||||
| * Tanja Lange <http://hyperelliptic.org/tanja> | ||||
| * Wesley Janssen | ||||
| 
 | ||||
| 
 | ||||
| [Poly1305-donna](https://github.com/floodyberry/poly1305-donna) | ||||
| -------------------------------------------------------------- | ||||
| 
 | ||||
| * Andrew Moon (@floodyberry) | ||||
							
								
								
									
										221
									
								
								node_modules/sshpk/node_modules/tweetnacl/CHANGELOG.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								node_modules/sshpk/node_modules/tweetnacl/CHANGELOG.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,221 @@ | |||
| TweetNaCl.js Changelog | ||||
| ====================== | ||||
| 
 | ||||
| 
 | ||||
| v0.14.5 | ||||
| ------- | ||||
| 
 | ||||
| * Fixed incomplete return types in TypeScript typings. | ||||
| * Replaced COPYING.txt with LICENSE file, which now has public domain dedication | ||||
|   text from The Unlicense. License fields in package.json and bower.json have | ||||
|   been set to "Unlicense". The project was and will be in the public domain -- | ||||
|   this change just makes it easier for automated tools to know about this fact by | ||||
|   using the widely recognized and SPDX-compatible template for public domain | ||||
|   dedication. | ||||
| 
 | ||||
| 
 | ||||
| v0.14.4 | ||||
| ------- | ||||
| 
 | ||||
| * Added TypeScript type definitions (contributed by @AndSDev). | ||||
| * Improved benchmarking code. | ||||
| 
 | ||||
| 
 | ||||
| v0.14.3 | ||||
| ------- | ||||
| 
 | ||||
| Fixed a bug in the fast version of Poly1305 and brought it back. | ||||
| 
 | ||||
| Thanks to @floodyberry for promptly responding and fixing the original C code: | ||||
| 
 | ||||
| > "The issue was not properly detecting if st->h was >= 2^130 - 5, coupled with | ||||
| > [testing mistake] not catching the failure. The chance of the bug affecting | ||||
| > anything in the real world is essentially zero luckily, but it's good to have | ||||
| > it fixed." | ||||
| 
 | ||||
| https://github.com/floodyberry/poly1305-donna/issues/2#issuecomment-202698577 | ||||
| 
 | ||||
| 
 | ||||
| v0.14.2 | ||||
| ------- | ||||
| 
 | ||||
| Switched Poly1305 fast version back to original (slow) version due to a bug. | ||||
| 
 | ||||
| 
 | ||||
| v0.14.1 | ||||
| ------- | ||||
| 
 | ||||
| No code changes, just tweaked packaging and added COPYING.txt. | ||||
| 
 | ||||
| 
 | ||||
| v0.14.0 | ||||
| ------- | ||||
| 
 | ||||
| * **Breaking change!** All functions from `nacl.util` have been removed. These | ||||
|   functions are no longer available: | ||||
| 
 | ||||
|       nacl.util.decodeUTF8 | ||||
|       nacl.util.encodeUTF8 | ||||
|       nacl.util.decodeBase64 | ||||
|       nacl.util.encodeBase64 | ||||
| 
 | ||||
|   If want to continue using them, you can include | ||||
|   <https://github.com/dchest/tweetnacl-util-js> package: | ||||
| 
 | ||||
|       <script src="nacl.min.js"></script> | ||||
|       <script src="nacl-util.min.js"></script> | ||||
| 
 | ||||
|   or | ||||
| 
 | ||||
|       var nacl = require('tweetnacl'); | ||||
|       nacl.util = require('tweetnacl-util'); | ||||
| 
 | ||||
|   However it is recommended to use better packages that have wider | ||||
|   compatibility and better performance. Functions from `nacl.util` were never | ||||
|   intended to be robust solution for string conversion and were included for | ||||
|   convenience: cryptography library is not the right place for them. | ||||
| 
 | ||||
|   Currently calling these functions will throw error pointing to | ||||
|   `tweetnacl-util-js` (in the next version this error message will be removed). | ||||
| 
 | ||||
| * Improved detection of available random number generators, making it possible | ||||
|   to use `nacl.randomBytes` and related functions in Web Workers without | ||||
|   changes. | ||||
| 
 | ||||
| * Changes to testing (see README). | ||||
| 
 | ||||
| 
 | ||||
| v0.13.3 | ||||
| ------- | ||||
| 
 | ||||
| No code changes. | ||||
| 
 | ||||
| * Reverted license field in package.json to "Public domain". | ||||
| 
 | ||||
| * Fixed typo in README. | ||||
| 
 | ||||
| 
 | ||||
| v0.13.2 | ||||
| ------- | ||||
| 
 | ||||
| * Fixed undefined variable bug in fast version of Poly1305. No worries, this | ||||
|   bug was *never* triggered. | ||||
| 
 | ||||
| * Specified CC0 public domain dedication. | ||||
| 
 | ||||
| * Updated development dependencies. | ||||
| 
 | ||||
| 
 | ||||
| v0.13.1 | ||||
| ------- | ||||
| 
 | ||||
| * Exclude `crypto` and `buffer` modules from browserify builds. | ||||
| 
 | ||||
| 
 | ||||
| v0.13.0 | ||||
| ------- | ||||
| 
 | ||||
| * Made `nacl-fast` the default version in NPM package. Now | ||||
|   `require("tweetnacl")` will use fast version; to get the original version, | ||||
|   use `require("tweetnacl/nacl.js")`. | ||||
| 
 | ||||
| * Cleanup temporary array after generating random bytes. | ||||
| 
 | ||||
| 
 | ||||
| v0.12.2 | ||||
| ------- | ||||
| 
 | ||||
| * Improved performance of curve operations, making `nacl.scalarMult`, `nacl.box`, | ||||
|   `nacl.sign` and related functions up to 3x faster in `nacl-fast` version. | ||||
| 
 | ||||
| 
 | ||||
| v0.12.1 | ||||
| ------- | ||||
| 
 | ||||
| * Significantly improved performance of Salsa20 (~1.5x faster) and | ||||
|   Poly1305 (~3.5x faster) in `nacl-fast` version. | ||||
| 
 | ||||
| 
 | ||||
| v0.12.0 | ||||
| ------- | ||||
| 
 | ||||
| * Instead of using the given secret key directly, TweetNaCl.js now copies it to | ||||
|   a new array in `nacl.box.keyPair.fromSecretKey` and | ||||
|   `nacl.sign.keyPair.fromSecretKey`. | ||||
| 
 | ||||
| 
 | ||||
| v0.11.2 | ||||
| ------- | ||||
| 
 | ||||
| * Added new constant: `nacl.sign.seedLength`. | ||||
| 
 | ||||
| 
 | ||||
| v0.11.1 | ||||
| ------- | ||||
| 
 | ||||
| * Even faster hash for both short and long inputs (in `nacl-fast`). | ||||
| 
 | ||||
| 
 | ||||
| v0.11.0 | ||||
| ------- | ||||
| 
 | ||||
| * Implement `nacl.sign.keyPair.fromSeed` to enable creation of sign key pairs | ||||
|   deterministically from a 32-byte seed. (It behaves like | ||||
|   [libsodium's](http://doc.libsodium.org/public-key_cryptography/public-key_signatures.html) | ||||
|   `crypto_sign_seed_keypair`: the seed becomes a secret part of the secret key.) | ||||
| 
 | ||||
| * Fast version now has an improved hash implementation that is 2x-5x faster. | ||||
| 
 | ||||
| * Fixed benchmarks, which may have produced incorrect measurements. | ||||
| 
 | ||||
| 
 | ||||
| v0.10.1 | ||||
| ------- | ||||
| 
 | ||||
| * Exported undocumented `nacl.lowlevel.crypto_core_hsalsa20`. | ||||
| 
 | ||||
| 
 | ||||
| v0.10.0 | ||||
| ------- | ||||
| 
 | ||||
| * **Signature API breaking change!** `nacl.sign` and `nacl.sign.open` now deal | ||||
|  with signed messages, and new `nacl.sign.detached` and | ||||
|  `nacl.sign.detached.verify` are available. | ||||
|   | ||||
|  Previously, `nacl.sign` returned a signature, and `nacl.sign.open` accepted a | ||||
|  message and "detached" signature. This was unlike NaCl's API, which dealt with | ||||
|  signed messages (concatenation of signature and message). | ||||
|   | ||||
|  The new API is: | ||||
| 
 | ||||
|       nacl.sign(message, secretKey) -> signedMessage | ||||
|       nacl.sign.open(signedMessage, publicKey) -> message | null | ||||
| 
 | ||||
|  Since detached signatures are common, two new API functions were introduced: | ||||
|   | ||||
|       nacl.sign.detached(message, secretKey) -> signature | ||||
|       nacl.sign.detached.verify(message, signature, publicKey) -> true | false | ||||
| 
 | ||||
|  (Note that it's `verify`, not `open`, and it returns a boolean value, unlike | ||||
|  `open`, which returns an "unsigned" message.) | ||||
| 
 | ||||
| * NPM package now comes without `test` directory to keep it small. | ||||
| 
 | ||||
| 
 | ||||
| v0.9.2 | ||||
| ------ | ||||
| 
 | ||||
| * Improved documentation. | ||||
| * Fast version: increased theoretical message size limit from 2^32-1 to 2^52 | ||||
|   bytes in Poly1305 (and thus, secretbox and box). However this has no impact | ||||
|   in practice since JavaScript arrays or ArrayBuffers are limited to 32-bit | ||||
|   indexes, and most implementations won't allocate more than a gigabyte or so. | ||||
|   (Obviously, there are no tests for the correctness of implementation.) Also, | ||||
|   it's not recommended to use messages that large without splitting them into | ||||
|   smaller packets anyway. | ||||
| 
 | ||||
| 
 | ||||
| v0.9.1 | ||||
| ------ | ||||
| 
 | ||||
| * Initial release | ||||
							
								
								
									
										24
									
								
								node_modules/sshpk/node_modules/tweetnacl/LICENSE
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								node_modules/sshpk/node_modules/tweetnacl/LICENSE
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| This is free and unencumbered software released into the public domain. | ||||
| 
 | ||||
| Anyone is free to copy, modify, publish, use, compile, sell, or | ||||
| distribute this software, either in source code form or as a compiled | ||||
| binary, for any purpose, commercial or non-commercial, and by any | ||||
| means. | ||||
| 
 | ||||
| In jurisdictions that recognize copyright laws, the author or authors | ||||
| of this software dedicate any and all copyright interest in the | ||||
| software to the public domain. We make this dedication for the benefit | ||||
| of the public at large and to the detriment of our heirs and | ||||
| successors. We intend this dedication to be an overt act of | ||||
| relinquishment in perpetuity of all present and future rights to this | ||||
| software under copyright law. | ||||
| 
 | ||||
| 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 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. | ||||
| 
 | ||||
| For more information, please refer to <http://unlicense.org> | ||||
							
								
								
									
										20
									
								
								node_modules/sshpk/node_modules/tweetnacl/PULL_REQUEST_TEMPLATE.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								node_modules/sshpk/node_modules/tweetnacl/PULL_REQUEST_TEMPLATE.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | |||
| # Important! | ||||
| 
 | ||||
| If your contribution is not trivial (not a typo fix, etc.), we can only accept | ||||
| it if you dedicate your copyright for the contribution to the public domain. | ||||
| Make sure you understand what it means (see http://unlicense.org/)! If you | ||||
| agree, please add yourself to AUTHORS.md file, and include the following text | ||||
| to your pull request description or a comment in it: | ||||
| 
 | ||||
| ------------------------------------------------------------------------------ | ||||
| 
 | ||||
|     I dedicate any and all copyright interest in this software to the | ||||
|     public domain. I make this dedication for the benefit of the public at | ||||
|     large and to the detriment of my heirs and successors. I intend this | ||||
|     dedication to be an overt act of relinquishment in perpetuity of all | ||||
|     present and future rights to this software under copyright law. | ||||
| 
 | ||||
|     Anyone is free to copy, modify, publish, use, compile, sell, or | ||||
|     distribute this software, either in source code form or as a compiled | ||||
|     binary, for any purpose, commercial or non-commercial, and by any | ||||
|     means. | ||||
							
								
								
									
										459
									
								
								node_modules/sshpk/node_modules/tweetnacl/README.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										459
									
								
								node_modules/sshpk/node_modules/tweetnacl/README.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,459 @@ | |||
| TweetNaCl.js | ||||
| ============ | ||||
| 
 | ||||
| Port of [TweetNaCl](http://tweetnacl.cr.yp.to) / [NaCl](http://nacl.cr.yp.to/) | ||||
| to JavaScript for modern browsers and Node.js. Public domain. | ||||
| 
 | ||||
| [ | ||||
| ](https://travis-ci.org/dchest/tweetnacl-js) | ||||
| 
 | ||||
| Demo: <https://tweetnacl.js.org> | ||||
| 
 | ||||
| **:warning: The library is stable and API is frozen, however it has not been | ||||
| independently reviewed. If you can help reviewing it, please [contact | ||||
| me](mailto:dmitry@codingrobots.com).** | ||||
| 
 | ||||
| Documentation | ||||
| ============= | ||||
| 
 | ||||
| * [Overview](#overview) | ||||
| * [Installation](#installation) | ||||
| * [Usage](#usage) | ||||
|   * [Public-key authenticated encryption (box)](#public-key-authenticated-encryption-box) | ||||
|   * [Secret-key authenticated encryption (secretbox)](#secret-key-authenticated-encryption-secretbox) | ||||
|   * [Scalar multiplication](#scalar-multiplication) | ||||
|   * [Signatures](#signatures) | ||||
|   * [Hashing](#hashing) | ||||
|   * [Random bytes generation](#random-bytes-generation) | ||||
|   * [Constant-time comparison](#constant-time-comparison) | ||||
| * [System requirements](#system-requirements) | ||||
| * [Development and testing](#development-and-testing) | ||||
| * [Benchmarks](#benchmarks) | ||||
| * [Contributors](#contributors) | ||||
| * [Who uses it](#who-uses-it) | ||||
| 
 | ||||
| 
 | ||||
| Overview | ||||
| -------- | ||||
| 
 | ||||
| The primary goal of this project is to produce a translation of TweetNaCl to | ||||
| JavaScript which is as close as possible to the original C implementation, plus | ||||
| a thin layer of idiomatic high-level API on top of it. | ||||
| 
 | ||||
| There are two versions, you can use either of them: | ||||
| 
 | ||||
| * `nacl.js` is the port of TweetNaCl with minimum differences from the | ||||
|   original + high-level API. | ||||
| 
 | ||||
| * `nacl-fast.js` is like `nacl.js`, but with some functions replaced with | ||||
|   faster versions. | ||||
| 
 | ||||
| 
 | ||||
| Installation | ||||
| ------------ | ||||
| 
 | ||||
| You can install TweetNaCl.js via a package manager: | ||||
| 
 | ||||
| [Bower](http://bower.io): | ||||
| 
 | ||||
|     $ bower install tweetnacl | ||||
| 
 | ||||
| [NPM](https://www.npmjs.org/): | ||||
| 
 | ||||
|     $ npm install tweetnacl | ||||
| 
 | ||||
| or [download source code](https://github.com/dchest/tweetnacl-js/releases). | ||||
| 
 | ||||
| 
 | ||||
| Usage | ||||
| ----- | ||||
| 
 | ||||
| All API functions accept and return bytes as `Uint8Array`s.  If you need to | ||||
| encode or decode strings, use functions from | ||||
| <https://github.com/dchest/tweetnacl-util-js> or one of the more robust codec | ||||
| packages. | ||||
| 
 | ||||
| In Node.js v4 and later `Buffer` objects are backed by `Uint8Array`s, so you | ||||
| can freely pass them to TweetNaCl.js functions as arguments. The returned | ||||
| objects are still `Uint8Array`s, so if you need `Buffer`s, you'll have to | ||||
| convert them manually; make sure to convert using copying: `new Buffer(array)`, | ||||
| instead of sharing: `new Buffer(array.buffer)`, because some functions return | ||||
| subarrays of their buffers. | ||||
| 
 | ||||
| 
 | ||||
| ### Public-key authenticated encryption (box) | ||||
| 
 | ||||
| Implements *curve25519-xsalsa20-poly1305*. | ||||
| 
 | ||||
| #### nacl.box.keyPair() | ||||
| 
 | ||||
| Generates a new random key pair for box and returns it as an object with | ||||
| `publicKey` and `secretKey` members: | ||||
| 
 | ||||
|     { | ||||
|        publicKey: ...,  // Uint8Array with 32-byte public key | ||||
|        secretKey: ...   // Uint8Array with 32-byte secret key | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| #### nacl.box.keyPair.fromSecretKey(secretKey) | ||||
| 
 | ||||
| Returns a key pair for box with public key corresponding to the given secret | ||||
| key. | ||||
| 
 | ||||
| #### nacl.box(message, nonce, theirPublicKey, mySecretKey) | ||||
| 
 | ||||
| Encrypt and authenticates message using peer's public key, our secret key, and | ||||
| the given nonce, which must be unique for each distinct message for a key pair. | ||||
| 
 | ||||
| Returns an encrypted and authenticated message, which is | ||||
| `nacl.box.overheadLength` longer than the original message. | ||||
| 
 | ||||
| #### nacl.box.open(box, nonce, theirPublicKey, mySecretKey) | ||||
| 
 | ||||
| Authenticates and decrypts the given box with peer's public key, our secret | ||||
| key, and the given nonce. | ||||
| 
 | ||||
| Returns the original message, or `false` if authentication fails. | ||||
| 
 | ||||
| #### nacl.box.before(theirPublicKey, mySecretKey) | ||||
| 
 | ||||
| Returns a precomputed shared key which can be used in `nacl.box.after` and | ||||
| `nacl.box.open.after`. | ||||
| 
 | ||||
| #### nacl.box.after(message, nonce, sharedKey) | ||||
| 
 | ||||
| Same as `nacl.box`, but uses a shared key precomputed with `nacl.box.before`. | ||||
| 
 | ||||
| #### nacl.box.open.after(box, nonce, sharedKey) | ||||
| 
 | ||||
| Same as `nacl.box.open`, but uses a shared key precomputed with `nacl.box.before`. | ||||
| 
 | ||||
| #### nacl.box.publicKeyLength = 32 | ||||
| 
 | ||||
| Length of public key in bytes. | ||||
| 
 | ||||
| #### nacl.box.secretKeyLength = 32 | ||||
| 
 | ||||
| Length of secret key in bytes. | ||||
| 
 | ||||
| #### nacl.box.sharedKeyLength = 32 | ||||
| 
 | ||||
| Length of precomputed shared key in bytes. | ||||
| 
 | ||||
| #### nacl.box.nonceLength = 24 | ||||
| 
 | ||||
| Length of nonce in bytes. | ||||
| 
 | ||||
| #### nacl.box.overheadLength = 16 | ||||
| 
 | ||||
| Length of overhead added to box compared to original message. | ||||
| 
 | ||||
| 
 | ||||
| ### Secret-key authenticated encryption (secretbox) | ||||
| 
 | ||||
| Implements *xsalsa20-poly1305*. | ||||
| 
 | ||||
| #### nacl.secretbox(message, nonce, key) | ||||
| 
 | ||||
| Encrypt and authenticates message using the key and the nonce. The nonce must | ||||
| be unique for each distinct message for this key. | ||||
| 
 | ||||
| Returns an encrypted and authenticated message, which is | ||||
| `nacl.secretbox.overheadLength` longer than the original message. | ||||
| 
 | ||||
| #### nacl.secretbox.open(box, nonce, key) | ||||
| 
 | ||||
| Authenticates and decrypts the given secret box using the key and the nonce. | ||||
| 
 | ||||
| Returns the original message, or `false` if authentication fails. | ||||
| 
 | ||||
| #### nacl.secretbox.keyLength = 32 | ||||
| 
 | ||||
| Length of key in bytes. | ||||
| 
 | ||||
| #### nacl.secretbox.nonceLength = 24 | ||||
| 
 | ||||
| Length of nonce in bytes. | ||||
| 
 | ||||
| #### nacl.secretbox.overheadLength = 16 | ||||
| 
 | ||||
| Length of overhead added to secret box compared to original message. | ||||
| 
 | ||||
| 
 | ||||
| ### Scalar multiplication | ||||
| 
 | ||||
| Implements *curve25519*. | ||||
| 
 | ||||
| #### nacl.scalarMult(n, p) | ||||
| 
 | ||||
| Multiplies an integer `n` by a group element `p` and returns the resulting | ||||
| group element. | ||||
| 
 | ||||
| #### nacl.scalarMult.base(n) | ||||
| 
 | ||||
| Multiplies an integer `n` by a standard group element and returns the resulting | ||||
| group element. | ||||
| 
 | ||||
| #### nacl.scalarMult.scalarLength = 32 | ||||
| 
 | ||||
| Length of scalar in bytes. | ||||
| 
 | ||||
| #### nacl.scalarMult.groupElementLength = 32 | ||||
| 
 | ||||
| Length of group element in bytes. | ||||
| 
 | ||||
| 
 | ||||
| ### Signatures | ||||
| 
 | ||||
| Implements [ed25519](http://ed25519.cr.yp.to). | ||||
| 
 | ||||
| #### nacl.sign.keyPair() | ||||
| 
 | ||||
| Generates new random key pair for signing and returns it as an object with | ||||
| `publicKey` and `secretKey` members: | ||||
| 
 | ||||
|     { | ||||
|        publicKey: ...,  // Uint8Array with 32-byte public key | ||||
|        secretKey: ...   // Uint8Array with 64-byte secret key | ||||
|     } | ||||
| 
 | ||||
| #### nacl.sign.keyPair.fromSecretKey(secretKey) | ||||
| 
 | ||||
| Returns a signing key pair with public key corresponding to the given | ||||
| 64-byte secret key. The secret key must have been generated by | ||||
| `nacl.sign.keyPair` or `nacl.sign.keyPair.fromSeed`. | ||||
| 
 | ||||
| #### nacl.sign.keyPair.fromSeed(seed) | ||||
| 
 | ||||
| Returns a new signing key pair generated deterministically from a 32-byte seed. | ||||
| The seed must contain enough entropy to be secure. This method is not | ||||
| recommended for general use: instead, use `nacl.sign.keyPair` to generate a new | ||||
| key pair from a random seed. | ||||
| 
 | ||||
| #### nacl.sign(message, secretKey) | ||||
| 
 | ||||
| Signs the message using the secret key and returns a signed message. | ||||
| 
 | ||||
| #### nacl.sign.open(signedMessage, publicKey) | ||||
| 
 | ||||
| Verifies the signed message and returns the message without signature. | ||||
| 
 | ||||
| Returns `null` if verification failed. | ||||
| 
 | ||||
| #### nacl.sign.detached(message, secretKey) | ||||
| 
 | ||||
| Signs the message using the secret key and returns a signature. | ||||
| 
 | ||||
| #### nacl.sign.detached.verify(message, signature, publicKey) | ||||
| 
 | ||||
| Verifies the signature for the message and returns `true` if verification | ||||
| succeeded or `false` if it failed. | ||||
| 
 | ||||
| #### nacl.sign.publicKeyLength = 32 | ||||
| 
 | ||||
| Length of signing public key in bytes. | ||||
| 
 | ||||
| #### nacl.sign.secretKeyLength = 64 | ||||
| 
 | ||||
| Length of signing secret key in bytes. | ||||
| 
 | ||||
| #### nacl.sign.seedLength = 32 | ||||
| 
 | ||||
| Length of seed for `nacl.sign.keyPair.fromSeed` in bytes. | ||||
| 
 | ||||
| #### nacl.sign.signatureLength = 64 | ||||
| 
 | ||||
| Length of signature in bytes. | ||||
| 
 | ||||
| 
 | ||||
| ### Hashing | ||||
| 
 | ||||
| Implements *SHA-512*. | ||||
| 
 | ||||
| #### nacl.hash(message) | ||||
| 
 | ||||
| Returns SHA-512 hash of the message. | ||||
| 
 | ||||
| #### nacl.hash.hashLength = 64 | ||||
| 
 | ||||
| Length of hash in bytes. | ||||
| 
 | ||||
| 
 | ||||
| ### Random bytes generation | ||||
| 
 | ||||
| #### nacl.randomBytes(length) | ||||
| 
 | ||||
| Returns a `Uint8Array` of the given length containing random bytes of | ||||
| cryptographic quality. | ||||
| 
 | ||||
| **Implementation note** | ||||
| 
 | ||||
| TweetNaCl.js uses the following methods to generate random bytes, | ||||
| depending on the platform it runs on: | ||||
| 
 | ||||
| * `window.crypto.getRandomValues` (WebCrypto standard) | ||||
| * `window.msCrypto.getRandomValues` (Internet Explorer 11) | ||||
| * `crypto.randomBytes` (Node.js) | ||||
| 
 | ||||
| If the platform doesn't provide a suitable PRNG, the following functions, | ||||
| which require random numbers, will throw exception: | ||||
| 
 | ||||
| * `nacl.randomBytes` | ||||
| * `nacl.box.keyPair` | ||||
| * `nacl.sign.keyPair` | ||||
| 
 | ||||
| Other functions are deterministic and will continue working. | ||||
| 
 | ||||
| If a platform you are targeting doesn't implement secure random number | ||||
| generator, but you somehow have a cryptographically-strong source of entropy | ||||
| (not `Math.random`!), and you know what you are doing, you can plug it into | ||||
| TweetNaCl.js like this: | ||||
| 
 | ||||
|     nacl.setPRNG(function(x, n) { | ||||
|       // ... copy n random bytes into x ... | ||||
|     }); | ||||
| 
 | ||||
| Note that `nacl.setPRNG` *completely replaces* internal random byte generator | ||||
| with the one provided. | ||||
| 
 | ||||
| 
 | ||||
| ### Constant-time comparison | ||||
| 
 | ||||
| #### nacl.verify(x, y) | ||||
| 
 | ||||
| Compares `x` and `y` in constant time and returns `true` if their lengths are | ||||
| non-zero and equal, and their contents are equal. | ||||
| 
 | ||||
| Returns `false` if either of the arguments has zero length, or arguments have | ||||
| different lengths, or their contents differ. | ||||
| 
 | ||||
| 
 | ||||
| System requirements | ||||
| ------------------- | ||||
| 
 | ||||
| TweetNaCl.js supports modern browsers that have a cryptographically secure | ||||
| pseudorandom number generator and typed arrays, including the latest versions | ||||
| of: | ||||
| 
 | ||||
| * Chrome | ||||
| * Firefox | ||||
| * Safari (Mac, iOS) | ||||
| * Internet Explorer 11 | ||||
| 
 | ||||
| Other systems: | ||||
| 
 | ||||
| * Node.js | ||||
| 
 | ||||
| 
 | ||||
| Development and testing | ||||
| ------------------------ | ||||
| 
 | ||||
| Install NPM modules needed for development: | ||||
| 
 | ||||
|     $ npm install | ||||
| 
 | ||||
| To build minified versions: | ||||
| 
 | ||||
|     $ npm run build | ||||
| 
 | ||||
| Tests use minified version, so make sure to rebuild it every time you change | ||||
| `nacl.js` or `nacl-fast.js`. | ||||
| 
 | ||||
| ### Testing | ||||
| 
 | ||||
| To run tests in Node.js: | ||||
| 
 | ||||
|     $ npm run test-node | ||||
| 
 | ||||
| By default all tests described here work on `nacl.min.js`. To test other | ||||
| versions, set environment variable `NACL_SRC` to the file name you want to test. | ||||
| For example, the following command will test fast minified version: | ||||
| 
 | ||||
|     $ NACL_SRC=nacl-fast.min.js npm run test-node | ||||
| 
 | ||||
| To run full suite of tests in Node.js, including comparing outputs of | ||||
| JavaScript port to outputs of the original C version: | ||||
| 
 | ||||
|     $ npm run test-node-all | ||||
| 
 | ||||
| To prepare tests for browsers: | ||||
| 
 | ||||
|     $ npm run build-test-browser | ||||
| 
 | ||||
| and then open `test/browser/test.html` (or `test/browser/test-fast.html`) to | ||||
| run them. | ||||
| 
 | ||||
| To run headless browser tests with `tape-run` (powered by Electron): | ||||
| 
 | ||||
|     $ npm run test-browser | ||||
| 
 | ||||
| (If you get `Error: spawn ENOENT`, install *xvfb*: `sudo apt-get install xvfb`.) | ||||
| 
 | ||||
| To run tests in both Node and Electron: | ||||
| 
 | ||||
|     $ npm test | ||||
| 
 | ||||
| ### Benchmarking | ||||
| 
 | ||||
| To run benchmarks in Node.js: | ||||
| 
 | ||||
|     $ npm run bench | ||||
|     $ NACL_SRC=nacl-fast.min.js npm run bench | ||||
| 
 | ||||
| To run benchmarks in a browser, open `test/benchmark/bench.html` (or | ||||
| `test/benchmark/bench-fast.html`). | ||||
| 
 | ||||
| 
 | ||||
| Benchmarks | ||||
| ---------- | ||||
| 
 | ||||
| For reference, here are benchmarks from MacBook Pro (Retina, 13-inch, Mid 2014) | ||||
| laptop with 2.6 GHz Intel Core i5 CPU (Intel) in Chrome 53/OS X and Xiaomi Redmi | ||||
| Note 3 smartphone with 1.8 GHz Qualcomm Snapdragon 650 64-bit CPU (ARM) in | ||||
| Chrome 52/Android: | ||||
| 
 | ||||
| |               | nacl.js Intel | nacl-fast.js Intel  |   nacl.js ARM | nacl-fast.js ARM  | | ||||
| | ------------- |:-------------:|:-------------------:|:-------------:|:-----------------:| | ||||
| | salsa20       | 1.3 MB/s      | 128 MB/s            |  0.4 MB/s     |  43 MB/s          | | ||||
| | poly1305      | 13 MB/s       | 171 MB/s            |  4 MB/s       |  52 MB/s          | | ||||
| | hash          | 4 MB/s        | 34 MB/s             |  0.9 MB/s     |  12 MB/s          | | ||||
| | secretbox 1K  | 1113 op/s     | 57583 op/s          |  334 op/s     |  14227 op/s       | | ||||
| | box 1K        | 145 op/s      | 718 op/s            |  37 op/s      |  368 op/s         | | ||||
| | scalarMult    | 171 op/s      | 733 op/s            |  56 op/s      |  380 op/s         | | ||||
| | sign          | 77  op/s      | 200 op/s            |  20 op/s      |  61 op/s          | | ||||
| | sign.open     | 39  op/s      | 102  op/s           |  11 op/s      |  31 op/s          | | ||||
| 
 | ||||
| (You can run benchmarks on your devices by clicking on the links at the bottom | ||||
| of the [home page](https://tweetnacl.js.org)). | ||||
| 
 | ||||
| In short, with *nacl-fast.js* and 1024-byte messages you can expect to encrypt and | ||||
| authenticate more than 57000 messages per second on a typical laptop or more than | ||||
| 14000 messages per second on a $170 smartphone, sign about 200 and verify 100 | ||||
| messages per second on a laptop or 60 and 30 messages per second on a smartphone, | ||||
| per CPU core (with Web Workers you can do these operations in parallel), | ||||
| which is good enough for most applications. | ||||
| 
 | ||||
| 
 | ||||
| Contributors | ||||
| ------------ | ||||
| 
 | ||||
| See AUTHORS.md file. | ||||
| 
 | ||||
| 
 | ||||
| Third-party libraries based on TweetNaCl.js | ||||
| ------------------------------------------- | ||||
| 
 | ||||
| * [forward-secrecy](https://github.com/alax/forward-secrecy) — Axolotl ratchet implementation | ||||
| * [nacl-stream](https://github.com/dchest/nacl-stream-js) - streaming encryption | ||||
| * [tweetnacl-auth-js](https://github.com/dchest/tweetnacl-auth-js) — implementation of [`crypto_auth`](http://nacl.cr.yp.to/auth.html) | ||||
| * [chloride](https://github.com/dominictarr/chloride) - unified API for various NaCl modules | ||||
| 
 | ||||
| 
 | ||||
| Who uses it | ||||
| ----------- | ||||
| 
 | ||||
| Some notable users of TweetNaCl.js: | ||||
| 
 | ||||
| * [miniLock](http://minilock.io/) | ||||
| * [Stellar](https://www.stellar.org/) | ||||
							
								
								
									
										2388
									
								
								node_modules/sshpk/node_modules/tweetnacl/nacl-fast.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2388
									
								
								node_modules/sshpk/node_modules/tweetnacl/nacl-fast.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										2
									
								
								node_modules/sshpk/node_modules/tweetnacl/nacl-fast.min.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								node_modules/sshpk/node_modules/tweetnacl/nacl-fast.min.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										98
									
								
								node_modules/sshpk/node_modules/tweetnacl/nacl.d.ts
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								node_modules/sshpk/node_modules/tweetnacl/nacl.d.ts
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,98 @@ | |||
| // Type definitions for TweetNaCl.js
 | ||||
| 
 | ||||
| export as namespace nacl; | ||||
| 
 | ||||
| declare var nacl: nacl; | ||||
| export = nacl; | ||||
| 
 | ||||
| declare namespace nacl { | ||||
|     export interface BoxKeyPair { | ||||
|         publicKey: Uint8Array; | ||||
|         secretKey: Uint8Array; | ||||
|     } | ||||
| 
 | ||||
|     export interface SignKeyPair { | ||||
|         publicKey: Uint8Array; | ||||
|         secretKey: Uint8Array; | ||||
|     } | ||||
| 
 | ||||
|     export interface secretbox { | ||||
|         (msg: Uint8Array, nonce: Uint8Array, key: Uint8Array): Uint8Array; | ||||
|         open(box: Uint8Array, nonce: Uint8Array, key: Uint8Array): Uint8Array | false; | ||||
|         readonly keyLength: number; | ||||
|         readonly nonceLength: number; | ||||
|         readonly overheadLength: number; | ||||
|     } | ||||
| 
 | ||||
|     export interface scalarMult { | ||||
|         (n: Uint8Array, p: Uint8Array): Uint8Array; | ||||
|         base(n: Uint8Array): Uint8Array; | ||||
|         readonly scalarLength: number; | ||||
|         readonly groupElementLength: number; | ||||
|     } | ||||
| 
 | ||||
|     namespace box { | ||||
|         export interface open { | ||||
|             (msg: Uint8Array, nonce: Uint8Array, publicKey: Uint8Array, secretKey: Uint8Array): Uint8Array | false; | ||||
|             after(box: Uint8Array, nonce: Uint8Array, key: Uint8Array): Uint8Array | false; | ||||
|         } | ||||
| 
 | ||||
|         export interface keyPair { | ||||
|             (): BoxKeyPair; | ||||
|             fromSecretKey(secretKey: Uint8Array): BoxKeyPair; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     export interface box { | ||||
|         (msg: Uint8Array, nonce: Uint8Array, publicKey: Uint8Array, secretKey: Uint8Array): Uint8Array; | ||||
|         before(publicKey: Uint8Array, secretKey: Uint8Array): Uint8Array; | ||||
|         after(msg: Uint8Array, nonce: Uint8Array, key: Uint8Array): Uint8Array; | ||||
|         open: box.open; | ||||
|         keyPair: box.keyPair; | ||||
|         readonly publicKeyLength: number; | ||||
|         readonly secretKeyLength: number; | ||||
|         readonly sharedKeyLength: number; | ||||
|         readonly nonceLength: number; | ||||
|         readonly overheadLength: number; | ||||
|     } | ||||
| 
 | ||||
|     namespace sign { | ||||
|         export interface detached { | ||||
|             (msg: Uint8Array, secretKey: Uint8Array): Uint8Array; | ||||
|             verify(msg: Uint8Array, sig: Uint8Array, publicKey: Uint8Array): boolean; | ||||
|         } | ||||
| 
 | ||||
|         export interface keyPair { | ||||
|             (): SignKeyPair; | ||||
|             fromSecretKey(secretKey: Uint8Array): SignKeyPair; | ||||
|             fromSeed(secretKey: Uint8Array): SignKeyPair; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     export interface sign { | ||||
|         (msg: Uint8Array, secretKey: Uint8Array): Uint8Array; | ||||
|         open(signedMsg: Uint8Array, publicKey: Uint8Array): Uint8Array | null; | ||||
|         detached: sign.detached; | ||||
|         keyPair: sign.keyPair; | ||||
|         readonly publicKeyLength: number; | ||||
|         readonly secretKeyLength: number; | ||||
|         readonly seedLength: number; | ||||
|         readonly signatureLength: number; | ||||
|     } | ||||
| 
 | ||||
|     export interface hash { | ||||
|         (msg: Uint8Array): Uint8Array; | ||||
|         readonly hashLength: number; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| declare interface nacl { | ||||
|     randomBytes(n: number): Uint8Array; | ||||
|     secretbox: nacl.secretbox; | ||||
|     scalarMult: nacl.scalarMult; | ||||
|     box: nacl.box; | ||||
|     sign: nacl.sign; | ||||
|     hash: nacl.hash; | ||||
|     verify(x: Uint8Array, y: Uint8Array): boolean; | ||||
|     setPRNG(fn: (x: Uint8Array, n: number) => void): void; | ||||
| } | ||||
							
								
								
									
										1175
									
								
								node_modules/sshpk/node_modules/tweetnacl/nacl.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1175
									
								
								node_modules/sshpk/node_modules/tweetnacl/nacl.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										1
									
								
								node_modules/sshpk/node_modules/tweetnacl/nacl.min.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								node_modules/sshpk/node_modules/tweetnacl/nacl.min.js
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										58
									
								
								node_modules/sshpk/node_modules/tweetnacl/package.json
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								node_modules/sshpk/node_modules/tweetnacl/package.json
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,58 @@ | |||
| { | ||||
|   "name": "tweetnacl", | ||||
|   "version": "0.14.5", | ||||
|   "description": "Port of TweetNaCl cryptographic library to JavaScript", | ||||
|   "main": "nacl-fast.js", | ||||
|   "types": "nacl.d.ts", | ||||
|   "directories": { | ||||
|     "test": "test" | ||||
|   }, | ||||
|   "scripts": { | ||||
|     "build": "uglifyjs nacl.js -c -m -o nacl.min.js && uglifyjs nacl-fast.js -c -m -o nacl-fast.min.js", | ||||
|     "test-node": "tape test/*.js | faucet", | ||||
|     "test-node-all": "make -C test/c && tape test/*.js test/c/*.js | faucet", | ||||
|     "test-browser": "NACL_SRC=${NACL_SRC:='nacl.min.js'} && npm run build-test-browser && cat $NACL_SRC test/browser/_bundle.js | tape-run | faucet", | ||||
|     "build-test-browser": "browserify test/browser/init.js test/*.js | uglifyjs -c -m -o test/browser/_bundle.js 2>/dev/null && browserify test/browser/init.js test/*.quick.js | uglifyjs -c -m -o test/browser/_bundle-quick.js 2>/dev/null", | ||||
|     "test": "npm run test-node-all && npm run test-browser", | ||||
|     "bench": "node test/benchmark/bench.js", | ||||
|     "lint": "eslint nacl.js nacl-fast.js test/*.js test/benchmark/*.js" | ||||
|   }, | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
|     "url": "https://github.com/dchest/tweetnacl-js.git" | ||||
|   }, | ||||
|   "keywords": [ | ||||
|     "crypto", | ||||
|     "cryptography", | ||||
|     "curve25519", | ||||
|     "ed25519", | ||||
|     "encrypt", | ||||
|     "hash", | ||||
|     "key", | ||||
|     "nacl", | ||||
|     "poly1305", | ||||
|     "public", | ||||
|     "salsa20", | ||||
|     "signatures" | ||||
|   ], | ||||
|   "author": "TweetNaCl-js contributors", | ||||
|   "license": "Unlicense", | ||||
|   "bugs": { | ||||
|     "url": "https://github.com/dchest/tweetnacl-js/issues" | ||||
|   }, | ||||
|   "homepage": "https://tweetnacl.js.org", | ||||
|   "devDependencies": { | ||||
|     "browserify": "^13.0.0", | ||||
|     "eslint": "^2.2.0", | ||||
|     "faucet": "^0.0.1", | ||||
|     "tap-browser-color": "^0.1.2", | ||||
|     "tape": "^4.4.0", | ||||
|     "tape-run": "^2.1.3", | ||||
|     "tweetnacl-util": "^0.13.3", | ||||
|     "uglify-js": "^2.6.1" | ||||
|   }, | ||||
|   "browser": { | ||||
|     "buffer": false, | ||||
|     "crypto": false | ||||
|   } | ||||
| } | ||||
							
								
								
									
										60
									
								
								node_modules/sshpk/package.json
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								node_modules/sshpk/package.json
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | |||
| { | ||||
|   "name": "sshpk", | ||||
|   "version": "1.17.0", | ||||
|   "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" | ||||
|   } | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue