v5
This commit is contained in:
		
							
								
								
									
										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();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										99
									
								
								node_modules/sshpk/lib/formats/putty.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								node_modules/sshpk/lib/formats/putty.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
// Copyright 2018 Joyent, Inc.
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
	read: read,
 | 
			
		||||
	write: write
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
var assert = require('assert-plus');
 | 
			
		||||
var Buffer = require('safer-buffer').Buffer;
 | 
			
		||||
var rfc4253 = require('./rfc4253');
 | 
			
		||||
var Key = require('../key');
 | 
			
		||||
 | 
			
		||||
var errors = require('../errors');
 | 
			
		||||
 | 
			
		||||
function read(buf, options) {
 | 
			
		||||
	var lines = buf.toString('ascii').split(/[\r\n]+/);
 | 
			
		||||
	var found = false;
 | 
			
		||||
	var parts;
 | 
			
		||||
	var si = 0;
 | 
			
		||||
	while (si < lines.length) {
 | 
			
		||||
		parts = splitHeader(lines[si++]);
 | 
			
		||||
		if (parts &&
 | 
			
		||||
		    parts[0].toLowerCase() === 'putty-user-key-file-2') {
 | 
			
		||||
			found = true;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (!found) {
 | 
			
		||||
		throw (new Error('No PuTTY format first line found'));
 | 
			
		||||
	}
 | 
			
		||||
	var alg = parts[1];
 | 
			
		||||
 | 
			
		||||
	parts = splitHeader(lines[si++]);
 | 
			
		||||
	assert.equal(parts[0].toLowerCase(), 'encryption');
 | 
			
		||||
 | 
			
		||||
	parts = splitHeader(lines[si++]);
 | 
			
		||||
	assert.equal(parts[0].toLowerCase(), 'comment');
 | 
			
		||||
	var comment = parts[1];
 | 
			
		||||
 | 
			
		||||
	parts = splitHeader(lines[si++]);
 | 
			
		||||
	assert.equal(parts[0].toLowerCase(), 'public-lines');
 | 
			
		||||
	var publicLines = parseInt(parts[1], 10);
 | 
			
		||||
	if (!isFinite(publicLines) || publicLines < 0 ||
 | 
			
		||||
	    publicLines > lines.length) {
 | 
			
		||||
		throw (new Error('Invalid public-lines count'));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var publicBuf = Buffer.from(
 | 
			
		||||
	    lines.slice(si, si + publicLines).join(''), 'base64');
 | 
			
		||||
	var keyType = rfc4253.algToKeyType(alg);
 | 
			
		||||
	var key = rfc4253.read(publicBuf);
 | 
			
		||||
	if (key.type !== keyType) {
 | 
			
		||||
		throw (new Error('Outer key algorithm mismatch'));
 | 
			
		||||
	}
 | 
			
		||||
	key.comment = comment;
 | 
			
		||||
	return (key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function splitHeader(line) {
 | 
			
		||||
	var idx = line.indexOf(':');
 | 
			
		||||
	if (idx === -1)
 | 
			
		||||
		return (null);
 | 
			
		||||
	var header = line.slice(0, idx);
 | 
			
		||||
	++idx;
 | 
			
		||||
	while (line[idx] === ' ')
 | 
			
		||||
		++idx;
 | 
			
		||||
	var rest = line.slice(idx);
 | 
			
		||||
	return ([header, rest]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function write(key, options) {
 | 
			
		||||
	assert.object(key);
 | 
			
		||||
	if (!Key.isKey(key))
 | 
			
		||||
		throw (new Error('Must be a public key'));
 | 
			
		||||
 | 
			
		||||
	var alg = rfc4253.keyTypeToAlg(key);
 | 
			
		||||
	var buf = rfc4253.write(key);
 | 
			
		||||
	var comment = key.comment || '';
 | 
			
		||||
 | 
			
		||||
	var b64 = buf.toString('base64');
 | 
			
		||||
	var lines = wrap(b64, 64);
 | 
			
		||||
 | 
			
		||||
	lines.unshift('Public-Lines: ' + lines.length);
 | 
			
		||||
	lines.unshift('Comment: ' + comment);
 | 
			
		||||
	lines.unshift('Encryption: none');
 | 
			
		||||
	lines.unshift('PuTTY-User-Key-File-2: ' + alg);
 | 
			
		||||
 | 
			
		||||
	return (Buffer.from(lines.join('\n') + '\n'));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function wrap(txt, len) {
 | 
			
		||||
	var lines = [];
 | 
			
		||||
	var pos = 0;
 | 
			
		||||
	while (pos < txt.length) {
 | 
			
		||||
		lines.push(txt.slice(pos, pos + 64));
 | 
			
		||||
		pos += 64;
 | 
			
		||||
	}
 | 
			
		||||
	return (lines);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										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);
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user