Skip to content

Commit eaeb9b6

Browse files
panvaaduh95
authored andcommitted
crypto: reject invalid raw key imports
Signed-off-by: Filip Skokan <[email protected]> PR-URL: #63134 Backport-PR-URL: #64629 Reviewed-By: Antoine du Hamel <[email protected]>
1 parent 898e70f commit eaeb9b6

4 files changed

Lines changed: 119 additions & 39 deletions

File tree

lib/internal/crypto/ml_kem.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ const {
1313
KEMDecapsulateJob,
1414
KEMEncapsulateJob,
1515
kKeyFormatDER,
16-
kKeyFormatRawPrivate,
1716
kKeyFormatRawPublic,
17+
kKeyFormatRawSeed,
1818
kWebCryptoKeyFormatPKCS8,
1919
kWebCryptoKeyFormatRaw,
2020
kWebCryptoKeyFormatSPKI,
@@ -182,7 +182,7 @@ function mlKemImportKey(
182182
case 'raw-seed': {
183183
const isPublic = format === 'raw-public';
184184
verifyAcceptableMlKemKeyUse(name, isPublic, usagesSet);
185-
handle = importRawKey(isPublic, keyData, isPublic ? kKeyFormatRawPublic : kKeyFormatRawPrivate, name);
185+
handle = importRawKey(isPublic, keyData, isPublic ? kKeyFormatRawPublic : kKeyFormatRawSeed, name);
186186
break;
187187
}
188188
case 'jwk': {

src/crypto/crypto_keys.cc

Lines changed: 85 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,85 @@ int GetNidFromName(const char* name) {
287287
return NID_undef;
288288
#endif
289289
}
290+
291+
bool IsUnavailablePqcKeyType(Environment* env, Local<String> key_type) {
292+
return key_type->StringEquals(env->crypto_ml_dsa_44_string()) ||
293+
key_type->StringEquals(env->crypto_ml_dsa_65_string()) ||
294+
key_type->StringEquals(env->crypto_ml_dsa_87_string()) ||
295+
key_type->StringEquals(env->crypto_ml_kem_512_string()) ||
296+
key_type->StringEquals(env->crypto_ml_kem_768_string()) ||
297+
key_type->StringEquals(env->crypto_ml_kem_1024_string()) ||
298+
key_type->StringEquals(env->crypto_slh_dsa_sha2_128f_string()) ||
299+
key_type->StringEquals(env->crypto_slh_dsa_sha2_128s_string()) ||
300+
key_type->StringEquals(env->crypto_slh_dsa_sha2_192f_string()) ||
301+
key_type->StringEquals(env->crypto_slh_dsa_sha2_192s_string()) ||
302+
key_type->StringEquals(env->crypto_slh_dsa_sha2_256f_string()) ||
303+
key_type->StringEquals(env->crypto_slh_dsa_sha2_256s_string()) ||
304+
key_type->StringEquals(env->crypto_slh_dsa_shake_128f_string()) ||
305+
key_type->StringEquals(env->crypto_slh_dsa_shake_128s_string()) ||
306+
key_type->StringEquals(env->crypto_slh_dsa_shake_192f_string()) ||
307+
key_type->StringEquals(env->crypto_slh_dsa_shake_192s_string()) ||
308+
key_type->StringEquals(env->crypto_slh_dsa_shake_256f_string()) ||
309+
key_type->StringEquals(env->crypto_slh_dsa_shake_256s_string());
310+
}
311+
312+
bool IsUnsupportedRawKeyType(Environment* env, Local<String> key_type) {
313+
return key_type->StringEquals(env->crypto_rsa_string()) ||
314+
key_type->StringEquals(env->crypto_rsa_pss_string()) ||
315+
key_type->StringEquals(env->crypto_dsa_string()) ||
316+
key_type->StringEquals(env->crypto_dh_string());
317+
}
318+
319+
void ValidateRawKeyImportFormat(Environment* env,
320+
Local<String> key_type,
321+
const char* key_type_name,
322+
int id,
323+
EVPKeyPointer::PKFormatType format) {
324+
auto validate_raw_format =
325+
[&](EVPKeyPointer::PKFormatType expected_private_format) {
326+
if (format == EVPKeyPointer::PKFormatType::RAW_PUBLIC ||
327+
format == expected_private_format) {
328+
return;
329+
}
330+
THROW_ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(env);
331+
};
332+
333+
if (key_type->StringEquals(env->crypto_ec_string())) {
334+
return validate_raw_format(EVPKeyPointer::PKFormatType::RAW_PRIVATE);
335+
}
336+
337+
switch (id) {
338+
case EVP_PKEY_X25519:
339+
case EVP_PKEY_X448:
340+
case EVP_PKEY_ED25519:
341+
case EVP_PKEY_ED448:
342+
return validate_raw_format(EVPKeyPointer::PKFormatType::RAW_PRIVATE);
343+
default:
344+
break;
345+
}
346+
347+
#if OPENSSL_WITH_PQC
348+
if (IsPqcSeedKeyId(id)) {
349+
return validate_raw_format(EVPKeyPointer::PKFormatType::RAW_SEED);
350+
}
351+
if (IsPqcRawPrivateKeyId(id)) {
352+
return validate_raw_format(EVPKeyPointer::PKFormatType::RAW_PRIVATE);
353+
}
354+
#endif
355+
356+
if (IsUnavailablePqcKeyType(env, key_type)) {
357+
THROW_ERR_INVALID_ARG_VALUE(env, "Unsupported key type");
358+
return;
359+
}
360+
361+
if (IsUnsupportedRawKeyType(env, key_type)) {
362+
THROW_ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(env);
363+
return;
364+
}
365+
366+
THROW_ERR_INVALID_ARG_VALUE(
367+
env, "Invalid asymmetricKeyType: %s", key_type_name);
368+
}
290369
} // namespace
291370

292371
bool KeyObjectData::ToEncodedPublicKey(
@@ -492,6 +571,12 @@ static KeyObjectData ImportRawKey(Environment* env,
492571
}
493572
};
494573

574+
const int id = GetNidFromName(key_type_name);
575+
ValidateRawKeyImportFormat(env, key_type, key_type_name, id, format);
576+
if (env->isolate()->HasPendingException()) {
577+
return {};
578+
}
579+
495580
// EC keys
496581
if (key_type->StringEquals(env->crypto_ec_string())) {
497582
int curve_nid = ncrypto::Ec::GetCurveIdFromName(named_curve);
@@ -549,8 +634,6 @@ static KeyObjectData ImportRawKey(Environment* env,
549634
return KeyObjectData::CreateAsymmetric(target_type, std::move(pkey));
550635
}
551636

552-
int id = GetNidFromName(key_type_name);
553-
554637
typedef EVPKeyPointer (*new_key_fn)(
555638
int, const ncrypto::Buffer<const unsigned char>&);
556639
new_key_fn fn = nullptr;
@@ -589,40 +672,6 @@ static KeyObjectData ImportRawKey(Environment* env,
589672
return KeyObjectData::CreateAsymmetric(target_type, std::move(pkey));
590673
}
591674

592-
if (key_type->StringEquals(env->crypto_rsa_string()) ||
593-
key_type->StringEquals(env->crypto_rsa_pss_string()) ||
594-
key_type->StringEquals(env->crypto_dsa_string()) ||
595-
key_type->StringEquals(env->crypto_dh_string())) {
596-
THROW_ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(env);
597-
return {};
598-
}
599-
600-
#if !OPENSSL_WITH_PQC
601-
if (key_type->StringEquals(env->crypto_ml_dsa_44_string()) ||
602-
key_type->StringEquals(env->crypto_ml_dsa_65_string()) ||
603-
key_type->StringEquals(env->crypto_ml_dsa_87_string()) ||
604-
key_type->StringEquals(env->crypto_ml_kem_512_string()) ||
605-
key_type->StringEquals(env->crypto_ml_kem_768_string()) ||
606-
key_type->StringEquals(env->crypto_ml_kem_1024_string()) ||
607-
key_type->StringEquals(env->crypto_slh_dsa_sha2_128f_string()) ||
608-
key_type->StringEquals(env->crypto_slh_dsa_sha2_128s_string()) ||
609-
key_type->StringEquals(env->crypto_slh_dsa_sha2_192f_string()) ||
610-
key_type->StringEquals(env->crypto_slh_dsa_sha2_192s_string()) ||
611-
key_type->StringEquals(env->crypto_slh_dsa_sha2_256f_string()) ||
612-
key_type->StringEquals(env->crypto_slh_dsa_sha2_256s_string()) ||
613-
key_type->StringEquals(env->crypto_slh_dsa_shake_128f_string()) ||
614-
key_type->StringEquals(env->crypto_slh_dsa_shake_128s_string()) ||
615-
key_type->StringEquals(env->crypto_slh_dsa_shake_192f_string()) ||
616-
key_type->StringEquals(env->crypto_slh_dsa_shake_192s_string()) ||
617-
key_type->StringEquals(env->crypto_slh_dsa_shake_256f_string()) ||
618-
key_type->StringEquals(env->crypto_slh_dsa_shake_256s_string())) {
619-
THROW_ERR_INVALID_ARG_VALUE(env, "Unsupported key type");
620-
return {};
621-
}
622-
#endif
623-
624-
THROW_ERR_INVALID_ARG_VALUE(
625-
env, "Invalid asymmetricKeyType: %s", key_type_name);
626675
return {};
627676
}
628677

test/parallel/test-crypto-key-objects-raw.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,11 @@ if (hasOpenSSL(3, 5)) {
154154
assert.throws(() => privKeyObj.export({ format: 'raw-private' }),
155155
{ code: 'ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS' });
156156

157-
for (const format of ['raw-public', 'raw-private', 'raw-seed']) {
157+
assert.throws(() => crypto.createPrivateKey({
158+
key: Buffer.alloc(32), format: 'raw-public', asymmetricKeyType: 'dh',
159+
}), { code: 'ERR_INVALID_ARG_VALUE' });
160+
161+
for (const format of ['raw-private', 'raw-seed']) {
158162
assert.throws(() => crypto.createPrivateKey({
159163
key: Buffer.alloc(32), format, asymmetricKeyType: 'dh',
160164
}), {
@@ -326,6 +330,12 @@ if (hasOpenSSL(3, 5)) {
326330
fixtures.readKey('ec_p256_private.pem', 'ascii'));
327331
assert.throws(() => ecPriv.export({ format: 'raw-seed' }),
328332
{ code: 'ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS' });
333+
assert.throws(() => crypto.createPrivateKey({
334+
key: ecPriv.export({ format: 'raw-private' }),
335+
format: 'raw-seed',
336+
asymmetricKeyType: 'ec',
337+
namedCurve: 'P-256',
338+
}), { code: 'ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS' });
329339

330340
if (process.features.openssl_is_boringssl) {
331341
common.printSkipMessage('Skipping unsupported ed448/x448 test cases');
@@ -337,13 +347,23 @@ if (hasOpenSSL(3, 5)) {
337347
fixtures.readKey(`${type}_private.pem`, 'ascii'));
338348
assert.throws(() => priv.export({ format: 'raw-seed' }),
339349
{ code: 'ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS' });
350+
assert.throws(() => crypto.createPrivateKey({
351+
key: priv.export({ format: 'raw-private' }),
352+
format: 'raw-seed',
353+
asymmetricKeyType: type,
354+
}), { code: 'ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS' });
340355
}
341356

342357
if (hasOpenSSL(3, 5)) {
343358
const slhPriv = crypto.createPrivateKey(
344359
fixtures.readKey('slh_dsa_sha2_128f_private.pem', 'ascii'));
345360
assert.throws(() => slhPriv.export({ format: 'raw-seed' }),
346361
{ code: 'ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS' });
362+
assert.throws(() => crypto.createPrivateKey({
363+
key: slhPriv.export({ format: 'raw-private' }),
364+
format: 'raw-seed',
365+
asymmetricKeyType: 'slh-dsa-sha2-128f',
366+
}), { code: 'ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS' });
347367
}
348368
}
349369

@@ -354,6 +374,11 @@ if (hasOpenSSL(3, 5) || process.features.openssl_is_boringssl) {
354374
fixtures.readKey(`${type.replaceAll('-', '_')}_private_seed_only.pem`, 'ascii'));
355375
assert.throws(() => priv.export({ format: 'raw-private' }),
356376
{ code: 'ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS' });
377+
assert.throws(() => crypto.createPrivateKey({
378+
key: priv.export({ format: 'raw-seed' }),
379+
format: 'raw-private',
380+
asymmetricKeyType: type,
381+
}), { code: 'ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS' });
357382
}
358383
}
359384

test/parallel/test-crypto-pqc-key-objects-slh-dsa.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ for (const asymmetricKeyType of [
9191
key: rawPriv, format: 'raw-private', asymmetricKeyType,
9292
});
9393
assert.strictEqual(importedPriv.equals(key), true);
94+
assert.throws(() => createPrivateKey({
95+
key: rawPriv, format: 'raw-seed', asymmetricKeyType,
96+
}), { code: 'ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS' });
97+
assert.throws(() => createPublicKey({
98+
key: rawPriv, format: 'raw-seed', asymmetricKeyType,
99+
}), { code: 'ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS' });
94100
}
95101

96102
if (!hasOpenSSL(3, 5)) {

0 commit comments

Comments
 (0)