2018-11-22 09:09:02 +00:00
|
|
|
'use strict';
|
|
|
|
|
2018-11-22 21:31:53 +00:00
|
|
|
// TODO fun idea: create a template from an existing file
|
|
|
|
|
2018-11-22 09:09:02 +00:00
|
|
|
var x509 = module.exports;
|
2018-11-22 11:32:33 +00:00
|
|
|
var ASN1 = require('./asn1.js');
|
|
|
|
var Enc = require('./encoding.js');
|
2018-11-22 09:09:02 +00:00
|
|
|
|
|
|
|
x509.guess = function (der, asn1) {
|
|
|
|
// accepting der for compatability with other usages
|
|
|
|
|
|
|
|
var meta = { kty: 'RSA', format: 'pkcs1', public: true };
|
|
|
|
//meta.asn1 = ASN1.parse(u8);
|
|
|
|
|
|
|
|
if (asn1.children.every(function(el) {
|
|
|
|
return 0x02 === el.type;
|
|
|
|
})) {
|
|
|
|
if (2 === asn1.children.length) {
|
|
|
|
// rsa pkcs1 public
|
|
|
|
return meta;
|
|
|
|
} else if (asn1.children.length >= 9) {
|
|
|
|
// the standard allows for "otherPrimeInfos", hence at least 9
|
|
|
|
meta.public = false;
|
|
|
|
// rsa pkcs1 private
|
|
|
|
return meta;
|
|
|
|
} else {
|
|
|
|
throw new Error("not an RSA PKCS#1 public or private key (wrong number of ints)");
|
|
|
|
}
|
2018-11-22 09:36:21 +00:00
|
|
|
} else {
|
|
|
|
meta.format = 'pkcs8';
|
2018-11-22 09:09:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return meta;
|
|
|
|
};
|
2018-11-22 11:32:33 +00:00
|
|
|
|
|
|
|
x509.parsePkcs1 = function parseRsaPkcs1(buf, asn1, jwk) {
|
|
|
|
if (!asn1.children.every(function(el) {
|
|
|
|
return 0x02 === el.type;
|
|
|
|
})) {
|
|
|
|
throw new Error("not an RSA PKCS#1 public or private key (not all ints)");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (2 === asn1.children.length) {
|
|
|
|
|
|
|
|
jwk.n = Enc.bufToUrlBase64(asn1.children[0].value);
|
|
|
|
jwk.e = Enc.bufToUrlBase64(asn1.children[1].value);
|
|
|
|
return jwk;
|
|
|
|
|
|
|
|
} else if (asn1.children.length >= 9) {
|
|
|
|
// the standard allows for "otherPrimeInfos", hence at least 9
|
|
|
|
|
|
|
|
jwk.n = Enc.bufToUrlBase64(asn1.children[1].value);
|
|
|
|
jwk.e = Enc.bufToUrlBase64(asn1.children[2].value);
|
|
|
|
jwk.d = Enc.bufToUrlBase64(asn1.children[3].value);
|
|
|
|
jwk.p = Enc.bufToUrlBase64(asn1.children[4].value);
|
|
|
|
jwk.q = Enc.bufToUrlBase64(asn1.children[5].value);
|
|
|
|
jwk.dp = Enc.bufToUrlBase64(asn1.children[6].value);
|
|
|
|
jwk.dq = Enc.bufToUrlBase64(asn1.children[7].value);
|
|
|
|
jwk.qi = Enc.bufToUrlBase64(asn1.children[8].value);
|
|
|
|
return jwk;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
throw new Error("not an RSA PKCS#1 public or private key (wrong number of ints)");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
x509.parsePkcs8 = function parseRsaPkcs8(buf, asn1, jwk) {
|
|
|
|
if (2 === asn1.children.length
|
|
|
|
&& 0x03 === asn1.children[1].type
|
|
|
|
&& 0x30 === asn1.children[1].value[0]) {
|
|
|
|
|
|
|
|
asn1 = ASN1.parse(asn1.children[1].value);
|
|
|
|
jwk.n = Enc.bufToUrlBase64(asn1.children[0].value);
|
|
|
|
jwk.e = Enc.bufToUrlBase64(asn1.children[1].value);
|
|
|
|
|
|
|
|
} else if (3 === asn1.children.length
|
|
|
|
&& 0x04 === asn1.children[2].type
|
|
|
|
&& 0x30 === asn1.children[2].children[0].type
|
|
|
|
&& 0x02 === asn1.children[2].children[0].children[0].type) {
|
|
|
|
|
|
|
|
asn1 = asn1.children[2].children[0];
|
|
|
|
jwk.n = Enc.bufToUrlBase64(asn1.children[1].value);
|
|
|
|
jwk.e = Enc.bufToUrlBase64(asn1.children[2].value);
|
|
|
|
jwk.d = Enc.bufToUrlBase64(asn1.children[3].value);
|
|
|
|
jwk.p = Enc.bufToUrlBase64(asn1.children[4].value);
|
|
|
|
jwk.q = Enc.bufToUrlBase64(asn1.children[5].value);
|
|
|
|
jwk.dp = Enc.bufToUrlBase64(asn1.children[6].value);
|
|
|
|
jwk.dq = Enc.bufToUrlBase64(asn1.children[7].value);
|
|
|
|
jwk.qi = Enc.bufToUrlBase64(asn1.children[8].value);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
throw new Error("not an RSA PKCS#8 public or private key (wrong format)");
|
|
|
|
}
|
|
|
|
return jwk;
|
|
|
|
};
|
2018-11-22 21:31:53 +00:00
|
|
|
|
|
|
|
x509.packPkcs1 = function (jwk) {
|
|
|
|
var n = ASN1.UInt(Enc.base64ToHex(jwk.n));
|
|
|
|
var e = ASN1.UInt(Enc.base64ToHex(jwk.e));
|
|
|
|
|
|
|
|
if (!jwk.d) {
|
|
|
|
return Enc.hexToBuf(ASN1('30', n, e));
|
|
|
|
}
|
|
|
|
|
|
|
|
return Enc.hexToBuf(ASN1('30'
|
|
|
|
, ASN1.UInt('00')
|
|
|
|
, n
|
|
|
|
, e
|
|
|
|
, ASN1.UInt(Enc.base64ToHex(jwk.d))
|
|
|
|
, ASN1.UInt(Enc.base64ToHex(jwk.p))
|
|
|
|
, ASN1.UInt(Enc.base64ToHex(jwk.q))
|
|
|
|
, ASN1.UInt(Enc.base64ToHex(jwk.dp))
|
|
|
|
, ASN1.UInt(Enc.base64ToHex(jwk.dq))
|
|
|
|
, ASN1.UInt(Enc.base64ToHex(jwk.qi))
|
|
|
|
));
|
|
|
|
};
|
2018-11-23 06:41:39 +00:00
|
|
|
|
|
|
|
x509.packPkcs8 = function (jwk) {
|
|
|
|
if (!jwk.d) {
|
|
|
|
// Public RSA
|
|
|
|
return Enc.hexToBuf(ASN1('30'
|
|
|
|
, ASN1('30'
|
|
|
|
, ASN1('06', '2a864886f70d010101')
|
|
|
|
, ASN1('05')
|
|
|
|
)
|
|
|
|
, ASN1.BitStr(ASN1('30'
|
|
|
|
, ASN1.UInt(Enc.base64ToHex(jwk.n))
|
|
|
|
, ASN1.UInt(Enc.base64ToHex(jwk.e))
|
|
|
|
))
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Private RSA
|
|
|
|
return Enc.hexToBuf(ASN1('30'
|
|
|
|
, ASN1.UInt('00')
|
|
|
|
, ASN1('30'
|
|
|
|
, ASN1('06', '2a864886f70d010101')
|
|
|
|
, ASN1('05')
|
|
|
|
)
|
|
|
|
, ASN1('04'
|
|
|
|
, ASN1('30'
|
|
|
|
, ASN1.UInt('00')
|
|
|
|
, ASN1.UInt(Enc.base64ToHex(jwk.n))
|
|
|
|
, ASN1.UInt(Enc.base64ToHex(jwk.e))
|
|
|
|
, ASN1.UInt(Enc.base64ToHex(jwk.d))
|
|
|
|
, ASN1.UInt(Enc.base64ToHex(jwk.p))
|
|
|
|
, ASN1.UInt(Enc.base64ToHex(jwk.q))
|
|
|
|
, ASN1.UInt(Enc.base64ToHex(jwk.dp))
|
|
|
|
, ASN1.UInt(Enc.base64ToHex(jwk.dq))
|
|
|
|
, ASN1.UInt(Enc.base64ToHex(jwk.qi))
|
|
|
|
)
|
|
|
|
)
|
|
|
|
));
|
|
|
|
};
|
|
|
|
x509.packSpki = x509.packPkcs8;
|