Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/wp_ecc_kmgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,31 @@ static int wp_ecc_import_keypair(wp_Ecc* ecc, const OSSL_PARAM params[],
) {
ecc->key.type = ECC_PRIVATEKEY;
ecc->hasPriv = 1;

/* Auto-derive public key if not already present and curve is
* set with OpenSSL version newer than 3.6.0 */
#if OPENSSL_VERSION_NUMBER > 0x30600000L
if (!ecc->hasPub && ecc->curveId != 0) {
int rc;

rc = wc_ecc_set_curve(&ecc->key, 0, ecc->curveId);
if (rc == 0) {
#ifdef ECC_TIMING_RESISTANT
rc = wc_ecc_make_pub_ex(&ecc->key, NULL, &ecc->rng);
#else
rc = wc_ecc_make_pub_ex(&ecc->key, NULL, NULL);
#endif
/* Indicate public key is available if derivation succeeds */
if (rc == 0) {
ecc->key.type = ECC_PRIVATEKEY;
ecc->hasPub = 1;
}
/* If derivation fails, continue.
* The key is still valid for private key operations.
* We will fail later if public key is accessed. */
}
}
#endif /* OPENSSL_VERSION_NUMBER > 0x30600000L 3.6.0+ */
}

WOLFPROV_LEAVE(WP_LOG_COMP_ECC, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok);
Expand Down
150 changes: 148 additions & 2 deletions test/test_ecc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1877,7 +1877,51 @@ static int test_ec_import_priv(void)
err = EVP_PKEY_fromdata(ctx2, &pkey2, EVP_PKEY_KEYPAIR, params) != 1;
}

/* For imported private only keys, get bn params should fail */
/* For imported private only keys, public key params behavior depends on OpenSSL version */
#if OPENSSL_VERSION_NUMBER > 0x30600000L
/* OpenSSL 3.6.0+ auto-derives public keys from private keys */
if (err == 0) {
err = EVP_PKEY_get_bn_param(pkey1, OSSL_PKEY_PARAM_EC_PUB_X, &x1) != 1;
}
if (err == 0) {
err = EVP_PKEY_get_bn_param(pkey2, OSSL_PKEY_PARAM_EC_PUB_X, &x2) != 1;
}
if (err == 0) {
err = EVP_PKEY_get_bn_param(pkey1, OSSL_PKEY_PARAM_EC_PUB_Y, &y1) != 1;
}
if (err == 0) {
err = EVP_PKEY_get_bn_param(pkey2, OSSL_PKEY_PARAM_EC_PUB_Y, &y2) != 1;
}

/* Verify public key is available */
if (err == 0) {
if (EVP_PKEY_get_octet_string_param(pkey1,
OSSL_PKEY_PARAM_PUB_KEY, NULL, 0, (size_t *)&len) != 1) {
err = 1;
}
}
if (err == 0) {
if (EVP_PKEY_get_octet_string_param(pkey2,
OSSL_PKEY_PARAM_PUB_KEY, NULL, 0, (size_t *)&len) != 1) {
err = 1;
}
}

/* Verify encoded public key is available */
if (err == 0) {
if (EVP_PKEY_get_octet_string_param(pkey1,
OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0, (size_t *)&len) != 1) {
err = 1;
}
}
if (err == 0) {
if (EVP_PKEY_get_octet_string_param(pkey2,
OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0, (size_t *)&len) != 1) {
err = 1;
}
}
#else
/* OpenSSL < 3.6.0: private-only keys should not have public components */
if (err == 0) {
err = EVP_PKEY_get_bn_param(pkey1, OSSL_PKEY_PARAM_EC_PUB_X, &x1) == 1;
}
Expand Down Expand Up @@ -1918,7 +1962,8 @@ static int test_ec_import_priv(void)
err = 1;
}
}
#endif
#endif /* OPENSSL_VERSION_NUMBER >= 0x30006000L 3.0.6+ */
#endif /* OPENSSL_VERSION_NUMBER > 0x30600000L 3.6.0+ */

