crypto: ensure invalid SubtleCrypto JWK data import results in DataError

PR-URL: https://github.com/nodejs/node/pull/55041
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
This commit is contained in:
Filip Skokan 2024-09-23 17:28:44 +02:00 committed by GitHub
parent 96ec7eede9
commit b64006c0ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 78 additions and 19 deletions

View File

@ -295,7 +295,12 @@ async function aesImportKey(
}
const handle = new KeyObjectHandle();
handle.initJwk(keyData);
try {
handle.initJwk(keyData);
} catch (err) {
throw lazyDOMException(
'Invalid keyData', { name: 'DataError', cause: err });
}
({ length } = handle.keyDetail({ }));
validateKeyLength(length);

View File

@ -17,6 +17,12 @@ const {
kSignJobModeVerify,
} = internalBinding('crypto');
const {
codes: {
ERR_CRYPTO_INVALID_JWK,
},
} = require('internal/errors');
const {
getUsagesUnion,
hasAnyNotIn,
@ -277,22 +283,26 @@ async function cfrgImportKey(
isPublic,
usagesSet);
const publicKeyObject = createCFRGRawKey(
name,
Buffer.from(keyData.x, 'base64'),
true);
if (isPublic) {
keyObject = publicKeyObject;
} else {
keyObject = createCFRGRawKey(
try {
const publicKeyObject = createCFRGRawKey(
name,
Buffer.from(keyData.d, 'base64'),
false);
Buffer.from(keyData.x, 'base64'),
true);
if (!createPublicKey(keyObject).equals(publicKeyObject)) {
throw lazyDOMException('Invalid JWK', 'DataError');
if (isPublic) {
keyObject = publicKeyObject;
} else {
keyObject = createCFRGRawKey(
name,
Buffer.from(keyData.d, 'base64'),
false);
if (!createPublicKey(keyObject).equals(publicKeyObject)) {
throw new ERR_CRYPTO_INVALID_JWK();
}
}
} catch (err) {
throw lazyDOMException('Invalid keyData', { name: 'DataError', cause: err });
}
break;
}

View File

@ -240,9 +240,15 @@ async function ecImportKey(
}
const handle = new KeyObjectHandle();
const type = handle.initJwk(keyData, namedCurve);
let type;
try {
type = handle.initJwk(keyData, namedCurve);
} catch (err) {
throw lazyDOMException(
'Invalid keyData', { name: 'DataError', cause: err });
}
if (type === undefined)
throw lazyDOMException('Invalid JWK', 'DataError');
throw lazyDOMException('Invalid keyData', 'DataError');
keyObject = type === kKeyTypePrivate ?
new PrivateKeyObject(handle) :
new PublicKeyObject(handle);

View File

@ -145,7 +145,12 @@ async function hmacImportKey(
}
const handle = new KeyObjectHandle();
handle.initJwk(keyData);
try {
handle.initJwk(keyData);
} catch (err) {
throw lazyDOMException(
'Invalid keyData', { name: 'DataError', cause: err });
}
keyObject = new SecretKeyObject(handle);
break;
}

View File

@ -275,9 +275,15 @@ async function rsaImportKey(
}
const handle = new KeyObjectHandle();
const type = handle.initJwk(keyData);
let type;
try {
type = handle.initJwk(keyData);
} catch (err) {
throw lazyDOMException(
'Invalid keyData', { name: 'DataError', cause: err });
}
if (type === undefined)
throw lazyDOMException('Invalid JWK', 'DataError');
throw lazyDOMException('Invalid keyData', 'DataError');
keyObject = type === kKeyTypePrivate ?
new PrivateKeyObject(handle) :

View File

@ -322,6 +322,15 @@ async function testImportJwk({ name, publicUsages, privateUsages }, extractable)
extractable,
[/* empty usages */]),
{ name: 'SyntaxError', message: 'Usages cannot be empty when importing a private key.' });
await assert.rejects(
subtle.importKey(
'jwk',
{ kty: jwk.kty, /* missing x */ crv: jwk.crv },
{ name },
extractable,
publicUsages),
{ name: 'DataError', message: 'Invalid keyData' });
}
async function testImportRaw({ name, publicUsages }) {

View File

@ -330,6 +330,15 @@ async function testImportJwk(
extractable,
[/* empty usages */]),
{ name: 'SyntaxError', message: 'Usages cannot be empty when importing a private key.' });
await assert.rejects(
subtle.importKey(
'jwk',
{ kty: jwk.kty, /* missing x */ y: jwk.y, crv: jwk.crv },
{ name, namedCurve },
extractable,
publicUsages),
{ name: 'DataError', message: 'Invalid keyData' });
}
async function testImportRaw({ name, publicUsages }, namedCurve) {

View File

@ -513,6 +513,15 @@ async function testImportJwk(
extractable,
[/* empty usages */]),
{ name: 'SyntaxError', message: 'Usages cannot be empty when importing a private key.' });
await assert.rejects(
subtle.importKey(
'jwk',
{ kty: jwk.kty, /* missing e */ n: jwk.n },
{ name, hash },
extractable,
publicUsages),
{ name: 'DataError', message: 'Invalid keyData' });
}
// combinations to test