Skip to content

Commit ee956ae

Browse files
panvaaduh95
authored andcommitted
crypto: export EC JWK coordinates directly
Query provider coordinates together instead of serializing and decoding the public point. Assisted-by: GitHub Copilot Signed-off-by: Filip Skokan <[email protected]> PR-URL: #65908 Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
1 parent 684008b commit ee956ae

4 files changed

Lines changed: 96 additions & 23 deletions

File tree

‎benchmark/crypto/ec-jwk-export.js‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const { generateKeyPairSync } = require('crypto');
5+
6+
const bench = common.createBenchmark(main, {
7+
namedCurve: ['prime256v1', 'secp384r1', 'secp521r1', 'secp256k1'],
8+
type: ['public', 'private'],
9+
n: [10000],
10+
});
11+
12+
function main({ namedCurve, type, n }) {
13+
const key = generateKeyPairSync('ec', { namedCurve })[`${type}Key`];
14+
const options = { format: 'jwk' };
15+
bench.start();
16+
for (let index = 0; index < n; index++)
17+
key.export(options);
18+
bench.end(n);
19+
}

‎deps/ncrypto/ncrypto.cc‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6916,6 +6916,65 @@ int Ec::getCurve() const {
69166916
return EC_GROUP_get_curve_name(getGroup());
69176917
}
69186918

6919+
bool Ec::GetKeyComponents(const EVPKeyPointer& key,
6920+
BignumPointer* x,
6921+
BignumPointer* y,
6922+
BignumPointer* priv,
6923+
int* degree) {
6924+
#if NCRYPTO_USE_OPENSSL3_PROVIDER
6925+
const int nid = GetCurveId(key);
6926+
switch (nid) {
6927+
case NID_X9_62_prime256v1:
6928+
case NID_secp256k1:
6929+
*degree = 256;
6930+
break;
6931+
case NID_secp384r1:
6932+
*degree = 384;
6933+
break;
6934+
case NID_secp521r1:
6935+
*degree = 521;
6936+
break;
6937+
default:
6938+
*degree = 0;
6939+
}
6940+
if (*degree != 0) {
6941+
MarkPopErrorOnReturn pop_errors;
6942+
unsigned char x_bytes[66]{};
6943+
unsigned char y_bytes[66]{};
6944+
const size_t width = (*degree + 7) / 8;
6945+
OSSL_PARAM params[] = {
6946+
OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_PUB_X, x_bytes, width),
6947+
OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_PUB_Y, y_bytes, width),
6948+
OSSL_PARAM_construct_end(),
6949+
};
6950+
if (EVP_PKEY_get_params(key.get(), params) == 1 &&
6951+
OSSL_PARAM_modified(&params[0]) && OSSL_PARAM_modified(&params[1])) {
6952+
x->reset(BN_native2bn(x_bytes, width, nullptr));
6953+
y->reset(BN_native2bn(y_bytes, width, nullptr));
6954+
return *x && *y &&
6955+
(priv == nullptr ||
6956+
GetPKeyBnParam(key.get(), OSSL_PKEY_PARAM_PRIV_KEY, priv));
6957+
}
6958+
}
6959+
#endif
6960+
ECKeyPointer ec(key);
6961+
if (!ec || ec.getPublicKey() == nullptr) return false;
6962+
*degree = EC_GROUP_get_degree(ec.getGroup());
6963+
x->reset(BN_new());
6964+
y->reset(BN_new());
6965+
if (!*x || !*y ||
6966+
EC_POINT_get_affine_coordinates(
6967+
ec.getGroup(), ec.getPublicKey(), x->get(), y->get(), nullptr) != 1) {
6968+
return false;
6969+
}
6970+
if (priv != nullptr) {
6971+
if (ec.getPrivateKey() == nullptr) return false;
6972+
priv->reset(BN_dup(ec.getPrivateKey()));
6973+
if (!*priv) return false;
6974+
}
6975+
return true;
6976+
}
6977+
69196978
int Ec::GetCurveId(const EVPKeyPointer& key) {
69206979
#if NCRYPTO_USE_OPENSSL3_PROVIDER
69216980
char name[80];

‎deps/ncrypto/ncrypto.h‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,11 @@ class Ec final {
813813

814814
static int GetCurveIdFromName(const char* name);
815815
static int GetCurveId(const EVPKeyPointer& key);
816+
static bool GetKeyComponents(const EVPKeyPointer& key,
817+
BignumPointer* x,
818+
BignumPointer* y,
819+
BignumPointer* priv,
820+
int* degree);
816821

817822
using GetCurveCallback = std::function<bool(const char*)>;
818823
static bool GetCurves(GetCurveCallback callback);

‎src/crypto/crypto_ec.cc‎

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -625,30 +625,21 @@ bool ExportJWKEcKey(Environment* env,
625625
const auto& m_pkey = key.GetAsymmetricKey();
626626
CHECK_EQ(m_pkey.id(), EVP_PKEY_EC);
627627

628-
ECKeyPointer ec(m_pkey);
629-
if (!ec) {
630-
THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JWK EC key");
628+
BignumPointer x;
629+
BignumPointer y;
630+
BignumPointer priv;
631+
int degree_bits;
632+
if (!Ec::GetKeyComponents(
633+
m_pkey,
634+
&x,
635+
&y,
636+
key.GetKeyType() == kKeyTypePrivate ? &priv : nullptr,
637+
&degree_bits)) {
631638
return false;
632639
}
633-
// A provider-backed key need not expose its public point.
634-
if (ec.getPublicKey() == nullptr) return false;
635-
636-
const auto pub = ec.getPublicKey();
637-
const auto group = ec.getGroup();
638-
639-
int degree_bits = EC_GROUP_get_degree(group);
640640
int degree_bytes =
641641
(degree_bits / CHAR_BIT) + (7 + (degree_bits % CHAR_BIT)) / 8;
642642

643-
auto x = BignumPointer::New();
644-
auto y = BignumPointer::New();
645-
646-
if (!EC_POINT_get_affine_coordinates(group, pub, x.get(), y.get(), nullptr)) {
647-
ThrowCryptoError(env, ERR_get_error(),
648-
"Failed to get elliptic-curve point coordinates");
649-
return false;
650-
}
651-
652643
if (!target
653644
->DefineOwnProperty(
654645
env->context(), env->jwk_kty_string(), env->jwk_ec_string())
@@ -672,7 +663,7 @@ bool ExportJWKEcKey(Environment* env,
672663
}
673664

674665
Local<String> crv_name;
675-
const int nid = EC_GROUP_get_curve_name(group);
666+
const int nid = Ec::GetCurveId(m_pkey);
676667
switch (nid) {
677668
case NID_X9_62_prime256v1:
678669
crv_name = env->p256_string();
@@ -699,9 +690,8 @@ bool ExportJWKEcKey(Environment* env,
699690
}
700691

701692
if (key.GetKeyType() == kKeyTypePrivate) {
702-
auto pvt = ec.getPrivateKey();
703-
if (pvt == nullptr) return false;
704-
return SetEncodedValue(env, target, env->jwk_d_string(), pvt, degree_bytes)
693+
return SetEncodedValue(
694+
env, target, env->jwk_d_string(), priv.get(), degree_bytes)
705695
.IsJust();
706696
}
707697

0 commit comments

Comments
 (0)