EVP_PKEY_free(pkey1);
EVP_PKEY_free(pkey2);
Expand Down Expand Up @@ -2060,4 +2105,105 @@ int test_ec_null_init(void* data)
return err;
}

#if OPENSSL_VERSION_NUMBER > 0x30600000L
static int test_ec_auto_derive_pub(void)
{
int err = 0;
EVP_PKEY_CTX *ctx = NULL;
EVP_PKEY* pkey = NULL;
OSSL_PARAM *params = NULL;
OSSL_PARAM_BLD *bld = NULL;
BIGNUM* priv = NULL;
BIGNUM* pub_x = NULL;
BIGNUM* pub_y = NULL;
unsigned char pub_key[65] = {0};
size_t pub_key_len = sizeof(pub_key);

/* Build params with private key only (no public key) */
err = (bld = OSSL_PARAM_BLD_new()) == NULL;
if (err == 0) {
err = OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME,
ecc_p256_group_str, 0) != 1;
}
if (err == 0) {
err = (priv = BN_bin2bn(ecc_p256_priv, sizeof(ecc_p256_priv), NULL)) == NULL;
}
if (err == 0) {
err = OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1;
}
if (err == 0) {
err = (params = OSSL_PARAM_BLD_to_param(bld)) == NULL;
}
/* Import key using wolfProvider */
if (err == 0) {
err = (ctx = EVP_PKEY_CTX_new_from_name(wpLibCtx, "EC", NULL)) == NULL;
}
if (err == 0) {
err = EVP_PKEY_fromdata_init(ctx) != 1;
}
if (err == 0) {
err = EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEYPAIR, params) != 1;
}
/* Verify public X coordinate is available (auto-derived) */
if (err == 0) {
err = EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_X, &pub_x) != 1;
}
/* Verify public Y coordinate is available (auto-derived) */
if (err == 0) {
err = EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &pub_y) != 1;
}
/* Verify public key octet string is available */
if (err == 0) {
err = EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY,
pub_key, pub_key_len, &pub_key_len) != 1;
}
if (err == 0) {
if (pub_key_len == 0 || pub_key_len > sizeof(pub_key)) {
err = 1;
}
}
/* Verify encoded public key is available */
if (err == 0) {
pub_key_len = sizeof(pub_key);
err = EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
pub_key, pub_key_len, &pub_key_len) != 1;
}
if (err == 0) {
if (pub_key_len == 0 || pub_key_len > sizeof(pub_key)) {
err = 1;
}
}
/* Verify the derived public key is valid (non-zero coordinates) */
if (err == 0) {
if (BN_is_zero(pub_x) || BN_is_zero(pub_y)) {
err = 1;
}
}

EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(ctx);
OSSL_PARAM_free(params);
OSSL_PARAM_BLD_free(bld);
BN_clear_free(priv);
BN_free(pub_x);
BN_free(pub_y);

return err;
}
#endif /* OPENSSL_VERSION_NUMBER > 0x30600000L */

int test_ec_auto_derive_pubkey(void* data)
{
int err = 0;
(void)data;

#if OPENSSL_VERSION_NUMBER > 0x30600000L
err = test_ec_auto_derive_pub();
#else
err = 0;
#endif

return err;
}

#endif /* WP_HAVE_ECC */
1 change: 1 addition & 0 deletions test/unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ TEST_CASE test_case[] = {
#endif
TEST_DECL(test_ec_decode, NULL),
TEST_DECL(test_ec_import, NULL),
TEST_DECL(test_ec_auto_derive_pubkey, NULL),
TEST_DECL(test_ec_null_init, NULL),
#endif
#ifdef WP_HAVE_EC_P384
Expand Down
1 change: 1 addition & 0 deletions test/unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ int test_ec_load_cert(void* data);

int test_ec_decode(void* data);
int test_ec_import(void* data);
int test_ec_auto_derive_pubkey(void* data);
int test_ec_null_init(void* data);

#endif /* WP_HAVE_ECC */
Expand Down
Loading