Skip to content

Commit 8feccc5

Browse files
panvaaduh95
authored andcommitted
crypto: use provider EC group names
Pass group names through EC key generation and report provider names in key details without requiring an OpenSSL NID. Preserve established curve aliases and synchronous invalid-curve errors. Filter built-in curves through EC parameter generation and refresh getCurves() results when FIPS properties change. Signed-off-by: Filip Skokan <panva.ip@gmail.com> Assisted-by: Codex PR-URL: #66108 Backport-PR-URL: #66233 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
1 parent 764e0d1 commit 8feccc5

8 files changed

Lines changed: 336 additions & 19 deletions

File tree

‎deps/ncrypto/ncrypto.cc‎

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6381,10 +6381,15 @@ bool EVPKeyCtxPointer::setDsaParameters(uint32_t bits,
63816381
}
63826382

63836383
bool EVPKeyCtxPointer::setEcParameters(int curve, int encoding) {
6384-
if (!ctx_) return false;
6384+
return setEcParameters(OBJ_nid2sn(curve), encoding);
6385+
}
6386+
6387+
bool EVPKeyCtxPointer::setEcParameters(const char* group_name, int encoding) {
6388+
if (!ctx_ || group_name == nullptr) return false;
6389+
const int curve = Ec::GetCurveIdFromName(group_name);
63856390
#if NCRYPTO_USE_OPENSSL3_PROVIDER
6386-
const char* group_name = OBJ_nid2sn(curve);
6387-
if (group_name == nullptr) return false;
6391+
// Keep the historical aliases while allowing names known only to providers.
6392+
if (curve != NID_undef) group_name = OBJ_nid2sn(curve);
63886393

63896394
const char* encoding_name = nullptr;
63906395
switch (encoding) {
@@ -6406,7 +6411,8 @@ bool EVPKeyCtxPointer::setEcParameters(int curve, int encoding) {
64066411
};
64076412
return EVP_PKEY_CTX_set_params(ctx_.get(), params) == 1;
64086413
#else
6409-
return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx_.get(), curve) == 1 &&
6414+
return curve != NID_undef &&
6415+
EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx_.get(), curve) == 1 &&
64106416
EVP_PKEY_CTX_set_ec_param_enc(ctx_.get(), encoding) == 1;
64116417
#endif
64126418
}
@@ -7491,6 +7497,57 @@ int Ec::GetCurveId(const EVPKeyPointer& key) {
74917497
#endif
74927498
}
74937499

