Skip to content

Commit 4f6e73f

Browse files
authored
Merge commit from fork
GHSA-869p-cjfg-cm3x on v3.x
2 parents 7d4a071 + bd0fea5 commit 4f6e73f

File tree

6 files changed

+146
-6
lines changed

6 files changed

+146
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ node_modules
22
/test/keys
33
/test/*.pem
44
/test/encrypted-key-passphrase
5+
package-lock.json

CHANGELOG.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
11
# Change Log
2+
23
All notable changes to this project will be documented in this file.
34

5+
## [3.2.3]
6+
7+
### Changed
8+
9+
- Fix advisory GHSA-869p-cjfg-cm3x: createSign and createVerify now require
10+
that a non empty secret is provided (via opts.secret, opts.privateKey or opts.key)
11+
when using HMAC algorithms.
12+
- Upgrading JWA version to 1.4.2, adressing a compatibility issue for Node >= 25.
13+
414
## [3.0.0]
15+
516
### Changed
17+
618
- **BREAKING**: `jwt.verify` now requires an `algorithm` parameter, and
719
`jws.createVerify` requires an `algorithm` option. The `"alg"` field
820
signature headers is ignored. This mitigates a critical security flaw
@@ -12,7 +24,9 @@ All notable changes to this project will be documented in this file.
1224
for details.
1325

1426
## [2.0.0] - 2015-01-30
27+
1528
### Changed
29+
1630
- **BREAKING**: Default payload encoding changed from `binary` to
1731
`utf8`. `utf8` is a is a more sensible default than `binary` because
1832
many payloads, as far as I can tell, will contain user-facing
@@ -21,14 +35,13 @@ All notable changes to this project will be documented in this file.
2135
- Code reorganization, thanks [@fearphage]! (<code>[7880050]</code>)
2236

2337
### Added
38+
2439
- Option in all relevant methods for `encoding`. For those few users
2540
that might be depending on a `binary` encoding of the messages, this
2641
is for them. (<code>[6b6de48]</code>)
2742

2843
[unreleased]: https://github.com/brianloveswords/node-jws/compare/v2.0.0...HEAD
2944
[2.0.0]: https://github.com/brianloveswords/node-jws/compare/v1.0.1...v2.0.0
30-
3145
[7880050]: https://github.com/brianloveswords/node-jws/commit/7880050
3246
[6b6de48]: https://github.com/brianloveswords/node-jws/commit/6b6de48
33-
3447
[@fearphage]: https://github.com/fearphage

lib/sign-stream.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,12 @@ function jwsSign(opts) {
3434
}
3535

3636
function SignStream(opts) {
37-
var secret = opts.secret||opts.privateKey||opts.key;
37+
var secret = opts.secret;
38+
secret = secret == null ? opts.privateKey : secret;
39+
secret = secret == null ? opts.key : secret;
40+
if (/^hs/i.test(opts.header.alg) === true && secret == null) {
41+
throw new TypeError('secret must be a string or buffer or a KeyObject')
42+
}
3843
var secretStream = new DataStream(secret);
3944
this.readable = true;
4045
this.header = opts.header;

lib/verify-stream.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,12 @@ function jwsDecode(jwsSig, opts) {
7979

8080
function VerifyStream(opts) {
8181
opts = opts || {};
82-
var secretOrKey = opts.secret||opts.publicKey||opts.key;
82+
var secretOrKey = opts.secret;
83+
secretOrKey = secretOrKey == null ? opts.publicKey : secretOrKey;
84+
secretOrKey = secretOrKey == null ? opts.key : secretOrKey;
85+
if (/^hs/i.test(opts.algorithm) === true && secretOrKey == null) {
86+
throw new TypeError('secret must be a string or buffer or a KeyObject')
87+
}
8388
var secretStream = new DataStream(secretOrKey);
8489
this.readable = true;
8590
this.algorithm = opts.algorithm;

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "jws",
3-
"version": "3.2.2",
3+
"version": "3.2.3",
44
"description": "Implementation of JSON Web Signatures",
55
"main": "index.js",
66
"directories": {
@@ -24,7 +24,7 @@
2424
"readmeFilename": "readme.md",
2525
"gitHead": "c0f6b27bcea5a2ad2e304d91c2e842e4076a6b03",
2626
"dependencies": {
27-
"jwa": "^1.4.1",
27+
"jwa": "^1.4.2",
2828
"safe-buffer": "^5.0.1"
2929
},
3030
"devDependencies": {

test/jws.test.js

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,3 +330,119 @@ test('jws.isValid', function (t) {
330330
t.same(jws.isValid(valid), true);
331331
t.end();
332332
});
333+
334+
test('Streaming sign: HMAC with empty secret buffer', function (t) {
335+
const dataStream = readstream('data.txt');
336+
const secret = Buffer.alloc(0);
337+
const sig = jws.createSign({
338+
header: { alg: 'HS256' },
339+
secret: secret
340+
});
341+
dataStream.pipe(sig.payload);
342+
sig.on('done', function (signature) {
343+
t.ok(jws.verify(signature, 'HS256', secret), 'should verify');
344+
t.end();
345+
}).sign();
346+
});
347+
348+
test('Streaming sign: HMAC with empty secret string', function (t) {
349+
const dataStream = readstream('data.txt');
350+
const secret = '';
351+
const sig = jws.createSign({
352+
header: { alg: 'HS256' },
353+
secret: secret
354+
});
355+
dataStream.pipe(sig.payload);
356+
sig.on('done', function (signature) {
357+
t.ok(jws.verify(signature, 'HS256', secret), 'should verify');
358+
t.end();
359+
}).sign();
360+
});
361+
362+
test('Streaming sign: HMAC with undefined secret', function (t) {
363+
try {
364+
jws.createSign({
365+
header: { alg: 'HS256' },
366+
secret: undefined
367+
});
368+
t.fail('should have errored');
369+
t.end();
370+
} catch (error) {
371+
t.equal(error.name, 'TypeError');
372+
t.equal(error.message, 'secret must be a string or buffer or a KeyObject');
373+
t.end();
374+
}
375+
});
376+
377+
test('Streaming sign: HMAC with null secret', function (t) {
378+
try {
379+
jws.createSign({
380+
header: { alg: 'HS256' },
381+
secret: null
382+
});
383+
t.fail('should have errored');
384+
t.end();
385+
} catch (error) {
386+
t.equal(error.name, 'TypeError');
387+
t.equal(error.message, 'secret must be a string or buffer or a KeyObject');
388+
t.end();
389+
}
390+
});
391+
392+
test('Streaming verify: HMAC with empty secret buffer', function (t) {
393+
const secret = Buffer.alloc(0);
394+
jws.createVerify({
395+
signature: 'eyJhbGciOiJIUzI1NiJ9.b25lLCB0d28sIHRocmVlCg.V1oQ0aq6FgAoe7C2TORtYpQAbYzJoFNFZlJkTlF1e60',
396+
algorithm: 'HS256',
397+
secret: secret
398+
}).on('done', function (valid, decoded) {
399+
t.true(valid);
400+
t.same(decoded.payload, readfile('data.txt'));
401+
t.end();
402+
}).verify();
403+
});
404+
405+
test('Streaming verify: HMAC with empty secret string', function (t) {
406+
const secret = '';
407+
jws.createVerify({
408+
signature: 'eyJhbGciOiJIUzI1NiJ9.b25lLCB0d28sIHRocmVlCg.V1oQ0aq6FgAoe7C2TORtYpQAbYzJoFNFZlJkTlF1e60',
409+
algorithm: 'HS256',
410+
secret: secret
411+
}).on('done', function (valid, decoded) {
412+
t.true(valid);
413+
t.same(decoded.payload, readfile('data.txt'));
414+
t.end();
415+
}).verify();
416+
});
417+
418+
test('Streaming verify: HMAC with undefined secret', function (t) {
419+
try {
420+
jws.createVerify({
421+
signature: 'eyJhbGciOiJIUzI1NiJ9.b25lLCB0d28sIHRocmVlCg.V1oQ0aq6FgAoe7C2TORtYpQAbYzJoFNFZlJkTlF1e60',
422+
algorithm: 'HS256',
423+
secret: undefined
424+
});
425+
t.fail('should have errored');
426+
t.end();
427+
} catch (error) {
428+
t.equal(error.name, 'TypeError');
429+
t.equal(error.message, 'secret must be a string or buffer or a KeyObject');
430+
t.end();
431+
}
432+
});
433+
434+
test('Streaming verify: HMAC with null secret', function (t) {
435+
try {
436+
jws.createVerify({
437+
signature: 'eyJhbGciOiJIUzI1NiJ9.b25lLCB0d28sIHRocmVlCg.V1oQ0aq6FgAoe7C2TORtYpQAbYzJoFNFZlJkTlF1e60',
438+
algorithm: 'HS256',
439+
secret: null
440+
});
441+
t.fail('should have errored');
442+
t.end();
443+
} catch (error) {
444+
t.equal(error.name, 'TypeError');
445+
t.equal(error.message, 'secret must be a string or buffer or a KeyObject');
446+
t.end();
447+
}
448+
});

0 commit comments

Comments
 (0)