jws
Advanced tools
Comparing version 2.0.0 to 3.0.0
# Change Log | ||
All notable changes to this project will be documented in this file. | ||
## [3.0.0] | ||
### Changed | ||
- **BREAKING**: `jwt.verify` now requires an `algorithm` parameter, and | ||
`jws.createVerify` requires an `algorithm` option. The `"alg"` field | ||
signature headers is ignored. This mitigates a critical security flaw | ||
in the library which would allow an attacker to generate signatures with | ||
arbitrary contents that would be accepted by `jwt.verify`. See | ||
https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/ | ||
for details. | ||
## [2.0.0] - 2015-01-30 | ||
@@ -19,3 +29,3 @@ ### Changed | ||
[unreleased]: https://github.com/brianloveswords/node-jws/compare/v2.0.0...HEAD | ||
[2.0.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v2.0.0...v1.0.1 | ||
[2.0.0]: https://github.com/brianloveswords/node-jws/compare/v1.0.1...v2.0.0 | ||
@@ -22,0 +32,0 @@ [7880050]: https://github.com/brianloveswords/node-jws/commit/7880050 |
@@ -30,21 +30,2 @@ /*global module*/ | ||
function algoFromJWS(jwsSig) { | ||
var err; | ||
const header = headerFromJWS(jwsSig); | ||
if (typeof header != 'object') { | ||
err = new Error("Invalid token: no header in signature '" + jwsSig + "'"); | ||
err.code = "MISSING_HEADER"; | ||
err.signature = jwsSig; | ||
throw err; | ||
} | ||
if (!header.alg) { | ||
err = new Error("Missing `alg` field in header for signature '"+ jwsSig +"'"); | ||
err.code = "MISSING_ALGORITHM"; | ||
err.header = header; | ||
err.signature = jwsSig; | ||
throw err; | ||
} | ||
return header.alg; | ||
} | ||
function signatureFromJWS(jwsSig) { | ||
@@ -64,7 +45,12 @@ return jwsSig.split('.')[2]; | ||
function jwsVerify(jwsSig, secretOrKey) { | ||
function jwsVerify(jwsSig, algorithm, secretOrKey) { | ||
if (!algorithm) { | ||
var err = new Error("Missing algorithm parameter for jws.verify"); | ||
err.code = "MISSING_ALGORITHM"; | ||
throw err; | ||
} | ||
jwsSig = toString(jwsSig); | ||
const signature = signatureFromJWS(jwsSig); | ||
const securedInput = securedInputFromJWS(jwsSig); | ||
const algo = jwa(algoFromJWS(jwsSig)); | ||
const algo = jwa(algorithm); | ||
return algo.verify(securedInput, signature, secretOrKey); | ||
@@ -101,2 +87,3 @@ } | ||
this.readable = true; | ||
this.algorithm = opts.algorithm; | ||
this.encoding = opts.encoding; | ||
@@ -117,3 +104,3 @@ this.secret = this.publicKey = this.key = secretStream; | ||
VerifyStream.prototype.verify = function verify() { | ||
const valid = jwsVerify(this.signature.buffer, this.key.buffer); | ||
const valid = jwsVerify(this.signature.buffer, this.algorithm, this.key.buffer); | ||
const obj = jwsDecode(this.signature.buffer, this.encoding); | ||
@@ -120,0 +107,0 @@ this.emit('done', valid, obj); |
{ | ||
"name": "jws", | ||
"version": "2.0.0", | ||
"version": "3.0.0", | ||
"description": "Implementation of JSON Web Signatures", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -49,3 +49,4 @@ /*global process*/ | ||
test('HMAC using SHA-'+bits+' hash algorithm', function (t) { | ||
const header = { alg: 'HS'+bits, typ: 'JWT' }; | ||
const alg = 'HS'+bits; | ||
const header = { alg: alg, typ: 'JWT' }; | ||
const secret = 'sup'; | ||
@@ -59,4 +60,5 @@ const jwsObj = jws.sign({ | ||
const parts = jws.decode(jwsObj); | ||
t.ok(jws.verify(jwsObj, secret), 'should verify'); | ||
t.notOk(jws.verify(jwsObj, 'something else'), 'should not verify'); | ||
t.ok(jws.verify(jwsObj, alg, secret), 'should verify'); | ||
t.notOk(jws.verify(jwsObj, alg, 'something else'), 'should not verify with non-matching secret'); | ||
t.notOk(jws.verify(jwsObj, 'RS'+bits, secret), 'should not verify with non-matching algorithm'); | ||
t.same(parts.payload, payload, 'should match payload'); | ||
@@ -70,3 +72,4 @@ t.same(parts.header, header, 'should match header'); | ||
test('RSASSA using SHA-'+bits+' hash algorithm', function (t) { | ||
const header = { alg: 'RS'+bits }; | ||
const alg = 'RS'+bits; | ||
const header = { alg: alg }; | ||
const privateKey = rsaPrivateKey; | ||
@@ -81,4 +84,5 @@ const publicKey = rsaPublicKey; | ||
const parts = jws.decode(jwsObj, { json: true }); | ||
t.ok(jws.verify(jwsObj, publicKey), 'should verify'); | ||
t.notOk(jws.verify(jwsObj, wrongPublicKey), 'should not verify'); | ||
t.ok(jws.verify(jwsObj, alg, publicKey), 'should verify'); | ||
t.notOk(jws.verify(jwsObj, alg, wrongPublicKey), 'should not verify with non-matching public key'); | ||
t.notOk(jws.verify(jwsObj, 'HS'+bits, publicKey), 'should not verify with non-matching algorithm'); | ||
t.same(parts.payload, payload, 'should match payload'); | ||
@@ -93,3 +97,4 @@ t.same(parts.header, header, 'should match header'); | ||
test('ECDSA using P-'+curve+' curve and SHA-'+bits+' hash algorithm', function (t) { | ||
const header = { alg: 'ES'+bits }; | ||
const alg = 'ES'+bits; | ||
const header = { alg: alg }; | ||
const privateKey = ecdsaPrivateKey['256']; | ||
@@ -104,4 +109,5 @@ const publicKey = ecdsaPublicKey['256']; | ||
const parts = jws.decode(jwsObj); | ||
t.ok(jws.verify(jwsObj, publicKey), 'should verify'); | ||
t.notOk(jws.verify(jwsObj, wrongPublicKey), 'should not verify'); | ||
t.ok(jws.verify(jwsObj, alg, publicKey), 'should verify'); | ||
t.notOk(jws.verify(jwsObj, alg, wrongPublicKey), 'should not verify with non-matching public key'); | ||
t.notOk(jws.verify(jwsObj, 'HS'+bits, publicKey), 'should not verify with non-matching algorithm'); | ||
t.same(parts.payload, payloadString, 'should match payload'); | ||
@@ -114,3 +120,4 @@ t.same(parts.header, header, 'should match header'); | ||
test('No digital signature or MAC value included', function (t) { | ||
const header = { alg: 'none' }; | ||
const alg = 'none'; | ||
const header = { alg: alg }; | ||
const payload = 'oh hey José!'; | ||
@@ -122,4 +129,5 @@ const jwsObj = jws.sign({ | ||
const parts = jws.decode(jwsObj); | ||
t.ok(jws.verify(jwsObj), 'should verify'); | ||
t.ok(jws.verify(jwsObj, 'anything'), 'should still verify'); | ||
t.ok(jws.verify(jwsObj, alg), 'should verify'); | ||
t.ok(jws.verify(jwsObj, alg, 'anything'), 'should still verify'); | ||
t.notOk(jws.verify(jwsObj, 'HS256', 'anything'), 'should not verify with non-matching algorithm'); | ||
t.same(parts.payload, payload, 'should match payload'); | ||
@@ -139,3 +147,3 @@ t.same(parts.header, header, 'should match header'); | ||
sig.on('done', function (signature) { | ||
t.ok(jws.verify(signature, secret), 'should verify'); | ||
t.ok(jws.verify(signature, 'HS256', secret), 'should verify'); | ||
t.end(); | ||
@@ -160,4 +168,4 @@ }); | ||
sig.on('done', function (signature) { | ||
t.ok(jws.verify(signature, publicKey), 'should verify'); | ||
t.notOk(jws.verify(signature, wrongPublicKey), 'should not verify'); | ||
t.ok(jws.verify(signature, 'RS256', publicKey), 'should verify'); | ||
t.notOk(jws.verify(signature, 'RS256', wrongPublicKey), 'should not verify'); | ||
t.same(jws.decode(signature).payload, readfile('data.txt'), 'got all the data'); | ||
@@ -179,4 +187,4 @@ t.end(); | ||
sig.on('done', function (signature) { | ||
t.ok(jws.verify(signature, publicKey), 'should verify'); | ||
t.notOk(jws.verify(signature, wrongPublicKey), 'should not verify'); | ||
t.ok(jws.verify(signature, 'RS256', publicKey), 'should verify'); | ||
t.notOk(jws.verify(signature, 'RS256', wrongPublicKey), 'should not verify'); | ||
t.same(jws.decode(signature).payload, readfile('data.txt'), 'got all the data'); | ||
@@ -196,3 +204,3 @@ t.end(); | ||
}); | ||
const verifier = jws.createVerify(); | ||
const verifier = jws.createVerify({algorithm: 'ES512'}); | ||
sigStream.pipe(verifier.signature); | ||
@@ -216,2 +224,3 @@ publicKeyStream.pipe(verifier.key); | ||
const verifier = jws.createVerify({ | ||
algorithm: 'ES512', | ||
signature: sigStream, | ||
@@ -241,10 +250,14 @@ publicKey: publicKeyStream, | ||
test('jws.decode: missing algo in header', function (t) { | ||
test('jws.verify: missing or invalid algorithm', function (t) { | ||
const header = Buffer('{"something":"not an algo"}').toString('base64'); | ||
const payload = Buffer('sup').toString('base64'); | ||
const sig = header + '.' + payload + '.'; | ||
try { jws.verify(sig, 'whatever') } | ||
try { jws.verify(sig) } | ||
catch (e) { | ||
t.same(e.code, 'MISSING_ALGORITHM'); | ||
} | ||
try { jws.verify(sig, 'whatever') } | ||
catch (e) { | ||
t.ok(e.message.match('"whatever" is not a valid algorithm.')); | ||
} | ||
t.end(); | ||
@@ -251,0 +264,0 @@ }); |
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
26880
459
0
245