ecdsa-sig-formatter
Advanced tools
Comparing version 1.0.2 to 1.0.5
{ | ||
"name": "ecdsa-sig-formatter", | ||
"version": "1.0.2", | ||
"version": "1.0.5", | ||
"description": "Translate ECDSA signatures between ASN.1/DER and JOSE-style concatenation", | ||
"main": "src/ecdsa-sig-formatter.js", | ||
"scripts": { | ||
"check-style": "eslint .", | ||
"pretest": "npm run check-style", | ||
"test": "istanbul cover --root src _mocha -- spec", | ||
@@ -30,12 +32,15 @@ "report-cov": "cat ./coverage/lcov.info | coveralls" | ||
"dependencies": { | ||
"asn1.js": "^2.0.3", | ||
"base64-url": "^1.2.1" | ||
}, | ||
"devDependencies": { | ||
"bench": "^0.3.5", | ||
"chai": "^3.0.0", | ||
"coveralls": "^2.11.2", | ||
"istanbul": "^0.3.15", | ||
"mocha": "^2.2.5" | ||
"bench": "^0.3.6", | ||
"chai": "^3.4.1", | ||
"coveralls": "^2.11.6", | ||
"elliptic": "^6.1.0", | ||
"eslint": "^1.10.3", | ||
"eslint-config-brightspace": "^0.1.0", | ||
"istanbul": "^0.4.2", | ||
"jwk-to-pem": "^1.2.4", | ||
"mocha": "^2.3.4" | ||
} | ||
} |
@@ -61,7 +61,6 @@ # ecdsa-sig-formatter | ||
This repository is configured with [EditorConfig][EditorConfig], [jscs][jscs] | ||
and [JSHint][JSHint] rules. | ||
This repository is configured with [EditorConfig][EditorConfig] and | ||
[ESLint][ESLint] rules. | ||
[EditorConfig]: http://editorconfig.org/ | ||
[jscs]: http://jscs.info/ | ||
[JSHint]: http://jshint.com/ | ||
[ESLint]: http://eslint.org |
'use strict'; | ||
var asn1 = require('asn1.js'), | ||
base64Url = require('base64-url').escape; | ||
var base64Url = require('base64-url').escape; | ||
var ECDSASigValue = asn1.define('ECDSASigValue', function () { | ||
this.seq().obj( | ||
this.key('r').int(), | ||
this.key('s').int() | ||
); | ||
}); | ||
var getParamBytesForAlg = require('./param-bytes-for-alg'); | ||
var seq = 0x10, | ||
int = 0x02; | ||
var MAX_OCTET = 0x80, | ||
CLASS_UNIVERSAL = 0, | ||
PRIMITIVE_BIT = 0x20, | ||
TAG_SEQ = 0x10, | ||
TAG_INT = 0x02, | ||
ENCODED_TAG_SEQ = (TAG_SEQ | PRIMITIVE_BIT) | (CLASS_UNIVERSAL << 6), | ||
ENCODED_TAG_INT = TAG_INT | (CLASS_UNIVERSAL << 6); | ||
function getParamSize (keySize) { | ||
var result = ((keySize / 8) | 0) + (keySize % 8 === 0 ? 0 : 1); | ||
return result; | ||
} | ||
var paramBytesForAlg = { | ||
ES256: getParamSize(256), | ||
ES384: getParamSize(384), | ||
ES512: getParamSize(521) | ||
}; | ||
function getParamBytesForAlg (alg) { | ||
var paramBytes = paramBytesForAlg[alg]; | ||
if (paramBytes) { | ||
return paramBytes; | ||
} | ||
throw new Error('Unknown algorithm "' + alg + '"'); | ||
} | ||
function bignumToBuf (bn, numBytes) { | ||
var buf = new Buffer(bn.toString('hex', numBytes), 'hex'); | ||
return buf; | ||
} | ||
function signatureAsBuffer (signature) { | ||
function signatureAsBuffer(signature) { | ||
if (Buffer.isBuffer(signature)) { | ||
return new Buffer(signature); | ||
return signature; | ||
} else if ('string' === typeof signature) { | ||
@@ -55,8 +29,77 @@ return new Buffer(signature, 'base64'); | ||
signature = ECDSASigValue.decode(signature, 'der'); | ||
// the DER encoded param should at most be the param size, plus a padding | ||
// zero, since due to being a signed integer | ||
var maxEncodedParamLength = paramBytes + 1; | ||
var r = bignumToBuf(signature.r, paramBytes); | ||
var s = bignumToBuf(signature.s, paramBytes); | ||
var inputLength = signature.length; | ||
signature = Buffer.concat([r, s], r.length + s.length); | ||
var offset = 0; | ||
if (signature[offset++] !== ENCODED_TAG_SEQ) { | ||
throw new Error('Could not find expected "seq"'); | ||
} | ||
var seqLength = signature[offset++]; | ||
if (seqLength === (MAX_OCTET | 1)) { | ||
seqLength = signature[offset++]; | ||
} | ||
if (inputLength - offset < seqLength) { | ||
throw new Error('"seq" specified length of "' + seqLength + '", only "' + (inputLength - offset) + '" remaining'); | ||
} | ||
if (signature[offset++] !== ENCODED_TAG_INT) { | ||
throw new Error('Could not find expected "int" for "r"'); | ||
} | ||
var rLength = signature[offset++]; | ||
if (inputLength - offset - 2 < rLength) { | ||
throw new Error('"r" specified length of "' + rLength + '", only "' + (inputLength - offset - 2) + '" available'); | ||
} | ||
if (maxEncodedParamLength < rLength) { | ||
throw new Error('"r" specified length of "' + rLength + '", max of "' + maxEncodedParamLength + '" is acceptable'); | ||
} | ||
var r = signature.slice(offset, offset + rLength); | ||
offset += r.length; | ||
if (signature[offset++] !== ENCODED_TAG_INT) { | ||
throw new Error('Could not find expected "int" for "s"'); | ||
} | ||
var sLength = signature[offset++]; | ||
if (inputLength - offset !== sLength) { | ||
throw new Error('"s" specified length of "' + sLength + '", expected "' + (inputLength - offset) + '"'); | ||
} | ||
if (maxEncodedParamLength < sLength) { | ||
throw new Error('"s" specified length of "' + sLength + '", max of "' + maxEncodedParamLength + '" is acceptable'); | ||
} | ||
var s = signature.slice(offset); | ||
offset += s.length; | ||
if (offset !== inputLength) { | ||
throw new Error('Expected to consume entire buffer, but "' + (inputLength - offset) + '" bytes remain'); | ||
} | ||
var rPadding = paramBytes - r.length, | ||
sPadding = paramBytes - s.length; | ||
signature = new Buffer(rPadding + r.length + sPadding + s.length); | ||
for (offset = 0; offset < rPadding; ++offset) { | ||
signature[offset] = 0; | ||
} | ||
r.copy(signature, offset, Math.max(-rPadding, 0)); | ||
offset = paramBytes; | ||
for (var o = offset; offset < o + sPadding; ++offset) { | ||
signature[offset] = 0; | ||
} | ||
s.copy(signature, offset, Math.max(-sPadding, 0)); | ||
signature = signature.toString('base64'); | ||
@@ -68,3 +111,3 @@ signature = base64Url(signature); | ||
function reduceBuffer (buf) { | ||
function reduceBuffer(buf) { | ||
var padding = 0; | ||
@@ -75,3 +118,3 @@ for (var n = buf.length; padding < n && buf[padding] === 0;) { | ||
var needsSign = buf[padding] >= 0x80; | ||
var needsSign = buf[padding] >= MAX_OCTET; | ||
if (needsSign) { | ||
@@ -112,19 +155,24 @@ --padding; | ||
var oneByteLength = rsBytes < 0x80; | ||
var shortLength = rsBytes < MAX_OCTET; | ||
signature = new Buffer((oneByteLength ? 2 : 3) + rsBytes); | ||
signature = new Buffer((shortLength ? 2 : 3) + rsBytes); | ||
var offset = 0; | ||
signature[offset++] = (seq | 0x20) | 0 << 6; | ||
if (oneByteLength) { | ||
signature[offset++] = ENCODED_TAG_SEQ; | ||
if (shortLength) { | ||
// Bit 8 has value "0" | ||
// bits 7-1 give the length. | ||
signature[offset++] = rsBytes; | ||
} else { | ||
signature[offset++] = 0x80 | 1; | ||
// Bit 8 of first octet has value "1" | ||
// bits 7-1 give the number of additional length octets. | ||
signature[offset++] = MAX_OCTET | 1; | ||
// length, base 256 | ||
signature[offset++] = rsBytes & 0xff; | ||
} | ||
signature[offset++] = int | (0 << 6); | ||
signature[offset++] = ENCODED_TAG_INT; | ||
signature[offset++] = r.length; | ||
r.copy(signature, offset); | ||
offset += r.length; | ||
signature[offset++] = int | (0 << 6); | ||
signature[offset++] = ENCODED_TAG_INT; | ||
signature[offset++] = s.length; | ||
@@ -131,0 +179,0 @@ s.copy(signature, offset); |
19617
1
157
9
5
66
- Removedasn1.js@^2.0.3
- Removedasn1.js@2.2.1(transitive)
- Removedbn.js@2.2.0(transitive)
- Removedinherits@2.0.4(transitive)
- Removedminimalistic-assert@1.0.1(transitive)