forked from root/acme.js
		
	remove cruft
This commit is contained in:
		
							parent
							
								
									c5757d2650
								
							
						
					
					
						commit
						1f2169c78c
					
				@ -1 +0,0 @@
 | 
				
			|||||||
Disabiguation: `Any`. There was once an actual ASN.1 type with the literal name 'Any'. It was deprecated in 1994 and the `Any` in the API simply means "give any value"
 | 
					 | 
				
			||||||
@ -1,11 +0,0 @@
 | 
				
			|||||||
'use strict';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var ASN1 = module.exports;
 | 
					 | 
				
			||||||
var packer = require('./packer.js');
 | 
					 | 
				
			||||||
var parser = require('./parser.js');
 | 
					 | 
				
			||||||
Object.keys(parser).forEach(function(key) {
 | 
					 | 
				
			||||||
	ASN1[key] = parser[key];
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
Object.keys(packer).forEach(function(key) {
 | 
					 | 
				
			||||||
	ASN1[key] = packer[key];
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
@ -1,91 +0,0 @@
 | 
				
			|||||||
'use strict';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var ASN1 = module.exports;
 | 
					 | 
				
			||||||
var Enc = require('@root/encoding/hex');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Packer
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Almost every ASN.1 type that's important for CSR
 | 
					 | 
				
			||||||
// can be represented generically with only a few rules.
 | 
					 | 
				
			||||||
function Any(/*type, hexstrings...*/) {
 | 
					 | 
				
			||||||
	var args = Array.prototype.slice.call(arguments);
 | 
					 | 
				
			||||||
	var typ = args.shift();
 | 
					 | 
				
			||||||
	var str = args
 | 
					 | 
				
			||||||
		.join('')
 | 
					 | 
				
			||||||
		.replace(/\s+/g, '')
 | 
					 | 
				
			||||||
		.toLowerCase();
 | 
					 | 
				
			||||||
	var len = str.length / 2;
 | 
					 | 
				
			||||||
	var lenlen = 0;
 | 
					 | 
				
			||||||
	var hex = typ;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// We can't have an odd number of hex chars
 | 
					 | 
				
			||||||
	if (len !== Math.round(len)) {
 | 
					 | 
				
			||||||
		throw new Error('invalid hex');
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// The first byte of any ASN.1 sequence is the type (Sequence, Integer, etc)
 | 
					 | 
				
			||||||
	// The second byte is either the size of the value, or the size of its size
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// 1. If the second byte is < 0x80 (128) it is considered the size
 | 
					 | 
				
			||||||
	// 2. If it is > 0x80 then it describes the number of bytes of the size
 | 
					 | 
				
			||||||
	//    ex: 0x82 means the next 2 bytes describe the size of the value
 | 
					 | 
				
			||||||
	// 3. The special case of exactly 0x80 is "indefinite" length (to end-of-file)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (len > 127) {
 | 
					 | 
				
			||||||
		lenlen += 1;
 | 
					 | 
				
			||||||
		while (len > 255) {
 | 
					 | 
				
			||||||
			lenlen += 1;
 | 
					 | 
				
			||||||
			len = len >> 8;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (lenlen) {
 | 
					 | 
				
			||||||
		hex += Enc.numToHex(0x80 + lenlen);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return hex + Enc.numToHex(str.length / 2) + str;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
ASN1.Any = Any;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// The Integer type has some special rules
 | 
					 | 
				
			||||||
ASN1.UInt = function UINT() {
 | 
					 | 
				
			||||||
	var str = Array.prototype.slice.call(arguments).join('');
 | 
					 | 
				
			||||||
	var first = parseInt(str.slice(0, 2), 16);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// If the first byte is 0x80 or greater, the number is considered negative
 | 
					 | 
				
			||||||
	// Therefore we add a '00' prefix if the 0x80 bit is set
 | 
					 | 
				
			||||||
	if (0x80 & first) {
 | 
					 | 
				
			||||||
		str = '00' + str;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return Any('02', str);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// The Bit String type also has a special rule
 | 
					 | 
				
			||||||
ASN1.BitStr = function BITSTR() {
 | 
					 | 
				
			||||||
	var str = Array.prototype.slice.call(arguments).join('');
 | 
					 | 
				
			||||||
	// '00' is a mask of how many bits of the next byte to ignore
 | 
					 | 
				
			||||||
	return Any('03', '00' + str);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ASN1.pack = function(arr) {
 | 
					 | 
				
			||||||
	var typ = Enc.numToHex(arr[0]);
 | 
					 | 
				
			||||||
	var str = '';
 | 
					 | 
				
			||||||
	if (Array.isArray(arr[1])) {
 | 
					 | 
				
			||||||
		arr[1].forEach(function(a) {
 | 
					 | 
				
			||||||
			str += ASN1.pack(a);
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
	} else if ('string' === typeof arr[1]) {
 | 
					 | 
				
			||||||
		str = arr[1];
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		throw new Error('unexpected array');
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if ('03' === typ) {
 | 
					 | 
				
			||||||
		return ASN1.BitStr(str);
 | 
					 | 
				
			||||||
	} else if ('02' === typ) {
 | 
					 | 
				
			||||||
		return ASN1.UInt(str);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		return Any(typ, str);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
							
								
								
									
										159
									
								
								asn1/parser.js
									
									
									
									
									
								
							
							
						
						
									
										159
									
								
								asn1/parser.js
									
									
									
									
									
								
							@ -1,159 +0,0 @@
 | 
				
			|||||||
// Copyright 2018 AJ ONeal. All rights reserved
 | 
					 | 
				
			||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
					 | 
				
			||||||
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
					 | 
				
			||||||
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
					 | 
				
			||||||
'use strict';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var ASN1 = module.exports;
 | 
					 | 
				
			||||||
var Enc = require('@root/encoding/hex');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Parser
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Although I've only seen 9 max in https certificates themselves,
 | 
					 | 
				
			||||||
// but each domain list could have up to 100
 | 
					 | 
				
			||||||
ASN1.ELOOPN = 102;
 | 
					 | 
				
			||||||
ASN1.ELOOP =
 | 
					 | 
				
			||||||
	'uASN1.js Error: iterated over ' +
 | 
					 | 
				
			||||||
	ASN1.ELOOPN +
 | 
					 | 
				
			||||||
	'+ elements (probably a malformed file)';
 | 
					 | 
				
			||||||
// I've seen https certificates go 29 deep
 | 
					 | 
				
			||||||
ASN1.EDEEPN = 60;
 | 
					 | 
				
			||||||
ASN1.EDEEP =
 | 
					 | 
				
			||||||
	'uASN1.js Error: element nested ' +
 | 
					 | 
				
			||||||
	ASN1.EDEEPN +
 | 
					 | 
				
			||||||
	'+ layers deep (probably a malformed file)';
 | 
					 | 
				
			||||||
// Container Types are Sequence 0x30, Container Array? (0xA0, 0xA1)
 | 
					 | 
				
			||||||
// Value Types are Boolean 0x01, Integer 0x02, Null 0x05, Object ID 0x06, String 0x0C, 0x16, 0x13, 0x1e Value Array? (0x82)
 | 
					 | 
				
			||||||
// Bit String (0x03) and Octet String (0x04) may be values or containers
 | 
					 | 
				
			||||||
// Sometimes Bit String is used as a container (RSA Pub Spki)
 | 
					 | 
				
			||||||
ASN1.CTYPES = [0x30, 0x31, 0xa0, 0xa1];
 | 
					 | 
				
			||||||
ASN1.VTYPES = [0x01, 0x02, 0x05, 0x06, 0x0c, 0x82];
 | 
					 | 
				
			||||||
ASN1.parse = function parseAsn1Helper(buf) {
 | 
					 | 
				
			||||||
	//var ws = '  ';
 | 
					 | 
				
			||||||
	function parseAsn1(buf, depth, eager) {
 | 
					 | 
				
			||||||
		if (depth.length >= ASN1.EDEEPN) {
 | 
					 | 
				
			||||||
			throw new Error(ASN1.EDEEP);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var index = 2; // we know, at minimum, data starts after type (0) and lengthSize (1)
 | 
					 | 
				
			||||||
		var asn1 = { type: buf[0], lengthSize: 0, length: buf[1] };
 | 
					 | 
				
			||||||
		var child;
 | 
					 | 
				
			||||||
		var iters = 0;
 | 
					 | 
				
			||||||
		var adjust = 0;
 | 
					 | 
				
			||||||
		var adjustedLen;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Determine how many bytes the length uses, and what it is
 | 
					 | 
				
			||||||
		if (0x80 & asn1.length) {
 | 
					 | 
				
			||||||
			asn1.lengthSize = 0x7f & asn1.length;
 | 
					 | 
				
			||||||
			// I think that buf->hex->int solves the problem of Endianness... not sure
 | 
					 | 
				
			||||||
			asn1.length = parseInt(
 | 
					 | 
				
			||||||
				Enc.bufToHex(buf.slice(index, index + asn1.lengthSize)),
 | 
					 | 
				
			||||||
				16
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			index += asn1.lengthSize;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// High-order bit Integers have a leading 0x00 to signify that they are positive.
 | 
					 | 
				
			||||||
		// Bit Streams use the first byte to signify padding, which x.509 doesn't use.
 | 
					 | 
				
			||||||
		if (0x00 === buf[index] && (0x02 === asn1.type || 0x03 === asn1.type)) {
 | 
					 | 
				
			||||||
			// However, 0x00 on its own is a valid number
 | 
					 | 
				
			||||||
			if (asn1.length > 1) {
 | 
					 | 
				
			||||||
				index += 1;
 | 
					 | 
				
			||||||
				adjust = -1;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		adjustedLen = asn1.length + adjust;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		//console.warn(depth.join(ws) + '0x' + Enc.numToHex(asn1.type), index, 'len:', asn1.length, asn1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		function parseChildren(eager) {
 | 
					 | 
				
			||||||
			asn1.children = [];
 | 
					 | 
				
			||||||
			//console.warn('1 len:', (2 + asn1.lengthSize + asn1.length), 'idx:', index, 'clen:', 0);
 | 
					 | 
				
			||||||
			while (
 | 
					 | 
				
			||||||
				iters < ASN1.ELOOPN &&
 | 
					 | 
				
			||||||
				index < 2 + asn1.length + asn1.lengthSize
 | 
					 | 
				
			||||||
			) {
 | 
					 | 
				
			||||||
				iters += 1;
 | 
					 | 
				
			||||||
				depth.length += 1;
 | 
					 | 
				
			||||||
				child = parseAsn1(
 | 
					 | 
				
			||||||
					buf.slice(index, index + adjustedLen),
 | 
					 | 
				
			||||||
					depth,
 | 
					 | 
				
			||||||
					eager
 | 
					 | 
				
			||||||
				);
 | 
					 | 
				
			||||||
				depth.length -= 1;
 | 
					 | 
				
			||||||
				// The numbers don't match up exactly and I don't remember why...
 | 
					 | 
				
			||||||
				// probably something with adjustedLen or some such, but the tests pass
 | 
					 | 
				
			||||||
				index += 2 + child.lengthSize + child.length;
 | 
					 | 
				
			||||||
				//console.warn('2 len:', (2 + asn1.lengthSize + asn1.length), 'idx:', index, 'clen:', (2 + child.lengthSize + child.length));
 | 
					 | 
				
			||||||
				if (index > 2 + asn1.lengthSize + asn1.length) {
 | 
					 | 
				
			||||||
					if (!eager) {
 | 
					 | 
				
			||||||
						console.error(JSON.stringify(asn1, ASN1._replacer, 2));
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					throw new Error(
 | 
					 | 
				
			||||||
						'Parse error: child value length (' +
 | 
					 | 
				
			||||||
							child.length +
 | 
					 | 
				
			||||||
							') is greater than remaining parent length (' +
 | 
					 | 
				
			||||||
							(asn1.length - index) +
 | 
					 | 
				
			||||||
							' = ' +
 | 
					 | 
				
			||||||
							asn1.length +
 | 
					 | 
				
			||||||
							' - ' +
 | 
					 | 
				
			||||||
							index +
 | 
					 | 
				
			||||||
							')'
 | 
					 | 
				
			||||||
					);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				asn1.children.push(child);
 | 
					 | 
				
			||||||
				//console.warn(depth.join(ws) + '0x' + Enc.numToHex(asn1.type), index, 'len:', asn1.length, asn1);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if (index !== 2 + asn1.lengthSize + asn1.length) {
 | 
					 | 
				
			||||||
				//console.warn('index:', index, 'length:', (2 + asn1.lengthSize + asn1.length));
 | 
					 | 
				
			||||||
				throw new Error('premature end-of-file');
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if (iters >= ASN1.ELOOPN) {
 | 
					 | 
				
			||||||
				throw new Error(ASN1.ELOOP);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			delete asn1.value;
 | 
					 | 
				
			||||||
			return asn1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Recurse into types that are _always_ containers
 | 
					 | 
				
			||||||
		if (-1 !== ASN1.CTYPES.indexOf(asn1.type)) {
 | 
					 | 
				
			||||||
			return parseChildren(eager);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Return types that are _always_ values
 | 
					 | 
				
			||||||
		asn1.value = buf.slice(index, index + adjustedLen);
 | 
					 | 
				
			||||||
		if (-1 !== ASN1.VTYPES.indexOf(asn1.type)) {
 | 
					 | 
				
			||||||
			return asn1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// For ambigious / unknown types, recurse and return on failure
 | 
					 | 
				
			||||||
		// (and return child array size to zero)
 | 
					 | 
				
			||||||
		try {
 | 
					 | 
				
			||||||
			return parseChildren(true);
 | 
					 | 
				
			||||||
		} catch (e) {
 | 
					 | 
				
			||||||
			asn1.children.length = 0;
 | 
					 | 
				
			||||||
			return asn1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var asn1 = parseAsn1(buf, []);
 | 
					 | 
				
			||||||
	var len = buf.byteLength || buf.length;
 | 
					 | 
				
			||||||
	if (len !== 2 + asn1.lengthSize + asn1.length) {
 | 
					 | 
				
			||||||
		throw new Error(
 | 
					 | 
				
			||||||
			'Length of buffer does not match length of ASN.1 sequence.'
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return asn1;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
ASN1._replacer = function(k, v) {
 | 
					 | 
				
			||||||
	if ('type' === k) {
 | 
					 | 
				
			||||||
		return '0x' + Enc.numToHex(v);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (v && 'value' === k) {
 | 
					 | 
				
			||||||
		return '0x' + Enc.bufToHex(v.data || v);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return v;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
							
								
								
									
										33
									
								
								pem.js
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								pem.js
									
									
									
									
									
								
							@ -1,33 +0,0 @@
 | 
				
			|||||||
'use strict';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var Enc = require('@root/encoding/base64');
 | 
					 | 
				
			||||||
var PEM = module.exports;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
PEM.packBlock = function(opts) {
 | 
					 | 
				
			||||||
	// TODO allow for headers?
 | 
					 | 
				
			||||||
	return (
 | 
					 | 
				
			||||||
		'-----BEGIN ' +
 | 
					 | 
				
			||||||
		opts.type +
 | 
					 | 
				
			||||||
		'-----\n' +
 | 
					 | 
				
			||||||
		Enc.bufToBase64(opts.bytes)
 | 
					 | 
				
			||||||
			.match(/.{1,64}/g)
 | 
					 | 
				
			||||||
			.join('\n') +
 | 
					 | 
				
			||||||
		'\n' +
 | 
					 | 
				
			||||||
		'-----END ' +
 | 
					 | 
				
			||||||
		opts.type +
 | 
					 | 
				
			||||||
		'-----'
 | 
					 | 
				
			||||||
	);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// don't replace the full parseBlock, if it exists
 | 
					 | 
				
			||||||
PEM.parseBlock =
 | 
					 | 
				
			||||||
	PEM.parseBlock ||
 | 
					 | 
				
			||||||
	function(str) {
 | 
					 | 
				
			||||||
		var der = str
 | 
					 | 
				
			||||||
			.split(/\n/)
 | 
					 | 
				
			||||||
			.filter(function(line) {
 | 
					 | 
				
			||||||
				return !/-----/.test(line);
 | 
					 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
			.join('');
 | 
					 | 
				
			||||||
		return { bytes: Enc.base64ToBuf(der) };
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
							
								
								
									
										347
									
								
								x509.js
									
									
									
									
									
								
							
							
						
						
									
										347
									
								
								x509.js
									
									
									
									
									
								
							@ -1,347 +0,0 @@
 | 
				
			|||||||
'use strict';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var x509 = module.exports;
 | 
					 | 
				
			||||||
var ASN1 = require('./asn1/packer.js');
 | 
					 | 
				
			||||||
var Asn1 = ASN1.Any;
 | 
					 | 
				
			||||||
var UInt = ASN1.UInt;
 | 
					 | 
				
			||||||
var BitStr = ASN1.BitStr;
 | 
					 | 
				
			||||||
var Enc = require('@root/encoding');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 1.2.840.10045.3.1.7
 | 
					 | 
				
			||||||
// prime256v1 (ANSI X9.62 named elliptic curve)
 | 
					 | 
				
			||||||
var OBJ_ID_EC = '06 08 2A8648CE3D030107'.replace(/\s+/g, '').toLowerCase();
 | 
					 | 
				
			||||||
// 1.3.132.0.34
 | 
					 | 
				
			||||||
// secp384r1 (SECG (Certicom) named elliptic curve)
 | 
					 | 
				
			||||||
var OBJ_ID_EC_384 = '06 05 2B81040022'.replace(/\s+/g, '').toLowerCase();
 | 
					 | 
				
			||||||
// 1.2.840.10045.2.1
 | 
					 | 
				
			||||||
// ecPublicKey (ANSI X9.62 public key type)
 | 
					 | 
				
			||||||
var OBJ_ID_EC_PUB = '06 07 2A8648CE3D0201'.replace(/\s+/g, '').toLowerCase();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
x509.parseSec1 = function parseEcOnlyPrivkey(u8, jwk) {
 | 
					 | 
				
			||||||
	var index = 7;
 | 
					 | 
				
			||||||
	var len = 32;
 | 
					 | 
				
			||||||
	var olen = OBJ_ID_EC.length / 2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ('P-384' === jwk.crv) {
 | 
					 | 
				
			||||||
		olen = OBJ_ID_EC_384.length / 2;
 | 
					 | 
				
			||||||
		index = 8;
 | 
					 | 
				
			||||||
		len = 48;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (len !== u8[index - 1]) {
 | 
					 | 
				
			||||||
		throw new Error('Unexpected bitlength ' + len);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// private part is d
 | 
					 | 
				
			||||||
	var d = u8.slice(index, index + len);
 | 
					 | 
				
			||||||
	// compression bit index
 | 
					 | 
				
			||||||
	var ci = index + len + 2 + olen + 2 + 3;
 | 
					 | 
				
			||||||
	var c = u8[ci];
 | 
					 | 
				
			||||||
	var x, y;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (0x04 === c) {
 | 
					 | 
				
			||||||
		y = u8.slice(ci + 1 + len, ci + 1 + len + len);
 | 
					 | 
				
			||||||
	} else if (0x02 !== c) {
 | 
					 | 
				
			||||||
		throw new Error('not a supported EC private key');
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	x = u8.slice(ci + 1, ci + 1 + len);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return {
 | 
					 | 
				
			||||||
		kty: jwk.kty,
 | 
					 | 
				
			||||||
		crv: jwk.crv,
 | 
					 | 
				
			||||||
		d: Enc.bufToUrlBase64(d),
 | 
					 | 
				
			||||||
		//, dh: Enc.bufToHex(d)
 | 
					 | 
				
			||||||
		x: Enc.bufToUrlBase64(x),
 | 
					 | 
				
			||||||
		//, xh: Enc.bufToHex(x)
 | 
					 | 
				
			||||||
		y: Enc.bufToUrlBase64(y)
 | 
					 | 
				
			||||||
		//, yh: Enc.bufToHex(y)
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
x509.packPkcs1 = function(jwk) {
 | 
					 | 
				
			||||||
	var n = UInt(Enc.base64ToHex(jwk.n));
 | 
					 | 
				
			||||||
	var e = UInt(Enc.base64ToHex(jwk.e));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!jwk.d) {
 | 
					 | 
				
			||||||
		return Enc.hexToBuf(Asn1('30', n, e));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return Enc.hexToBuf(
 | 
					 | 
				
			||||||
		Asn1(
 | 
					 | 
				
			||||||
			'30',
 | 
					 | 
				
			||||||
			UInt('00'),
 | 
					 | 
				
			||||||
			n,
 | 
					 | 
				
			||||||
			e,
 | 
					 | 
				
			||||||
			UInt(Enc.base64ToHex(jwk.d)),
 | 
					 | 
				
			||||||
			UInt(Enc.base64ToHex(jwk.p)),
 | 
					 | 
				
			||||||
			UInt(Enc.base64ToHex(jwk.q)),
 | 
					 | 
				
			||||||
			UInt(Enc.base64ToHex(jwk.dp)),
 | 
					 | 
				
			||||||
			UInt(Enc.base64ToHex(jwk.dq)),
 | 
					 | 
				
			||||||
			UInt(Enc.base64ToHex(jwk.qi))
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
	);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
x509.parsePkcs8 = function parseEcPkcs8(u8, jwk) {
 | 
					 | 
				
			||||||
	var index = 24 + OBJ_ID_EC.length / 2;
 | 
					 | 
				
			||||||
	var len = 32;
 | 
					 | 
				
			||||||
	if ('P-384' === jwk.crv) {
 | 
					 | 
				
			||||||
		index = 24 + OBJ_ID_EC_384.length / 2 + 2;
 | 
					 | 
				
			||||||
		len = 48;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	//console.log(index, u8.slice(index));
 | 
					 | 
				
			||||||
	if (0x04 !== u8[index]) {
 | 
					 | 
				
			||||||
		//console.log(jwk);
 | 
					 | 
				
			||||||
		throw new Error('privkey not found');
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var d = u8.slice(index + 2, index + 2 + len);
 | 
					 | 
				
			||||||
	var ci = index + 2 + len + 5;
 | 
					 | 
				
			||||||
	var xi = ci + 1;
 | 
					 | 
				
			||||||
	var x = u8.slice(xi, xi + len);
 | 
					 | 
				
			||||||
	var yi = xi + len;
 | 
					 | 
				
			||||||
	var y;
 | 
					 | 
				
			||||||
	if (0x04 === u8[ci]) {
 | 
					 | 
				
			||||||
		y = u8.slice(yi, yi + len);
 | 
					 | 
				
			||||||
	} else if (0x02 !== u8[ci]) {
 | 
					 | 
				
			||||||
		throw new Error('invalid compression bit (expected 0x04 or 0x02)');
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return {
 | 
					 | 
				
			||||||
		kty: jwk.kty,
 | 
					 | 
				
			||||||
		crv: jwk.crv,
 | 
					 | 
				
			||||||
		d: Enc.bufToUrlBase64(d),
 | 
					 | 
				
			||||||
		//, dh: Enc.bufToHex(d)
 | 
					 | 
				
			||||||
		x: Enc.bufToUrlBase64(x),
 | 
					 | 
				
			||||||
		//, xh: Enc.bufToHex(x)
 | 
					 | 
				
			||||||
		y: Enc.bufToUrlBase64(y)
 | 
					 | 
				
			||||||
		//, yh: Enc.bufToHex(y)
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
x509.parseSpki = function parsePem(u8, jwk) {
 | 
					 | 
				
			||||||
	var ci = 16 + OBJ_ID_EC.length / 2;
 | 
					 | 
				
			||||||
	var len = 32;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ('P-384' === jwk.crv) {
 | 
					 | 
				
			||||||
		ci = 16 + OBJ_ID_EC_384.length / 2;
 | 
					 | 
				
			||||||
		len = 48;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var c = u8[ci];
 | 
					 | 
				
			||||||
	var xi = ci + 1;
 | 
					 | 
				
			||||||
	var x = u8.slice(xi, xi + len);
 | 
					 | 
				
			||||||
	var yi = xi + len;
 | 
					 | 
				
			||||||
	var y;
 | 
					 | 
				
			||||||
	if (0x04 === c) {
 | 
					 | 
				
			||||||
		y = u8.slice(yi, yi + len);
 | 
					 | 
				
			||||||
	} else if (0x02 !== c) {
 | 
					 | 
				
			||||||
		throw new Error('not a supported EC private key');
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return {
 | 
					 | 
				
			||||||
		kty: jwk.kty,
 | 
					 | 
				
			||||||
		crv: jwk.crv,
 | 
					 | 
				
			||||||
		x: Enc.bufToUrlBase64(x),
 | 
					 | 
				
			||||||
		//, xh: Enc.bufToHex(x)
 | 
					 | 
				
			||||||
		y: Enc.bufToUrlBase64(y)
 | 
					 | 
				
			||||||
		//, yh: Enc.bufToHex(y)
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
x509.parsePkix = x509.parseSpki;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
x509.packSec1 = function(jwk) {
 | 
					 | 
				
			||||||
	var d = Enc.base64ToHex(jwk.d);
 | 
					 | 
				
			||||||
	var x = Enc.base64ToHex(jwk.x);
 | 
					 | 
				
			||||||
	var y = Enc.base64ToHex(jwk.y);
 | 
					 | 
				
			||||||
	var objId = 'P-256' === jwk.crv ? OBJ_ID_EC : OBJ_ID_EC_384;
 | 
					 | 
				
			||||||
	return Enc.hexToBuf(
 | 
					 | 
				
			||||||
		Asn1(
 | 
					 | 
				
			||||||
			'30',
 | 
					 | 
				
			||||||
			UInt('01'),
 | 
					 | 
				
			||||||
			Asn1('04', d),
 | 
					 | 
				
			||||||
			Asn1('A0', objId),
 | 
					 | 
				
			||||||
			Asn1('A1', BitStr('04' + x + y))
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
	);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * take a private jwk and creates a der from it
 | 
					 | 
				
			||||||
 * @param {*} jwk
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
x509.packPkcs8 = function(jwk) {
 | 
					 | 
				
			||||||
	if ('RSA' === jwk.kty) {
 | 
					 | 
				
			||||||
		if (!jwk.d) {
 | 
					 | 
				
			||||||
			// Public RSA
 | 
					 | 
				
			||||||
			return Enc.hexToBuf(
 | 
					 | 
				
			||||||
				Asn1(
 | 
					 | 
				
			||||||
					'30',
 | 
					 | 
				
			||||||
					Asn1('30', Asn1('06', '2a864886f70d010101'), Asn1('05')),
 | 
					 | 
				
			||||||
					BitStr(
 | 
					 | 
				
			||||||
						Asn1(
 | 
					 | 
				
			||||||
							'30',
 | 
					 | 
				
			||||||
							UInt(Enc.base64ToHex(jwk.n)),
 | 
					 | 
				
			||||||
							UInt(Enc.base64ToHex(jwk.e))
 | 
					 | 
				
			||||||
						)
 | 
					 | 
				
			||||||
					)
 | 
					 | 
				
			||||||
				)
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Private RSA
 | 
					 | 
				
			||||||
		return Enc.hexToBuf(
 | 
					 | 
				
			||||||
			Asn1(
 | 
					 | 
				
			||||||
				'30',
 | 
					 | 
				
			||||||
				UInt('00'),
 | 
					 | 
				
			||||||
				Asn1('30', Asn1('06', '2a864886f70d010101'), Asn1('05')),
 | 
					 | 
				
			||||||
				Asn1(
 | 
					 | 
				
			||||||
					'04',
 | 
					 | 
				
			||||||
					Asn1(
 | 
					 | 
				
			||||||
						'30',
 | 
					 | 
				
			||||||
						UInt('00'),
 | 
					 | 
				
			||||||
						UInt(Enc.base64ToHex(jwk.n)),
 | 
					 | 
				
			||||||
						UInt(Enc.base64ToHex(jwk.e)),
 | 
					 | 
				
			||||||
						UInt(Enc.base64ToHex(jwk.d)),
 | 
					 | 
				
			||||||
						UInt(Enc.base64ToHex(jwk.p)),
 | 
					 | 
				
			||||||
						UInt(Enc.base64ToHex(jwk.q)),
 | 
					 | 
				
			||||||
						UInt(Enc.base64ToHex(jwk.dp)),
 | 
					 | 
				
			||||||
						UInt(Enc.base64ToHex(jwk.dq)),
 | 
					 | 
				
			||||||
						UInt(Enc.base64ToHex(jwk.qi))
 | 
					 | 
				
			||||||
					)
 | 
					 | 
				
			||||||
				)
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var d = Enc.base64ToHex(jwk.d);
 | 
					 | 
				
			||||||
	var x = Enc.base64ToHex(jwk.x);
 | 
					 | 
				
			||||||
	var y = Enc.base64ToHex(jwk.y);
 | 
					 | 
				
			||||||
	var objId = 'P-256' === jwk.crv ? OBJ_ID_EC : OBJ_ID_EC_384;
 | 
					 | 
				
			||||||
	return Enc.hexToBuf(
 | 
					 | 
				
			||||||
		Asn1(
 | 
					 | 
				
			||||||
			'30',
 | 
					 | 
				
			||||||
			UInt('00'),
 | 
					 | 
				
			||||||
			Asn1('30', OBJ_ID_EC_PUB, objId),
 | 
					 | 
				
			||||||
			Asn1(
 | 
					 | 
				
			||||||
				'04',
 | 
					 | 
				
			||||||
				Asn1(
 | 
					 | 
				
			||||||
					'30',
 | 
					 | 
				
			||||||
					UInt('01'),
 | 
					 | 
				
			||||||
					Asn1('04', d),
 | 
					 | 
				
			||||||
					Asn1('A1', BitStr('04' + x + y))
 | 
					 | 
				
			||||||
				)
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
	);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
x509.packSpki = function(jwk) {
 | 
					 | 
				
			||||||
	if (/EC/i.test(jwk.kty)) {
 | 
					 | 
				
			||||||
		return x509.packSpkiEc(jwk);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return x509.packSpkiRsa(jwk);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
x509.packSpkiRsa = function(jwk) {
 | 
					 | 
				
			||||||
	if (!jwk.d) {
 | 
					 | 
				
			||||||
		// Public RSA
 | 
					 | 
				
			||||||
		return Enc.hexToBuf(
 | 
					 | 
				
			||||||
			Asn1(
 | 
					 | 
				
			||||||
				'30',
 | 
					 | 
				
			||||||
				Asn1('30', Asn1('06', '2a864886f70d010101'), Asn1('05')),
 | 
					 | 
				
			||||||
				BitStr(
 | 
					 | 
				
			||||||
					Asn1(
 | 
					 | 
				
			||||||
						'30',
 | 
					 | 
				
			||||||
						UInt(Enc.base64ToHex(jwk.n)),
 | 
					 | 
				
			||||||
						UInt(Enc.base64ToHex(jwk.e))
 | 
					 | 
				
			||||||
					)
 | 
					 | 
				
			||||||
				)
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Private RSA
 | 
					 | 
				
			||||||
	return Enc.hexToBuf(
 | 
					 | 
				
			||||||
		Asn1(
 | 
					 | 
				
			||||||
			'30',
 | 
					 | 
				
			||||||
			UInt('00'),
 | 
					 | 
				
			||||||
			Asn1('30', Asn1('06', '2a864886f70d010101'), Asn1('05')),
 | 
					 | 
				
			||||||
			Asn1(
 | 
					 | 
				
			||||||
				'04',
 | 
					 | 
				
			||||||
				Asn1(
 | 
					 | 
				
			||||||
					'30',
 | 
					 | 
				
			||||||
					UInt('00'),
 | 
					 | 
				
			||||||
					UInt(Enc.base64ToHex(jwk.n)),
 | 
					 | 
				
			||||||
					UInt(Enc.base64ToHex(jwk.e)),
 | 
					 | 
				
			||||||
					UInt(Enc.base64ToHex(jwk.d)),
 | 
					 | 
				
			||||||
					UInt(Enc.base64ToHex(jwk.p)),
 | 
					 | 
				
			||||||
					UInt(Enc.base64ToHex(jwk.q)),
 | 
					 | 
				
			||||||
					UInt(Enc.base64ToHex(jwk.dp)),
 | 
					 | 
				
			||||||
					UInt(Enc.base64ToHex(jwk.dq)),
 | 
					 | 
				
			||||||
					UInt(Enc.base64ToHex(jwk.qi))
 | 
					 | 
				
			||||||
				)
 | 
					 | 
				
			||||||
			)
 | 
					 | 
				
			||||||
		)
 | 
					 | 
				
			||||||
	);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
x509.packSpkiEc = function(jwk) {
 | 
					 | 
				
			||||||
	var x = Enc.base64ToHex(jwk.x);
 | 
					 | 
				
			||||||
	var y = Enc.base64ToHex(jwk.y);
 | 
					 | 
				
			||||||
	var objId = 'P-256' === jwk.crv ? OBJ_ID_EC : OBJ_ID_EC_384;
 | 
					 | 
				
			||||||
	return Enc.hexToBuf(
 | 
					 | 
				
			||||||
		Asn1('30', Asn1('30', OBJ_ID_EC_PUB, objId), BitStr('04' + x + y))
 | 
					 | 
				
			||||||
	);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
x509.packPkix = x509.packSpki;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
x509.packCsrRsaPublicKey = function(jwk) {
 | 
					 | 
				
			||||||
	// Sequence the key
 | 
					 | 
				
			||||||
	var n = UInt(Enc.base64ToHex(jwk.n));
 | 
					 | 
				
			||||||
	var e = UInt(Enc.base64ToHex(jwk.e));
 | 
					 | 
				
			||||||
	var asn1pub = Asn1('30', n, e);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Add the CSR pub key header
 | 
					 | 
				
			||||||
	return Asn1(
 | 
					 | 
				
			||||||
		'30',
 | 
					 | 
				
			||||||
		Asn1('30', Asn1('06', '2a864886f70d010101'), Asn1('05')),
 | 
					 | 
				
			||||||
		BitStr(asn1pub)
 | 
					 | 
				
			||||||
	);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
x509.packCsrEcPublicKey = function(jwk) {
 | 
					 | 
				
			||||||
	var ecOid = x509._oids[jwk.crv];
 | 
					 | 
				
			||||||
	if (!ecOid) {
 | 
					 | 
				
			||||||
		throw new Error(
 | 
					 | 
				
			||||||
			"Unsupported namedCurve '" +
 | 
					 | 
				
			||||||
				jwk.crv +
 | 
					 | 
				
			||||||
				"'. Supported types are " +
 | 
					 | 
				
			||||||
				Object.keys(x509._oids)
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var cmp = '04'; // 04 == x+y, 02 == x-only
 | 
					 | 
				
			||||||
	var hxy = '';
 | 
					 | 
				
			||||||
	// Placeholder. I'm not even sure if compression should be supported.
 | 
					 | 
				
			||||||
	if (!jwk.y) {
 | 
					 | 
				
			||||||
		cmp = '02';
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	hxy += Enc.base64ToHex(jwk.x);
 | 
					 | 
				
			||||||
	if (jwk.y) {
 | 
					 | 
				
			||||||
		hxy += Enc.base64ToHex(jwk.y);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// 1.2.840.10045.2.1 ecPublicKey
 | 
					 | 
				
			||||||
	return Asn1(
 | 
					 | 
				
			||||||
		'30',
 | 
					 | 
				
			||||||
		Asn1('30', Asn1('06', '2a8648ce3d0201'), Asn1('06', ecOid)),
 | 
					 | 
				
			||||||
		BitStr(cmp + hxy)
 | 
					 | 
				
			||||||
	);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
x509._oids = {
 | 
					 | 
				
			||||||
	// 1.2.840.10045.3.1.7 prime256v1
 | 
					 | 
				
			||||||
	// (ANSI X9.62 named elliptic curve) (06 08 - 2A 86 48 CE 3D 03 01 07)
 | 
					 | 
				
			||||||
	'P-256': '2a8648ce3d030107',
 | 
					 | 
				
			||||||
	// 1.3.132.0.34 P-384 (06 05 - 2B 81 04 00 22)
 | 
					 | 
				
			||||||
	// (SEC 2 recommended EC domain secp256r1)
 | 
					 | 
				
			||||||
	'P-384': '2b81040022'
 | 
					 | 
				
			||||||
	// requires more logic and isn't a recommended standard
 | 
					 | 
				
			||||||
	// 1.3.132.0.35 P-521 (06 05 - 2B 81 04 00 23)
 | 
					 | 
				
			||||||
	// (SEC 2 alternate P-521)
 | 
					 | 
				
			||||||
	//, 'P-521': '2B 81 04 00 23'
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user