Files
node-jsonwebtoken/test/validateAsymmetricKey.tests.js
T
925d95de54 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]>
2022-12-21 13:36:01 +01:00

143 lines
5.3 KiB
JavaScript

const validateAsymmetricKey = require('../lib/validateAsymmetricKey');
const PS_SUPPORTED = require('../lib/psSupported');
const ASYMMETRIC_KEY_DETAILS_SUPPORTED = require('../lib/asymmetricKeyDetailsSupported');
const RSA_PSS_KEY_DETAILS_SUPPORTED = require('../lib/rsaPssKeyDetailsSupported');
const fs = require('fs');
const path = require('path');
const { createPrivateKey } = require('crypto');
const expect = require('chai').expect;
function loadKey(filename) {
return createPrivateKey(
fs.readFileSync(path.join(__dirname, filename))
);
}
const algorithmParams = {
RS256: {
invalidPrivateKey: loadKey('secp384r1-private.pem')
},
ES256: {
invalidPrivateKey: loadKey('priv.pem')
}
};
if (PS_SUPPORTED) {
algorithmParams.PS256 = {
invalidPrivateKey: loadKey('secp384r1-private.pem')
};
}
describe('Asymmetric key validation', function() {
Object.keys(algorithmParams).forEach(function(algorithm) {
describe(algorithm, function() {
const keys = algorithmParams[algorithm];
describe('when validating a key with an invalid private key type', function () {
it('should throw an error', function () {
const expectedErrorMessage = /"alg" parameter for "[\w\d-]+" key type must be one of:/;
expect(function() {
validateAsymmetricKey(algorithm, keys.invalidPrivateKey);
}).to.throw(expectedErrorMessage);
});
});
});
});
describe('when the function has missing parameters', function() {
it('should pass the validation if no key has been provided', function() {
const algorithm = 'ES256';
validateAsymmetricKey(algorithm);
});
it('should pass the validation if no algorithm has been provided', function() {
const key = loadKey('dsa-private.pem');
validateAsymmetricKey(null, key);
});
});
describe('when validating a key with an unsupported type', function () {
it('should throw an error', function() {
const algorithm = 'RS256';
const key = loadKey('dsa-private.pem');
const expectedErrorMessage = 'Unknown key type "dsa".';
expect(function() {
validateAsymmetricKey(algorithm, key);
}).to.throw(expectedErrorMessage);
});
});
describe('Elliptic curve algorithms', function () {
const curvesAlgorithms = [
{ algorithm: 'ES256', curve: 'prime256v1' },
{ algorithm: 'ES384', curve: 'secp384r1' },
{ algorithm: 'ES512', curve: 'secp521r1' },
];
const curvesKeys = [
{ curve: 'prime256v1', key: loadKey('prime256v1-private.pem') },
{ curve: 'secp384r1', key: loadKey('secp384r1-private.pem') },
{ curve: 'secp521r1', key: loadKey('secp521r1-private.pem') }
];
describe('when validating keys generated using Elliptic Curves', function () {
curvesAlgorithms.forEach(function(curveAlgorithm) {
curvesKeys
.forEach((curveKeys) => {
if (curveKeys.curve !== curveAlgorithm.curve) {
if (ASYMMETRIC_KEY_DETAILS_SUPPORTED) {
it(`should throw an error when validating an ${curveAlgorithm.algorithm} token for key with curve ${curveKeys.curve}`, function() {
expect(() => {
validateAsymmetricKey(curveAlgorithm.algorithm, curveKeys.key);
}).to.throw(`"alg" parameter "${curveAlgorithm.algorithm}" requires curve "${curveAlgorithm.curve}".`);
});
} else {
it(`should pass the validation for incorrect keys if the Node version does not support checking the key's curve name`, function() {
expect(() => {
validateAsymmetricKey(curveAlgorithm.algorithm, curveKeys.key);
}).not.to.throw();
});
}
} else {
it(`should accept an ${curveAlgorithm.algorithm} token for key with curve ${curveKeys.curve}`, function() {
expect(() => {
validateAsymmetricKey(curveAlgorithm.algorithm, curveKeys.key);
}).not.to.throw();
});
}
});
});
});
});
if (RSA_PSS_KEY_DETAILS_SUPPORTED) {
describe('RSA-PSS algorithms', function () {
const key = loadKey('rsa-pss-private.pem');
it(`it should throw an error when validating a key with wrong RSA-RSS parameters`, function () {
const algorithm = 'PS512';
expect(function() {
validateAsymmetricKey(algorithm, key);
}).to.throw('Invalid key for this operation, its RSA-PSS parameters do not meet the requirements of "alg" PS512')
});
it(`it should throw an error when validating a key with invalid salt length`, function () {
const algorithm = 'PS256';
const shortSaltKey = loadKey('rsa-pss-invalid-salt-length-private.pem');
expect(function() {
validateAsymmetricKey(algorithm, shortSaltKey);
}).to.throw('Invalid key for this operation, its RSA-PSS parameter saltLength does not meet the requirements of "alg" PS256.')
});
it(`it should pass the validation when the key matches all the requirements for the algorithm`, function () {
expect(function() {
const algorithm = 'PS256';
validateAsymmetricKey(algorithm, key);
}).not.to.throw()
});
});
}
});