diff --git a/lib/ecdsacsr.js b/lib/ecdsacsr.js index b4fe82d..729854d 100644 --- a/lib/ecdsacsr.js +++ b/lib/ecdsacsr.js @@ -6,6 +6,55 @@ var crypto = require('crypto'); // prime256v1 (ANSI X9.62 named elliptic curve) var OBJ_ID_EC = '06 08 2A8648CE3D030107'.replace(/\s+/g, '').toLowerCase(); +function ANY() { + var args = Array.prototype.slice.call(arguments); + var typ = args.shift(); + var str = args.join('').replace(/\s+/g, ''); + console.log('typ:', typ, 'str:', str); + var len = (str.length/2); + var len2 = len; + var lenlen = 1; + var hex = typ; + // high-order bit means multiple bytes + if (len2 !== Math.round(len2)) { + throw new Error("invalid hex"); + } + console.log(len); + if (0x80 & len) { + while (len2 > 127) { lenlen += 1; len2 = len2 >> 8; } + hex += numToHex(0x80 + lenlen); + } + return hex + numToHex(len) + str; +} + +function UINT() { + var str = Array.prototype.slice.call(arguments).join(''); + var first = parseInt(str.slice(0, 2), 16); + // high-order bit means signed, negative + // we want positive, so we pad with a leading '00' + if (0x80 & first) { str = '00' + str; } + return ANY('02', str); +} + +function BITSTR() { + var str = Array.prototype.slice.call(arguments).join(''); + var first = parseInt(str.slice(0, 2), 16); + // '00' is a mask of how many bits of the next byte to ignore + return ANY('03', '00' + str); +} +function SEQ() { + return ANY('30', Array.prototype.slice.call(arguments).join('')); +} +function SET() { + return ANY('31', Array.prototype.slice.call(arguments).join('')); +} +function OBJID() { + return ANY('06', Array.prototype.slice.call(arguments).join('')); +} +function NULL() { + return '0500'; +} + function fromBase64(b64) { var buf; var ab; @@ -144,16 +193,22 @@ function toBase64(der) { // (those segments will be content, signature header, and signature) var csrHead = '30 82 {0seq0len}'.replace(/\s+/g, ''); // The tail specifies the ES256 signature header (and is followed by the signature -var csrEcFoot = - ( '30 0A' + +function csrEcSig(r, s) { + return [ + SEQ( // 1.2.840.10045.4.3.2 ecdsaWithSHA256 // (ANSI X9.62 ECDSA algorithm with SHA256) - + '06 08 2A 86 48 CE 3D 04 03 02' - + '03 {len} 00' // bit stream (why??) - + '30 {rslen}' // sequence - + '02 {rlen} {r}' // integer r - + '02 {slen} {s}' // integer s - ).replace(/\s+/g, ''); + OBJID('2A 86 48 CE 3D 04 03 02') + ) + , BITSTR( + SEQ( + UINT(toHex(r)) + , UINT(toHex(s)) + ) + ) + ].join(''); +} var csrDomains = '82 {dlen} {domain.tld}'; // 2+n bytes (type 82?) function strToHex(str) { @@ -329,7 +384,8 @@ function createEcCsr(domains, keypem, ecpub) { if (0x80 & new Uint8Array(sig.r)[0]) { rc = '00'; rLen += 1; } if (0x80 & new Uint8Array(sig.s)[0]) { sc = '00'; sLen += 1; } - var csrSig = csrEcFoot + var csrSig = csrEcSig(sig.r, sig.s); + /* .replace(/{len}/, numToHex(1 + 2 + 2 + 2 + rLen + sLen)) .replace(/{rslen}/, numToHex(2 + 2 + rLen + sLen)) .replace(/{rlen}/, numToHex(rLen)) @@ -337,6 +393,7 @@ function createEcCsr(domains, keypem, ecpub) { .replace(/{slen}/, numToHex(sLen)) .replace(/{s}/, sc + toHex(sig.s)) ; + */ // Note: If we supported P-521 a number of the lengths would change // by one byte and that would be... annoying to update