7500+
std::optional<std::string> Ec::GetCurveName(const EVPKeyPointer& key) {
7501+
if (!key) return std::nullopt;
7502+
#if NCRYPTO_USE_OPENSSL3_PROVIDER
7503+
size_t length = 0;
7504+
if (EVP_PKEY_get_utf8_string_param(
7505+
key.get(), OSSL_PKEY_PARAM_GROUP_NAME, nullptr, 0, &length) != 1) {
7506+
return std::nullopt;
7507+
}
7508+
std::string name(length, '\0');
7509+
if (EVP_PKEY_get_utf8_string_param(key.get(),
7510+
OSSL_PKEY_PARAM_GROUP_NAME,
7511+
name.data(),
7512+
name.size() + 1,
7513+
&length) != 1) {
7514+
return std::nullopt;
7515+
}
7516+
name.resize(length);
7517+
// Preserve the public short names for the curves OpenSSL already knows.
7518+
const int nid = GetCurveIdFromName(name.c_str());
7519+
return nid == NID_undef ? name : std::string(OBJ_nid2sn(nid));
7520+
#else
7521+
const int nid = GetCurveId(key);
7522+
if (nid == NID_undef) return std::nullopt;
7523+
return std::string(OBJ_nid2sn(nid));
7524+
#endif
7525+
}
7526+
7527+
#if NCRYPTO_USE_OPENSSL3_PROVIDER
7528+
namespace {
7529+
bool IsAvailableEcGroup(const char* name) {
7530+
MarkPopErrorOnReturn mark;
7531+
auto ctx = EVPKeyCtxPointer::NewFromAlgorithm(KeyAlgorithm::EC);
7532+
return ctx.initForParamgen() &&
7533+
ctx.setEcParameters(name, OPENSSL_EC_NAMED_CURVE) && ctx.paramgen();
7534+
}
7535+
} // namespace
7536+
#endif
7537+
7538+
bool Ec::CheckCurveName(const char* name) {
7539+
if (name == nullptr) return false;
7540+
if (GetCurveIdFromName(name) != NID_undef) return true;
7541+
#if NCRYPTO_USE_OPENSSL3_PROVIDER
7542+
// Keep invalid names a synchronous argument error. Generation contexts can
7543+
// defer rejecting a group until parameter generation. Use the same parameter
7544+
// generation path as key generation without requiring parameter import.
7545+
return IsAvailableEcGroup(name);
7546+
#else
7547+
return false;
7548+
#endif
7549+
}
7550+
74947551
int Ec::GetCurveIdFromName(const char* name) {
74957552
int nid = EC_curve_nist2nid(name);
74967553
if (nid == NID_undef) {
@@ -7513,8 +7570,12 @@ bool Ec::GetCurves(Ec::GetCurveCallback callback) {
75137570
if (EC_get_builtin_curves(curves.data(), count) != count) {
75147571
return false;
75157572
}
7516-
for (auto curve : curves) {
7517-
if (!callback(OBJ_nid2sn(curve.nid))) return false;
7573+
for (const auto& curve : curves) {
7574+
const char* name = OBJ_nid2sn(curve.nid);
7575+
#if NCRYPTO_USE_OPENSSL3_PROVIDER
7576+
if (!IsAvailableEcGroup(name)) continue;
7577+
#endif
7578+
if (!callback(name)) return false;
75187579
}
75197580
return true;
75207581
}

‎deps/ncrypto/ncrypto.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,8 @@ class Ec final {
771771

772772
static int GetCurveIdFromName(const char* name);
773773
static int GetCurveId(const EVPKeyPointer& key);
774+
static std::optional<std::string> GetCurveName(const EVPKeyPointer& key);
775+
static bool CheckCurveName(const char* name);
774776
static DataPointer TryExportPublic(const EVPKeyPointer& key,
775777
point_conversion_form_t form);
776778
static DataPointer ExportPrivate(const EVPKeyPointer& key);
@@ -1150,6 +1152,7 @@ class EVPKeyCtxPointer final {
11501152
bool setDhParameters(int prime_size, uint32_t generator);
11511153
bool setDsaParameters(uint32_t bits, std::optional<int> q_bits);
11521154
bool setEcParameters(int curve, int encoding);
1155+
bool setEcParameters(const char* group_name, int encoding);
11531156

11541157
bool setRsaOaepMd(const Digest& md);
11551158
bool setRsaMgf1Md(const Digest& md);

‎lib/internal/crypto/util.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ const {
8080
const { Buffer } = require('buffer');
8181

8282
const {
83-
cachedResult,
8483
emitExperimentalWarning,
8584
filterDuplicateStrings,
8685
lazyDOMException,
@@ -192,7 +191,8 @@ const getMacs = cachedArrayByFipsGeneration(
192191
_macCache = undefined;
193192
});
194193

195-
const getCurves = cachedResult(() => filterDuplicateStrings(_getCurves()));
194+
const getCurves = cachedArrayByFipsGeneration(
195+
() => filterDuplicateStrings(_getCurves()));
196196

197197
function setEngine(id, flags) {
198198
validateString(id, 'id');

‎src/crypto/crypto_ec.cc‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -409,14 +409,18 @@ void ECDH::ConvertKey(const FunctionCallbackInfo<Value>& args) {
409409
}
410410
}
411411

412+
void EcKeyPairParams::MemoryInfo(MemoryTracker* tracker) const {
413+
tracker->TrackField("curve_name", curve_name);
414+
}
415+
412416
EVPKeyCtxPointer EcKeyGenTraits::Setup(EcKeyPairGenConfig* params) {
413417
EVPKeyCtxPointer key_ctx;
414418
if (params->params.algorithm != nullptr) {
415419
key_ctx = EVPKeyCtxPointer::NewFromAlgorithm(*params->params.algorithm);
416420
} else {
417421
auto param_ctx = EVPKeyCtxPointer::NewFromAlgorithm(KeyAlgorithm::EC);
418422
if (!param_ctx.initForParamgen() ||
419-
!param_ctx.setEcParameters(params->params.curve_nid,
423+
!param_ctx.setEcParameters(params->params.curve_name.c_str(),
420424
params->params.param_encoding)) {
421425
return {};
422426
}
@@ -450,11 +454,11 @@ Maybe<void> EcKeyGenTraits::AdditionalConfig(
450454
Utf8Value curve_name(env->isolate(), args[*offset]);
451455
params->params.algorithm = ncrypto::Ec::GetNamedKeyAlgorithm(*curve_name);
452456
if (params->params.algorithm == nullptr) {
453-
params->params.curve_nid = Ec::GetCurveIdFromName(*curve_name);
454-
if (params->params.curve_nid == NID_undef) {
457+
if (!Ec::CheckCurveName(*curve_name)) {
455458
THROW_ERR_CRYPTO_INVALID_CURVE(env);
456459
return Nothing<void>();
457460
}
461+
params->params.curve_name = *curve_name;
458462
}
459463

460464
// param encoding
@@ -762,13 +766,13 @@ bool GetEcKeyDetail(Environment* env,
762766
const auto& m_pkey = key.GetAsymmetricKey();
763767
DCHECK(m_pkey.isA(KeyAlgorithm::EC));
764768

765-
int nid = Ec::GetCurveId(m_pkey);
766-
if (nid == NID_undef) return true;
769+
const auto name = Ec::GetCurveName(m_pkey);
770+
if (!name) return true;
767771

768772
return target
769773
->Set(env->context(),
770774
env->named_curve_string(),
771-
OneByteString(env->isolate(), OBJ_nid2sn(nid)))
775+
OneByteString(env->isolate(), name.value()))
772776
.IsJust();
773777
}
774778

‎src/crypto/crypto_ec.h‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include "node_internals.h"
1414
#include "v8.h"
1515

16+
#include <string>
17+
1618
namespace node {
1719
namespace crypto {
1820

@@ -60,9 +62,9 @@ class ECDH final : public BaseObject {
6062

6163
struct EcKeyPairParams final : public MemoryRetainer {
6264
const ncrypto::KeyAlgorithm* algorithm = nullptr;
63-
int curve_nid = NID_undef;
65+
std::string curve_name;
6466
int param_encoding;
65-
SET_NO_MEMORY_INFO()
67+
void MemoryInfo(MemoryTracker* tracker) const override;
6668
SET_MEMORY_INFO_NAME(EcKeyPairParams)
6769
SET_SELF_SIZE(EcKeyPairParams)
6870
};

0 commit comments

Comments
 (0)