Skip to content

Commit

Permalink
Merge 8dcc2c1 into 5423b70
Browse files Browse the repository at this point in the history
  • Loading branch information
omsmith committed Nov 6, 2015
2 parents 5423b70 + 8dcc2c1 commit 5b72263
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 19 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
},
"homepage": "https://github.com/Brightspace/node-ecdsa-sig-formatter#readme",
"dependencies": {
"asn1.js": "^2.0.3",
"base64-url": "^1.2.1"
},
"devDependencies": {
Expand Down
29 changes: 29 additions & 0 deletions spec/der-to-jose.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ var describe = mocha.describe,

var format = require('..');

var MAX_LENGTH_OCTET = 0x80,
CLASS_UNIVERSAL = 0,
PRIMITIVE_BIT = 0x20,
TAG_SEQ = (0x10 | PRIMITIVE_BIT) | (CLASS_UNIVERSAL << 6),
TAG_INT = 0x02 | (CLASS_UNIVERSAL << 6);

describe('#derToJose', function () {
describe('should throw for', function () {
it('no signature', function () {
Expand All @@ -33,5 +39,28 @@ describe('#derToJose', function () {

expect(fn).to.throw(/"foozleberries"/);
});

it('no seq', function () {
var input = new Buffer(10);
input[0] = TAG_SEQ + 1; // not seq

function fn () {
format.derToJose(input, 'ES256');
}

expect(fn).to.throw(Error);
});

it('seq length exceeding input', function () {
var input = new Buffer(10);
input[0] = TAG_SEQ;
input[1] = 10;

function fn () {
format.derToJose(input, 'ES256');
}

expect(fn).to.throw(Error);
});
});
});
78 changes: 60 additions & 18 deletions src/ecdsa-sig-formatter.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
'use strict';

var asn1 = require('asn1.js'),
base64Url = require('base64-url').escape;

var ECDSASigValue = asn1.define('ECDSASigValue', function () {
this.seq().obj(
this.key('r').int(),
this.key('s').int()
);
});
var base64Url = require('base64-url').escape;

var MAX_OCTET = 0x80,
CLASS_UNIVERSAL = 0,
Expand Down Expand Up @@ -38,11 +30,6 @@ function getParamBytesForAlg (alg) {
throw new Error('Unknown algorithm "' + alg + '"');
}

function bignumToBuf (bn, numBytes) {
var buf = new Buffer(bn.toString('hex', numBytes), 'hex');
return buf;
}

function signatureAsBuffer (signature) {
if (Buffer.isBuffer(signature)) {
return signature;
Expand All @@ -57,14 +44,69 @@ function derToJose(signature, alg) {
signature = signatureAsBuffer(signature);
var paramBytes = getParamBytesForAlg(alg);

var inputLength = signature.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');
}

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) + '"');
}

signature = ECDSASigValue.decode(signature, 'der');
var s = signature.slice(offset);
offset += s.length;

var r = bignumToBuf(signature.r, paramBytes);
var s = bignumToBuf(signature.s, paramBytes);
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 = Buffer.concat([r, s], r.length + s.length);
signature = signature.toString('base64');
signature = base64Url(signature);

Expand Down

0 comments on commit 5b72263

Please sign in to comment.