|
|
@ -180,14 +180,6 @@ Keypairs.signJws = function (opts) { |
|
|
|
var msg = protected64 + '.' + payload64; |
|
|
|
|
|
|
|
return Keypairs._sign(opts, msg).then(function (buf) { |
|
|
|
/* |
|
|
|
* This will come back into play for CSRs, but not for JOSE |
|
|
|
if ('EC' === opts.jwk.kty) { |
|
|
|
// ECDSA JWT signatures differ from "normal" ECDSA signatures
|
|
|
|
// https://tools.ietf.org/html/rfc7518#section-3.4
|
|
|
|
binsig = convertIfEcdsa(binsig); |
|
|
|
} |
|
|
|
*/ |
|
|
|
var signedMsg = { |
|
|
|
protected: protected64 |
|
|
|
, payload: payload64 |
|
|
@ -212,40 +204,6 @@ Keypairs.signJws = function (opts) { |
|
|
|
} |
|
|
|
}); |
|
|
|
}; |
|
|
|
Keypairs._convertIfEcdsa = function (binsig) { |
|
|
|
// should have asn1 sequence header of 0x30
|
|
|
|
if (0x30 !== binsig[0]) { throw new Error("Impossible EC SHA head marker"); } |
|
|
|
var index = 2; // first ecdsa "R" header byte
|
|
|
|
var len = binsig[1]; |
|
|
|
var lenlen = 0; |
|
|
|
// Seek length of length if length is greater than 127 (i.e. two 512-bit / 64-byte R and S values)
|
|
|
|
if (0x80 & len) { |
|
|
|
lenlen = len - 0x80; // should be exactly 1
|
|
|
|
len = binsig[2]; // should be <= 130 (two 64-bit SHA-512s, plus padding)
|
|
|
|
index += lenlen; |
|
|
|
} |
|
|
|
// should be of BigInt type
|
|
|
|
if (0x02 !== binsig[index]) { throw new Error("Impossible EC SHA R marker"); } |
|
|
|
index += 1; |
|
|
|
|
|
|
|
var rlen = binsig[index]; |
|
|
|
var bits = 32; |
|
|
|
if (rlen > 49) { |
|
|
|
bits = 64; |
|
|
|
} else if (rlen > 33) { |
|
|
|
bits = 48; |
|
|
|
} |
|
|
|
var r = binsig.slice(index + 1, index + 1 + rlen).toString('hex'); |
|
|
|
var slen = binsig[index + 1 + rlen + 1]; // skip header and read length
|
|
|
|
var s = binsig.slice(index + 1 + rlen + 1 + 1).toString('hex'); |
|
|
|
if (2 *slen !== s.length) { throw new Error("Impossible EC SHA S length"); } |
|
|
|
// There may be one byte of padding on either
|
|
|
|
while (r.length < 2*bits) { r = '00' + r; } |
|
|
|
while (s.length < 2*bits) { s = '00' + s; } |
|
|
|
if (2*(bits+1) === r.length) { r = r.slice(2); } |
|
|
|
if (2*(bits+1) === s.length) { s = s.slice(2); } |
|
|
|
return Enc.hexToBuf(r + s); |
|
|
|
}; |
|
|
|
|
|
|
|
Keypairs._sign = function (opts, payload) { |
|
|
|
return Keypairs._import(opts).then(function (privkey) { |
|
|
@ -259,9 +217,12 @@ Keypairs._sign = function (opts, payload) { |
|
|
|
, privkey |
|
|
|
, payload |
|
|
|
).then(function (signature) { |
|
|
|
// convert buffer to urlsafe base64
|
|
|
|
//return Enc.bufToUrlBase64(new Uint8Array(signature));
|
|
|
|
return new Uint8Array(signature); |
|
|
|
signature = new Uint8Array(signature); // ArrayBuffer -> u8
|
|
|
|
// This will come back into play for CSRs, but not for JOSE
|
|
|
|
if ('EC' === opts.jwk.kty && /x509/i.test(opts.format)) { |
|
|
|
signature = Keypairs._ecdsaJoseSigToAsn1Sig(signature); |
|
|
|
} |
|
|
|
return signature; |
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
@ -287,7 +248,6 @@ Keypairs._getName = function (opts) { |
|
|
|
return 'RSASSA-PKCS1-v1_5'; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
Keypairs._import = function (opts) { |
|
|
|
return Promise.resolve().then(function () { |
|
|
|
var ops; |
|
|
@ -316,6 +276,30 @@ Keypairs._import = function (opts) { |
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
|
// ECDSA JOSE / JWS / JWT signatures differ from "normal" ASN1/X509 ECDSA signatures
|
|
|
|
// https://tools.ietf.org/html/rfc7518#section-3.4
|
|
|
|
Keypairs._ecdsaJoseSigToAsn1Sig = function (bufsig) { |
|
|
|
// it's easier to do the manipulation in the browser with an array
|
|
|
|
bufsig = Array.from(bufsig); |
|
|
|
var hlen = bufsig.length / 2; // should be even
|
|
|
|
var r = bufsig.slice(0, hlen); |
|
|
|
var s = bufsig.slice(hlen); |
|
|
|
// unpad positive ints less than 32 bytes wide
|
|
|
|
while (!r[0]) { r = r.slice(1); } |
|
|
|
while (!s[0]) { s = s.slice(1); } |
|
|
|
// pad (or re-pad) ambiguously non-negative BigInts, up to 33 bytes wide
|
|
|
|
if (0x80 & r[0]) { r.unshift(0); } |
|
|
|
if (0x80 & s[0]) { s.unshift(0); } |
|
|
|
|
|
|
|
var len = 2 + r.length + 2 + s.length; |
|
|
|
var head = [0x30]; |
|
|
|
// hard code 0x80 + 1 because it won't be longer than
|
|
|
|
// two SHA512 plus two pad bytes (130 bytes <= 256)
|
|
|
|
if (len >= 0x80) { head.push(0x81); } |
|
|
|
head.push(len); |
|
|
|
|
|
|
|
return Uint8Array.from(head.concat([0x02, r.length], r, [0x02, s.byteLength], s)); |
|
|
|
}; |
|
|
|
|
|
|
|
function setTime(time) { |
|
|
|
if ('number' === typeof time) { return time; } |
|
|
|