Skip to content

Commit e1fa9dc

Browse files
Merge pull request from GHSA-8cf7-32gw-wr33
* Check if node version supports asymmetricKeyDetails * Validate algorithms for ec key type * Rename variable * Rename function * Add early return for symmetric keys * Validate algorithm for RSA key type * Validate algorithm for RSA-PSS key type * Check key types for EdDSA algorithm * Rename function * Move validateKey function to module * Convert arrow to function notation * Validate key in verify function * Simplify if * Convert if to switch..case * Guard against empty key in validation * Remove empty line * Add lib to check modulus length * Add modulus length checks * Validate mgf1HashAlgorithm and saltLength * Check node version before using key details API * Use built-in modulus length getter * Fix Node version validations * Remove duplicate validateKey * Add periods to error messages * Fix validation in verify function * Make asymmetric key validation the latest validation step * Change key curve validation * Remove support for ES256K * Fix old test that was using wrong key types to sign tokens * Enable RSA-PSS for old Node versions * Add specific RSA-PSS validations on Node 16 LTS+ * Improve error message * Simplify key validation code * Fix typo * Improve error message * Change var to const in test * Change const to let to avoid reassigning problem * Improve error message * Test incorrect private key type * Rename invalid to unsupported * Test verifying of jwt token with unsupported key * Test invalid private key type * Change order of object parameters * Move validation test to separate file * Move all validation tests to separate file * Add prime256v1 ec key * Remove modulus length check * WIP: Add EC key validation tests * Fix node version checks * Fix error message check on test * Add successful tests for EC curve check * Remove only from describe * Remove `only` * Remove duplicate block of code * Move variable to a different scope and make it const * Convert allowed curves to object for faster lookup * Rename variable * Change variable assignment order * Remove unused object properties * Test RSA-PSS happy path and wrong length * Add missing tests * Pass validation if no algorithm has been provided * Test validation of invalid salt length * Test error when signing token with invalid key * Change var to const/let in verify tests * Test verifying token with invalid key * Improve test error messages * Add parameter to skip private key validation * Replace DSA key with a 4096 bit long key * Test allowInvalidPrivateKeys in key signing * Improve test message * Rename variable * Add key validation flag tests * Fix variable name in Readme * Change private to public dsa key in verify * Rename flag * Run EC validation tests conditionally * Fix tests in old node versions * Ignore block of code from test coverage * Separate EC validations tests into two different ones * Add comment * Wrap switch in if instead of having an early return * Remove unsupported algorithms from asymmetric key validation * Rename option to allowInvalidAsymmetricKeyTypes and improve Readme * 9.0.0 * adding migration notes to readme * adding changelog for version 9.0.0 Co-authored-by: julienwoll <[email protected]>
1 parent 5eaedbf commit e1fa9dc

19 files changed

+557
-90
lines changed

CHANGELOG.md

