Skip to content

Commit 7c20a5c

Browse files
panvanodejs-github-bot
authored andcommitted
crypto: check RSA JWK alg with SHA-3 hashes
Reject a supplied JWK alg when no matching identifier exists for the requested RSA algorithm and hash. Signed-off-by: Filip Skokan <panva.ip@gmail.com> Assisted-by: Codex PR-URL: #66237 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Aviv Keller <me@aviv.sh>
1 parent 71689e8 commit 7c20a5c

2 files changed

Lines changed: 43 additions & 1 deletion

File tree

‎lib/internal/crypto/rsa.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ function rsaImportKey(
202202
algorithm.name === 'RSA-PSS' ? normalizeHashName.kContextJwkRsaPss :
203203
normalizeHashName.kContextJwkRsaOaep);
204204

205-
if (expected && keyData.alg !== expected)
205+
if (keyData.alg !== expected)
206206
throw lazyDOMException(
207207
'JWK "alg" does not match the requested algorithm',
208208
'DataError');
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
if (!common.hasCrypto)
5+
common.skip('missing crypto');
6+
7+
const { isBoringSSL } = require('../common/crypto');
8+
if (isBoringSSL)
9+
common.skip('missing SHA-3');
10+
11+
const assert = require('assert');
12+
const { createPrivateKey, createPublicKey } = require('crypto');
13+
const fixtures = require('../common/fixtures');
14+
const { subtle } = globalThis.crypto;
15+
16+
(async () => {
17+
const privateKey = createPrivateKey(fixtures.readKey('rsa_private_2048.pem'));
18+
const privateJwk = privateKey.export({ format: 'jwk' });
19+
const publicJwk = createPublicKey(privateKey).export({ format: 'jwk' });
20+
21+
for (const name of ['RSA-PSS', 'RSASSA-PKCS1-v1_5', 'RSA-OAEP']) {
22+
for (const hash of ['SHA3-256', 'SHA3-384', 'SHA3-512']) {
23+
for (const jwk of [publicJwk, privateJwk]) {
24+
const usages = name === 'RSA-OAEP' ? [jwk.d ? 'decrypt' : 'encrypt'] :
25+
[jwk.d ? 'sign' : 'verify'];
26+
const algorithm = { name, hash };
27+
// There is no JWK alg identifier for RSA with SHA-3. Omitting alg is
28+
// valid, but an identifier for SHA-2 or an unknown identifier is not.
29+
const key = await subtle.importKey('jwk', jwk, algorithm, true, usages);
30+
const exported = await subtle.exportKey('jwk', key);
31+
assert.strictEqual(Object.hasOwn(exported, 'alg'), false);
32+
const imported = await subtle.importKey('jwk', exported, algorithm, true, usages);
33+
assert.deepStrictEqual(imported.algorithm, key.algorithm);
34+
assert.deepStrictEqual(await subtle.exportKey('jwk', imported), exported);
35+
for (const alg of ['RS256', 'PS256', 'RSA-OAEP-256', 'unknown']) {
36+
await assert.rejects(subtle.importKey(
37+
'jwk', { ...jwk, alg }, algorithm, true, usages), { name: 'DataError' });
38+
}
39+
}
40+
}
41+
}
42+
})().then(common.mustCall());

0 commit comments

Comments
 (0)