Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 541be3a

Browse filesBrowse files
panvaaduh95
authored andcommitted
crypto: recognize raw formats in keygen
Signed-off-by: Filip Skokan <panva.ip@gmail.com> PR-URL: #62480 Backport-PR-URL: #62455 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
1 parent 54ef940 commit 541be3a
Copy full SHA for 541be3a

4 files changed

+488-1Lines changed: 488 additions & 1 deletion

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎deps/ncrypto/ncrypto.h‎

Copy file name to clipboardExpand all lines: deps/ncrypto/ncrypto.h
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,9 @@ class EVPKeyPointer final {
855855
DER,
856856
PEM,
857857
JWK,
858+
RAW_PUBLIC,
859+
RAW_PRIVATE,
860+
RAW_SEED,
858861
};
859862

860863
enum class PKParseError { NOT_RECOGNIZED, NEED_PASSPHRASE, FAILED };
@@ -864,6 +867,7 @@ class EVPKeyPointer final {
864867
bool output_key_object = false;
865868
PKFormatType format = PKFormatType::DER;
866869
PKEncodingType type = PKEncodingType::PKCS8;
870+
int ec_point_form = POINT_CONVERSION_UNCOMPRESSED;
867871
AsymmetricKeyEncodingConfig() = default;
868872
AsymmetricKeyEncodingConfig(bool output_key_object,
869873
PKFormatType format,
Collapse file

‎lib/internal/crypto/keys.js‎

Copy file name to clipboardExpand all lines: lib/internal/crypto/keys.js
+44Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ const {
2121
kKeyFormatPEM,
2222
kKeyFormatDER,
2323
kKeyFormatJWK,
24+
kKeyFormatRawPublic,
25+
kKeyFormatRawPrivate,
26+
kKeyFormatRawSeed,
2427
kKeyEncodingPKCS1,
2528
kKeyEncodingPKCS8,
2629
kKeyEncodingSPKI,
@@ -419,6 +422,12 @@ function parseKeyFormat(formatStr, defaultFormat, optionName) {
419422
return kKeyFormatDER;
420423
else if (formatStr === 'jwk')
421424
return kKeyFormatJWK;
425+
else if (formatStr === 'raw-public')
426+
return kKeyFormatRawPublic;
427+
else if (formatStr === 'raw-private')
428+
return kKeyFormatRawPrivate;
429+
else if (formatStr === 'raw-seed')
430+
return kKeyFormatRawSeed;
422431
throw new ERR_INVALID_ARG_VALUE(optionName, formatStr);
423432
}
424433

@@ -459,6 +468,33 @@ function parseKeyFormatAndType(enc, keyType, isPublic, objName) {
459468
isInput ? kKeyFormatPEM : undefined,
460469
option('format', objName));
461470

471+
if (format === kKeyFormatRawPublic) {
472+
if (isPublic === false) {
473+
throw new ERR_INVALID_ARG_VALUE(option('format', objName), 'raw-public');
474+
}
475+
let type;
476+
if (typeStr === undefined || typeStr === 'uncompressed') {
477+
type = POINT_CONVERSION_UNCOMPRESSED;
478+
} else if (typeStr === 'compressed') {
479+
type = POINT_CONVERSION_COMPRESSED;
480+
} else {
481+
throw new ERR_INVALID_ARG_VALUE(option('type', objName), typeStr);
482+
}
483+
return { format, type };
484+
}
485+
486+
if (format === kKeyFormatRawPrivate || format === kKeyFormatRawSeed) {
487+
if (isPublic === true) {
488+
throw new ERR_INVALID_ARG_VALUE(
489+
option('format', objName),
490+
format === kKeyFormatRawPrivate ? 'raw-private' : 'raw-seed');
491+
}
492+
if (typeStr !== undefined) {
493+
throw new ERR_INVALID_ARG_VALUE(option('type', objName), typeStr);
494+
}
495+
return { format };
496+
}
497+
462498
const isRequired = (!isInput ||
463499
format === kKeyFormatDER) &&
464500
format !== kKeyFormatJWK;
@@ -490,6 +526,14 @@ function parseKeyEncoding(enc, keyType, isPublic, objName) {
490526
if (isPublic !== true) {
491527
({ cipher, passphrase, encoding } = enc);
492528

529+
if (format === kKeyFormatRawPrivate || format === kKeyFormatRawSeed) {
530+
if (cipher != null || passphrase !== undefined) {
531+
throw new ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(
532+
'raw format', 'does not support encryption');
533+
}
534+
return { format, type };
535+
}
536+
493537
if (!isInput) {
494538
if (cipher != null) {
495539
if (typeof cipher !== 'string')
Collapse file

‎src/crypto/crypto_keys.cc‎

Copy file name to clipboardExpand all lines: src/crypto/crypto_keys.cc
+155-1Lines changed: 155 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,16 @@ Maybe<EVPKeyPointer::AsymmetricKeyEncodingConfig> GetKeyFormatAndTypeFromJs(
6767
config.format = static_cast<EVPKeyPointer::PKFormatType>(
6868
args[*offset].As<Int32>()->Value());
6969

70-
if (args[*offset + 1]->IsInt32()) {
70+
if (config.format == EVPKeyPointer::PKFormatType::RAW_PUBLIC ||
71+
config.format == EVPKeyPointer::PKFormatType::RAW_PRIVATE ||
72+
config.format == EVPKeyPointer::PKFormatType::RAW_SEED) {
73+
// Raw formats use the type slot for ec_point_form (int) or null.
74+
if (args[*offset + 1]->IsInt32()) {
75+
config.ec_point_form = args[*offset + 1].As<Int32>()->Value();
76+
} else {
77+
CHECK(args[*offset + 1]->IsNullOrUndefined());
78+
}
79+
} else if (args[*offset + 1]->IsInt32()) {
7180
config.type = static_cast<EVPKeyPointer::PKEncodingType>(
7281
args[*offset + 1].As<Int32>()->Value());
7382
} else {
@@ -325,6 +334,54 @@ bool KeyObjectData::ToEncodedPublicKey(
325334
*out = Object::New(env->isolate());
326335
return ExportJWKInner(
327336
env, addRefWithType(KeyType::kKeyTypePublic), *out, false);
337+
} else if (config.format == EVPKeyPointer::PKFormatType::RAW_PUBLIC) {
338+
Mutex::ScopedLock lock(mutex());
339+
const auto& pkey = GetAsymmetricKey();
340+
if (pkey.id() == EVP_PKEY_EC) {
341+
const EC_KEY* ec_key = pkey;
342+
CHECK_NOT_NULL(ec_key);
343+
auto form = static_cast<point_conversion_form_t>(config.ec_point_form);
344+
const auto group = ECKeyPointer::GetGroup(ec_key);
345+
const auto point = ECKeyPointer::GetPublicKey(ec_key);
346+
return ECPointToBuffer(env, group, point, form).ToLocal(out);
347+
}
348+
switch (pkey.id()) {
349+
case EVP_PKEY_ED25519:
350+
case EVP_PKEY_ED448:
351+
case EVP_PKEY_X25519:
352+
case EVP_PKEY_X448:
353+
#if OPENSSL_WITH_PQC
354+
case EVP_PKEY_ML_DSA_44:
355+
case EVP_PKEY_ML_DSA_65:
356+
case EVP_PKEY_ML_DSA_87:
357+
case EVP_PKEY_ML_KEM_512:
358+
case EVP_PKEY_ML_KEM_768:
359+
case EVP_PKEY_ML_KEM_1024:
360+
case EVP_PKEY_SLH_DSA_SHA2_128F:
361+
case EVP_PKEY_SLH_DSA_SHA2_128S:
362+
case EVP_PKEY_SLH_DSA_SHA2_192F:
363+
case EVP_PKEY_SLH_DSA_SHA2_192S:
364+
case EVP_PKEY_SLH_DSA_SHA2_256F:
365+
case EVP_PKEY_SLH_DSA_SHA2_256S:
366+
case EVP_PKEY_SLH_DSA_SHAKE_128F:
367+
case EVP_PKEY_SLH_DSA_SHAKE_128S:
368+
case EVP_PKEY_SLH_DSA_SHAKE_192F:
369+
case EVP_PKEY_SLH_DSA_SHAKE_192S:
370+
case EVP_PKEY_SLH_DSA_SHAKE_256F:
371+
case EVP_PKEY_SLH_DSA_SHAKE_256S:
372+
#endif
373+
break;
374+
default:
375+
THROW_ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(env);
376+
return false;
377+
}
378+
auto raw_data = pkey.rawPublicKey();
379+
if (!raw_data) {
380+
THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to get raw public key");
381+
return false;
382+
}
383+
return Buffer::Copy(env, raw_data.get<const char>(), raw_data.size())
384+
.ToLocal(out);
328385
}
329386

330387
return WritePublicKey(env, GetAsymmetricKey(), config).ToLocal(out);
@@ -343,6 +400,86 @@ bool KeyObjectData::ToEncodedPrivateKey(
343400
*out = Object::New(env->isolate());
344401
return ExportJWKInner(
345402
env, addRefWithType(KeyType::kKeyTypePrivate), *out, false);
403+
} else if (config.format == EVPKeyPointer::PKFormatType::RAW_PRIVATE) {
404+
Mutex::ScopedLock lock(mutex());
405+
const auto& pkey = GetAsymmetricKey();
406+
if (pkey.id() == EVP_PKEY_EC) {
407+
const EC_KEY* ec_key = pkey;
408+
CHECK_NOT_NULL(ec_key);
409+
const BIGNUM* private_key = ECKeyPointer::GetPrivateKey(ec_key);
410+
CHECK_NOT_NULL(private_key);
411+
const auto group = ECKeyPointer::GetGroup(ec_key);
412+
auto order = BignumPointer::New();
413+
CHECK(order);
414+
CHECK(EC_GROUP_get_order(group, order.get(), nullptr));
415+
auto buf = BignumPointer::EncodePadded(private_key, order.byteLength());
416+
if (!buf) {
417+
THROW_ERR_CRYPTO_OPERATION_FAILED(env,
418+
"Failed to export EC private key");
419+
return false;
420+
}
421+
return Buffer::Copy(env, buf.get<const char>(), buf.size()).ToLocal(out);
422+
}
423+
switch (pkey.id()) {
424+
case EVP_PKEY_ED25519:
425+
case EVP_PKEY_ED448:
426+
case EVP_PKEY_X25519:
427+
case EVP_PKEY_X448:
428+
#if OPENSSL_WITH_PQC
429+
case EVP_PKEY_SLH_DSA_SHA2_128F:
430+
case EVP_PKEY_SLH_DSA_SHA2_128S:
431+
case EVP_PKEY_SLH_DSA_SHA2_192F:
432+
case EVP_PKEY_SLH_DSA_SHA2_192S:
433+
case EVP_PKEY_SLH_DSA_SHA2_256F:
434+
case EVP_PKEY_SLH_DSA_SHA2_256S:
435+
case EVP_PKEY_SLH_DSA_SHAKE_128F:
436+
case EVP_PKEY_SLH_DSA_SHAKE_128S:
437+
case EVP_PKEY_SLH_DSA_SHAKE_192F:
438+
case EVP_PKEY_SLH_DSA_SHAKE_192S:
439+
case EVP_PKEY_SLH_DSA_SHAKE_256F:
440+
case EVP_PKEY_SLH_DSA_SHAKE_256S:
441+
#endif
442+
break;
443+
default:
444+
THROW_ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(env);
445+
return false;
446+
}
447+
auto raw_data = pkey.rawPrivateKey();
448+
if (!raw_data) {
449+
THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to get raw private key");
450+
return false;
451+
}
452+
return Buffer::Copy(env, raw_data.get<const char>(), raw_data.size())
453+
.ToLocal(out);
454+
} else if (config.format == EVPKeyPointer::PKFormatType::RAW_SEED) {
455+
Mutex::ScopedLock lock(mutex());
456+
const auto& pkey = GetAsymmetricKey();
457+
switch (pkey.id()) {
458+
#if OPENSSL_WITH_PQC
459+
case EVP_PKEY_ML_DSA_44:
460+
case EVP_PKEY_ML_DSA_65:
461+
case EVP_PKEY_ML_DSA_87:
462+
case EVP_PKEY_ML_KEM_512:
463+
case EVP_PKEY_ML_KEM_768:
464+
case EVP_PKEY_ML_KEM_1024:
465+
break;
466+
#endif
467+
default:
468+
THROW_ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(env);
469+
return false;
470+
}
471+
#if OPENSSL_WITH_PQC
472+
auto raw_data = pkey.rawSeed();
473+
if (!raw_data) {
474+
THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to get raw seed");
475+
return false;
476+
}
477+
return Buffer::Copy(env, raw_data.get<const char>(), raw_data.size())
478+
.ToLocal(out);
479+
#else
480+
THROW_ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(env);
481+
return false;
482+
#endif
346483
}
347484

348485
return WritePrivateKey(env, GetAsymmetricKey(), config).ToLocal(out);
@@ -363,6 +500,14 @@ KeyObjectData::GetPrivateKeyEncodingFromJs(
363500
if (config.output_key_object) {
364501
if (context != kKeyContextInput)
365502
(*offset)++;
503+
} else if (config.format == EVPKeyPointer::PKFormatType::RAW_PRIVATE ||
504+
config.format == EVPKeyPointer::PKFormatType::RAW_SEED) {
505+
// Raw formats don't support encryption. Still consume the arg offsets.
506+
if (context != kKeyContextInput) {
507+
CHECK(args[*offset]->IsNullOrUndefined());
508+
(*offset)++;
509+
}
510+
CHECK(args[*offset]->IsNullOrUndefined());
366511
} else {
367512
bool needs_passphrase = false;
368513
if (context != kKeyContextInput) {
@@ -1581,6 +1726,12 @@ void Initialize(Environment* env, Local<Object> target) {
15811726
static_cast<int>(EVPKeyPointer::PKFormatType::PEM);
15821727
constexpr int kKeyFormatJWK =
15831728
static_cast<int>(EVPKeyPointer::PKFormatType::JWK);
1729+
constexpr int kKeyFormatRawPublic =
1730+
static_cast<int>(EVPKeyPointer::PKFormatType::RAW_PUBLIC);
1731+
constexpr int kKeyFormatRawPrivate =
1732+
static_cast<int>(EVPKeyPointer::PKFormatType::RAW_PRIVATE);
1733+
constexpr int kKeyFormatRawSeed =
1734+
static_cast<int>(EVPKeyPointer::PKFormatType::RAW_SEED);
15841735

15851736
constexpr auto kSigEncDER = DSASigEnc::DER;
15861737
constexpr auto kSigEncP1363 = DSASigEnc::P1363;
@@ -1620,6 +1771,9 @@ void Initialize(Environment* env, Local<Object> target) {
16201771
NODE_DEFINE_CONSTANT(target, kKeyFormatDER);
16211772
NODE_DEFINE_CONSTANT(target, kKeyFormatPEM);
16221773
NODE_DEFINE_CONSTANT(target, kKeyFormatJWK);
1774+
NODE_DEFINE_CONSTANT(target, kKeyFormatRawPublic);
1775+
NODE_DEFINE_CONSTANT(target, kKeyFormatRawPrivate);
1776+
NODE_DEFINE_CONSTANT(target, kKeyFormatRawSeed);
16231777
NODE_DEFINE_CONSTANT(target, kKeyTypeSecret);
16241778
NODE_DEFINE_CONSTANT(target, kKeyTypePublic);
16251779
NODE_DEFINE_CONSTANT(target, kKeyTypePrivate);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.