+18
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,24 @@
44
All notable changes to this project will be documented in this file starting from version **v4.0.0**.
55
This project adheres to [Semantic Versioning](http://semver.org/).
66

7+
## 9.0.0 - 2022-12-21
8+
9+
**Breaking changes: See [Migration from v8 to v9](https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v8-to-v9)**
10+
11+
### Breaking changes
12+
13+
- Removed support for Node versions 11 and below.
14+
- The verify() function no longer accepts unsigned tokens by default. ([834503079514b72264fd13023a3b8d648afd6a16]https://github.com/auth0/node-jsonwebtoken/commit/834503079514b72264fd13023a3b8d648afd6a16)
15+
- RSA key size must be 2048 bits or greater. ([ecdf6cc6073ea13a7e71df5fad043550f08d0fa6]https://github.com/auth0/node-jsonwebtoken/commit/ecdf6cc6073ea13a7e71df5fad043550f08d0fa6)
16+
- Key types must be valid for the signing / verification algorithm
17+
18+
### Security fixes
19+
20+
- security: fixes `Arbitrary File Write via verify function` - CVE-2022-23529
21+
- security: fixes `Insecure default algorithm in jwt.verify() could lead to signature validation bypass` - CVE-2022-23540
22+
- security: fixes `Insecure implementation of key retrieval function could lead to Forgeable Public/Private Tokens from RSA to HMAC` - CVE-2022-23541
23+
- security: fixes `Unrestricted key type could lead to legacy keys usage` - CVE-2022-23539
24+
725
## 8.5.1 - 2019-03-18
826

927
### Bug fix

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ $ npm install jsonwebtoken
1717

1818
# Migration notes
1919

20+
* [From v8 to v9](https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v8-to-v9)
2021
* [From v7 to v8](https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v7-to-v8)
2122

2223
# Usage
@@ -52,6 +53,7 @@ When signing with RSA algorithms the minimum modulus length is 2048 except when
5253
* `keyid`
5354
* `mutatePayload`: if true, the sign function will modify the payload object directly. This is useful if you need a raw reference to the payload after claims have been applied to it but before it has been encoded into a token.
5455
* `allowInsecureKeySizes`: if true allows private keys with a modulus below 2048 to be used for RSA
56+
* `allowInvalidAsymmetricKeyTypes`: if true, allows asymmetric keys which do not match the specified algorithm. This option is intended only for backwards compatability and should be avoided.
5557

5658

5759

@@ -158,7 +160,7 @@ As mentioned in [this comment](https://github.com/auth0/node-jsonwebtoken/issues
158160
> Eg: `1000`, `"2 days"`, `"10h"`, `"7d"`. A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default (`"120"` is equal to `"120ms"`).
159161
* `clockTimestamp`: the time in seconds that should be used as the current time for all necessary comparisons.
160162
* `nonce`: if you want to check `nonce` claim, provide a string value here. It is used on Open ID for the ID Tokens. ([Open ID implementation notes](https://openid.net/specs/openid-connect-core-1_0.html#NonceNotes))
161-
163+
* `allowInvalidAsymmetricKeyTypes`: if true, allows asymmetric keys which do not match the specified algorithm. This option is intended only for backwards compatability and should be avoided.
162164

163165
```js
164166
// verify a token symmetric - synchronous

lib/asymmetricKeyDetailsSupported.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const semver = require('semver');
2+
3+
module.exports = semver.satisfies(process.version, '>=15.7.0');

lib/rsaPssKeyDetailsSupported.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const semver = require('semver');
2+
3+
module.exports = semver.satisfies(process.version, '>=16.9.0');

lib/validateAsymmetricKey.js

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
const ASYMMETRIC_KEY_DETAILS_SUPPORTED = require('./asymmetricKeyDetailsSupported');
2+
const RSA_PSS_KEY_DETAILS_SUPPORTED = require('./rsaPssKeyDetailsSupported');
3+
4+
const allowedAlgorithmsForKeys = {
5+
'ec': ['ES256', 'ES384', 'ES512'],
6+
'rsa': ['RS256', 'PS256', 'RS384', 'PS384', 'RS512', 'PS512'],
7+
'rsa-pss': ['PS256', 'PS384', 'PS512']
8+
};
9+
10+
const allowedCurves = {
11+
ES256: 'prime256v1',
12+
ES384: 'secp384r1',
13+
ES512: 'secp521r1',
14+
};
15+
16+
module.exports = function(algorithm, key) {
17+
if (!algorithm || !key) return;
18+
19+
const keyType = key.asymmetricKeyType;
20+
if (!keyType) return;
21+
22+
const allowedAlgorithms = allowedAlgorithmsForKeys[keyType];
23+
24+
if (!allowedAlgorithms) {
25+
throw new Error(`Unknown key type "${keyType}".`);
26+
}
27+
28+
if (!allowedAlgorithms.includes(algorithm)) {
29+
throw new Error(`"alg" parameter for "${keyType}" key type must be one of: ${allowedAlgorithms.join(', ')}.`)
30+
}
31+
32+
/*
33+
* Ignore the next block from test coverage because it gets executed
34+
* conditionally depending on the Node version. Not ignoring it would
35+
* prevent us from reaching the target % of coverage for versions of
36+
* Node under 15.7.0.
37+
*/
38+
/* istanbul ignore next */
39+
if (ASYMMETRIC_KEY_DETAILS_SUPPORTED) {
40+
switch (keyType) {
41+
case 'ec':
42+
const keyCurve = key.asymmetricKeyDetails.namedCurve;
43+
const allowedCurve = allowedCurves[algorithm];
44+
45+
if (keyCurve !== allowedCurve) {
46+
throw new Error(`"alg" parameter "${algorithm}" requires curve "${allowedCurve}".`);
47+
}
48+
break;
49+
50+
case 'rsa-pss':
51+
if (RSA_PSS_KEY_DETAILS_SUPPORTED) {
52+
const length = parseInt(algorithm.slice(-3), 10);
53+
const { hashAlgorithm, mgf1HashAlgorithm, saltLength } = key.asymmetricKeyDetails;
54+
55+
if (hashAlgorithm !== `sha${length}` || mgf1HashAlgorithm !== hashAlgorithm) {
56+
throw new Error(`Invalid key for this operation, its RSA-PSS parameters do not meet the requirements of "alg" ${algorithm}.`);
57+
}
58+
59+
if (saltLength !== undefined && saltLength > length >> 3) {
60+
throw new Error(`Invalid key for this operation, its RSA-PSS parameter saltLength does not meet the requirements of "alg" ${algorithm}.`)
61+
}
62+
}
63+
break;
64+
}
65+
}
66+
}

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "jsonwebtoken",
3-
"version": "8.5.1",
3+
"version": "9.0.0",
44
"description": "JSON Web Token implementation (symmetric and asymmetric)",
55
"main": "index.js",
66
"nyc": {

sign.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const timespan = require('./lib/timespan');
22
const PS_SUPPORTED = require('./lib/psSupported');
3+
const validateAsymmetricKey = require('./lib/validateAsymmetricKey');
34
const jws = require('jws');
45
const {includes, isBoolean, isInteger, isNumber, isPlainObject, isString, once} = require('lodash')
56
const { KeyObject, createSecretKey, createPrivateKey } = require('crypto')
@@ -22,7 +23,8 @@ const sign_options_schema = {
2223
noTimestamp: { isValid: isBoolean, message: '"noTimestamp" must be a boolean' },
2324
keyid: { isValid: isString, message: '"keyid" must be a string' },
2425
mutatePayload: { isValid: isBoolean, message: '"mutatePayload" must be a boolean' },
25-
allowInsecureKeySizes: { isValid: isBoolean, message: '"allowInsecureKeySizes" must be a boolean'}
26+
allowInsecureKeySizes: { isValid: isBoolean, message: '"allowInsecureKeySizes" must be a boolean'},
27+
allowInvalidAsymmetricKeyTypes: { isValid: isBoolean, message: '"allowInvalidAsymmetricKeyTypes" must be a boolean'}
2628
};
2729

2830
const registered_claims_schema = {
@@ -166,6 +168,14 @@ module.exports = function (payload, secretOrPrivateKey, options, callback) {
166168
return failure(error);
167169
}
168170

171+
if (!options.allowInvalidAsymmetricKeyTypes) {
172+
try {
173+
validateAsymmetricKey(header.alg, secretOrPrivateKey);
174+
} catch (error) {
175+
return failure(error);
176+
}
177+
}
178+
169179
const timestamp = payload.iat || Math.floor(Date.now() / 1000);
170180

171181
if (options.noTimestamp) {

test/dsa-private.pem

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
-----BEGIN DSA PRIVATE KEY-----
2+
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
36+
-----END DSA PRIVATE KEY-----

test/dsa-public.pem

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
-----BEGIN PUBLIC KEY-----
2+
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
35+
y0elWU3mxe6Rn6R7WHM8or7sX3tWDq6OntJlKg==
36+
-----END PUBLIC KEY-----

0 commit comments

Comments
 (0)