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
				
			
		
							
								
								
									
										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); | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue