Skip to content

Commit 34c45b2

Browse files
authored
Merge commit from fork
GHSA-869p-cjfg-cm3x on main branch
2 parents b9fb8d3 + 49bc39b commit 34c45b2

File tree

6 files changed

+155
-6
lines changed

6 files changed

+155
-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: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,29 @@
11
# Change Log
2+
23
All notable changes to this project will be documented in this file.
34

5+
## [4.0.1]
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 2.0.1, adressing a compatibility issue for Node >= 25.
13+
14+
## [3.2.3]
15+
16+
### Changed
17+
18+
- Fix advisory GHSA-869p-cjfg-cm3x: createSign and createVerify now require
19+
that a non empty secret is provided (via opts.secret, opts.privateKey or opts.key)
20+
when using HMAC algorithms.
21+
- Upgrading JWA version to 1.4.2, adressing a compatibility issue for Node >= 25.
22+
423
## [3.0.0]
24+
525
### Changed
26+
627
- **BREAKING**: `jwt.verify` now requires an `algorithm` parameter, and
728
`jws.createVerify` requires an `algorithm` option. The `"alg"` field
829
signature headers is ignored. This mitigates a critical security flaw
@@ -12,7 +33,9 @@ All notable changes to this project will be documented in this file.
1233
for details.
1334

1435
## [2.0.0] - 2015-01-30
36+
1537
### Changed
38+
1639
- **BREAKING**: Default payload encoding changed from `binary` to
1740
`utf8`. `utf8` is a is a more sensible default than `binary` because
1841
many payloads, as far as I can tell, will contain user-facing
@@ -21,14 +44,13 @@ All notable changes to this project will be documented in this file.
2144
- Code reorganization, thanks [@fearphage]! (<code>[7880050]</code>)
2245

2346
### Added
47+
2448
- Option in all relevant methods for `encoding`. For those few users
2549
that might be depending on a `binary` encoding of the messages, this
2650
is for them. (<code>[6b6de48]</code>)
2751

2852
[unreleased]: https://github.com/brianloveswords/node-jws/compare/v2.0.0...HEAD
2953
[2.0.0]: https://github.com/brianloveswords/node-jws/compare/v1.0.1...v2.0.0
30-
3154
[7880050]: https://github.com/brianloveswords/node-jws/commit/7880050
3255
[6b6de48]: https://github.com/brianloveswords/node-jws/commit/6b6de48
33-
3456
[@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": "4.0.0",
3+
"version": "4.0.1",
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": "^2.0.0",
27+
"jwa": "^2.0.1",
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
@@ -329,3 +329,119 @@ test('jws.isValid', function (t) {
329329
t.same(jws.isValid(valid), true);
330330
t.end();
331331
});
332+
333+
test('Streaming sign: HMAC with empty secret buffer', function (t) {
334+
const dataStream = readstream('data.txt');
335+
const secret = Buffer.alloc(0);
336+
const sig = jws.createSign({
337+
header: { alg: 'HS256' },
338+
secret: secret
339+
});
340+
dataStream.pipe(sig.payload);
341+
sig.on('done', function (signature) {
342+
t.ok(jws.verify(signature, 'HS256', secret), 'should verify');
343+
t.end();
344+
}).sign();
345+
});
346+
347+
test('Streaming sign: HMAC with empty secret string', function (t) {
348+
const dataStream = readstream('data.txt');
349+
const secret = '';
350+
const sig = jws.createSign({
351+
header: { alg: 'HS256' },
352+
secret: secret
353+
});
354+
dataStream.pipe(sig.payload);
355+
sig.on('done', function (signature) {
356+
t.ok(jws.verify(signature, 'HS256', secret), 'should verify');
357+
t.end();
358+
}).sign();
359+
});
360+
361+
test('Streaming sign: HMAC with undefined secret', function (t) {
362+
try {
363+
jws.createSign({
364+
header: { alg: 'HS256' },
365+
secret: undefined
366+
});
367+
t.fail('should have errored');
368+
t.end();
369+
} catch (error) {
370+
t.equal(error.name, 'TypeError');
371+
t.equal(error.message, 'secret must be a string or buffer or a KeyObject');
372+
t.end();
373+
}
374+
});
375+
376+
test('Streaming sign: HMAC with null secret', function (t) {
377+
try {
378+
jws.createSign({
379+
header: { alg: 'HS256' },
380+
secret: null
381+
});
382+
t.fail('should have errored');
383+
t.end();
384+
} catch (error) {
385+
t.equal(error.name, 'TypeError');
386+
t.equal(error.message, 'secret must be a string or buffer or a KeyObject');
387+
t.end();
388+
}
389+
});
390+
391+
test('Streaming verify: HMAC with empty secret buffer', function (t) {
392+
const secret = Buffer.alloc(0);
393+
jws.createVerify({
394+
signature: 'eyJhbGciOiJIUzI1NiJ9.b25lLCB0d28sIHRocmVlCg.V1oQ0aq6FgAoe7C2TORtYpQAbYzJoFNFZlJkTlF1e60',
395+
algorithm: 'HS256',
396+
secret: secret
397+
}).on('done', function (valid, decoded) {
398+
t.true(valid);
399+
t.same(decoded.payload, readfile('data.txt'));
400+
t.end();
401+
}).verify();
402+
});
403+
404+
test('Streaming verify: HMAC with empty secret string', function (t) {
405+
const secret = '';
406+
jws.createVerify({
407+
signature: 'eyJhbGciOiJIUzI1NiJ9.b25lLCB0d28sIHRocmVlCg.V1oQ0aq6FgAoe7C2TORtYpQAbYzJoFNFZlJkTlF1e60',
408+
algorithm: 'HS256',
409+
secret: secret
410+
}).on('done', function (valid, decoded) {
411+
t.true(valid);
412+
t.same(decoded.payload, readfile('data.txt'));
413+
t.end();
414+
}).verify();
415+
});
416+
417+
test('Streaming verify: HMAC with undefined secret', function (t) {
418+
try {
419+
jws.createVerify({
420+
signature: 'eyJhbGciOiJIUzI1NiJ9.b25lLCB0d28sIHRocmVlCg.V1oQ0aq6FgAoe7C2TORtYpQAbYzJoFNFZlJkTlF1e60',
421+
algorithm: 'HS256',
422+
secret: undefined
423+
});
424+
t.fail('should have errored');
425+
t.end();
426+
} catch (error) {
427+
t.equal(error.name, 'TypeError');
428+
t.equal(error.message, 'secret must be a string or buffer or a KeyObject');
429+
t.end();
430+
}
431+
});
432+
433+
test('Streaming verify: HMAC with null secret', function (t) {
434+
try {
435+
jws.createVerify({
436+
signature: 'eyJhbGciOiJIUzI1NiJ9.b25lLCB0d28sIHRocmVlCg.V1oQ0aq6FgAoe7C2TORtYpQAbYzJoFNFZlJkTlF1e60',
437+
algorithm: 'HS256',
438+
secret: null
439+
});
440+
t.fail('should have errored');
441+
t.end();
442+
} catch (error) {
443+
t.equal(error.name, 'TypeError');
444+
t.equal(error.message, 'secret must be a string or buffer or a KeyObject');
445+
t.end();
446+
}
447+
});

0 commit comments

Comments
 (0)