crypto: ensure expected JWK alg in SubtleCrypto.importKey RSA imports

PR-URL: https://github.com/nodejs/node/pull/57450
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
This commit is contained in:
Filip Skokan authored and GitHub committed 2025-03-16 15:32:12 +00:00
1 parent 8b41272f79
commit 0cfc471e82
3 files changed
+82 -27

No files matched your search

+3 -8
View File
@@ -2,7 +2,6 @@
const {
ObjectKeys,
StringPrototypeToLowerCase,
} = primordials;
const kHashContextNode = 1;
@@ -58,8 +57,7 @@ const kHashNames = {
for (let n = 0; n < keys.length; n++) {
const contexts = ObjectKeys(kHashNames[keys[n]]);
for (let i = 0; i < contexts.length; i++) {
const alias =
StringPrototypeToLowerCase(kHashNames[keys[n]][contexts[i]]);
const alias = kHashNames[keys[n]][contexts[i]];
if (kHashNames[alias] === undefined)
kHashNames[alias] = kHashNames[keys[n]];
}
@@ -67,13 +65,10 @@ const kHashNames = {
}
function normalizeHashName(name, context = kHashContextNode) {
if (typeof name !== 'string')
return name;
name = StringPrototypeToLowerCase(name);
const alias = kHashNames[name]?.[context];
return alias || name;
return kHashNames[name]?.[context];
}
normalizeHashName.kContextNode = kHashContextNode;
normalizeHashName.kContextWebCrypto = kHashContextWebCrypto;
normalizeHashName.kContextJwkRsa = kHashContextJwkRsa;
+7 -3
View File
@@ -275,9 +275,13 @@ function rsaImportKey(
}
if (keyData.alg !== undefined) {
const hash =
normalizeHashName(keyData.alg, normalizeHashName.kContextWebCrypto);
if (hash !== algorithm.hash.name)
const expected =
normalizeHashName(algorithm.hash.name,
algorithm.name === 'RSASSA-PKCS1-v1_5' ? normalizeHashName.kContextJwkRsa :
algorithm.name === 'RSA-PSS' ? normalizeHashName.kContextJwkRsaPss :
normalizeHashName.kContextJwkRsaOaep);
if (keyData.alg !== expected)
throw lazyDOMException(
'JWK "alg" does not match the requested algorithm',
'DataError');
@@ -384,6 +384,19 @@ async function testImportJwk(
const jwk = keyData[size].jwk;
let alg;
switch (name) {
case 'RSA-PSS':
alg = `PS${hash === 'SHA-1' ? 1 : hash.substring(4)}`;
break;
case 'RSA-OAEP':
alg = `RSA-OAEP${hash === 'SHA-1' ? '' : hash.substring(3)}`;
break;
case 'RSASSA-PKCS1-v1_5':
alg = `RS${hash === 'SHA-1' ? 1 : hash.substring(4)}`;
break;
}
const [
publicKey,
privateKey,
@@ -394,14 +407,14 @@ async function testImportJwk(
kty: jwk.kty,
n: jwk.n,
e: jwk.e,
alg: `PS${hash.substring(4)}`
alg,
},
{ name, hash },
extractable,
publicUsages),
subtle.importKey(
'jwk',
{ ...jwk, alg: `PS${hash.substring(4)}` },
{ ...jwk, alg },
{ name, hash },
extractable,
privateUsages),
@@ -435,6 +448,8 @@ async function testImportJwk(
assert.strictEqual(pubJwk.kty, 'RSA');
assert.strictEqual(pvtJwk.kty, 'RSA');
assert.strictEqual(pubJwk.alg, alg);
assert.strictEqual(pvtJwk.alg, alg);
assert.strictEqual(pubJwk.n, jwk.n);
assert.strictEqual(pvtJwk.n, jwk.n);
assert.strictEqual(pubJwk.e, jwk.e);
@@ -483,22 +498,10 @@ async function testImportJwk(
}
{
let invalidAlg = name === 'RSA-OAEP' ? name : name === 'RSA-PSS' ? 'PS' : 'RS';
switch (name) {
case 'RSA-OAEP':
if (hash === 'SHA-1')
invalidAlg += '-256';
break;
default:
if (hash === 'SHA-256')
invalidAlg += '384';
else
invalidAlg += '256';
}
await assert.rejects(
subtle.importKey(
'jwk',
{ kty: jwk.kty, n: jwk.n, e: jwk.e, alg: invalidAlg },
{ kty: jwk.kty, n: jwk.n, e: jwk.e, alg: alg.toLowerCase() },
{ name, hash },
extractable,
publicUsages),
@@ -506,7 +509,60 @@ async function testImportJwk(
await assert.rejects(
subtle.importKey(
'jwk',
{ ...jwk, alg: invalidAlg },
{ ...jwk, alg: alg.toLowerCase() },
{ name, hash },
extractable,
privateUsages),
{ message: 'JWK "alg" does not match the requested algorithm' });
}
{
let invalidAlgHash = name === 'RSA-OAEP' ? name : name === 'RSA-PSS' ? 'PS' : 'RS';
switch (name) {
case 'RSA-OAEP':
if (hash === 'SHA-1')
invalidAlgHash += '-256';
break;
default:
if (hash === 'SHA-256')
invalidAlgHash += '384';
else
invalidAlgHash += '256';
}
await assert.rejects(
subtle.importKey(
'jwk',
{ kty: jwk.kty, n: jwk.n, e: jwk.e, alg: invalidAlgHash },
{ name, hash },
extractable,
publicUsages),
{ message: 'JWK "alg" does not match the requested algorithm' });
await assert.rejects(
subtle.importKey(
'jwk',
{ ...jwk, alg: invalidAlgHash },
{ name, hash },
extractable,
privateUsages),
{ message: 'JWK "alg" does not match the requested algorithm' });
}
{
const invalidAlgType = name === 'RSA-PSS' ? `RS${hash.substring(4)}` : `PS${hash.substring(4)}`;
await assert.rejects(
subtle.importKey(
'jwk',
{ kty: jwk.kty, n: jwk.n, e: jwk.e, alg: invalidAlgType },
{ name, hash },
extractable,
publicUsages),
{ message: 'JWK "alg" does not match the requested algorithm' }).catch((e) => {
throw e;
});
await assert.rejects(
subtle.importKey(
'jwk',
{ ...jwk, alg: invalidAlgType },
{ name, hash },
extractable,
privateUsages),