forked from coolaj86/eckles.js
		
	
		
			
				
	
	
		
			171 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			171 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| var ASN1 = require('./asn1.js');
 | |
| var Enc = require('./encoding.js');
 | |
| var x509 = module.exports;
 | |
| 
 | |
| // 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.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.hexToUint8(
 | |
|     ASN1('30'
 | |
|     , ASN1.UInt('01')
 | |
|     , ASN1('04', d)
 | |
|     , ASN1('A0', objId)
 | |
|     , ASN1('A1', ASN1.BitStr('04' + x + y)))
 | |
|   );
 | |
| };
 | |
| x509.packPkcs8 = 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.hexToUint8(
 | |
|     ASN1('30'
 | |
|     , ASN1.UInt('00')
 | |
|     , ASN1('30'
 | |
|       , OBJ_ID_EC_PUB
 | |
|       , objId
 | |
|       )
 | |
|     , ASN1('04'
 | |
|       , ASN1('30'
 | |
|         , ASN1.UInt('01')
 | |
|         , ASN1('04', d)
 | |
|         , ASN1('A1', ASN1.BitStr('04' + x + y)))))
 | |
|   );
 | |
| };
 | |
| x509.packSpki = 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.hexToUint8(
 | |
|     ASN1('30'
 | |
|     , ASN1('30'
 | |
|       , OBJ_ID_EC_PUB
 | |
|       , objId
 | |
|       )
 | |
|     , ASN1.BitStr('04' + x + y))
 | |
|   );
 | |
| };
 | |
| x509.packPkix = x509.packSpki;
 |