evp: fix EVP_PKEY2PKCS8 returning NULL for private-key-only EC keys

When an EC_KEY is created via EC_KEY_new + EC_KEY_set_group +
EC_KEY_set_private_key (no public point set), SetECKeyInternal
incorrectly marks the internal ecc_key as ECC_PRIVATEKEY (instead of
ECC_PRIVATEKEY_ONLY) because pub_key is always non-NULL — EC_KEY_new
always allocates it as an empty, zero-initialised EC_POINT.

ECC_populate_EVP_PKEY only calls wc_ecc_make_pub for ECC_PRIVATEKEY_ONLY
keys, so the zero public-key point was serialised into the DER stored in
pkey->pkey.ptr.  After commit 929dd9913 made wc_ecc_import_x963_ex always
pass untrusted=1, the re-decode inside wolfSSL_EVP_PKEY2PKCS8 →
wolfSSL_d2i_PrivateKey_EVP correctly rejected that zero point with an
on-curve failure, causing EVP_PKEY2PKCS8 to return NULL.

Fix: in ECC_populate_EVP_PKEY, also call wc_ecc_make_pub when the key
type is ECC_PRIVATEKEY but pubkey.x is zero (meaning the public key was
never actually populated).  This reconstructs the public key from the
private scalar so that the encoded DER contains a valid on-curve point.
This commit is contained in:
Tobias Frauenschläger
2026-04-05 20:08:57 +02:00
parent 0fb2d2ec11
commit e32e926f4e
+15 -1
View File
@@ -3704,6 +3704,10 @@ int wolfSSL_EVP_PKEY_keygen_init(WOLFSSL_EVP_PKEY_CTX *ctx)
return WOLFSSL_SUCCESS;
}
#ifdef HAVE_ECC
static int ECC_populate_EVP_PKEY(WOLFSSL_EVP_PKEY* pkey, WOLFSSL_EC_KEY *key);
#endif
int wolfSSL_EVP_PKEY_keygen(WOLFSSL_EVP_PKEY_CTX *ctx,
WOLFSSL_EVP_PKEY **ppkey)
{
@@ -3758,6 +3762,8 @@ int wolfSSL_EVP_PKEY_keygen(WOLFSSL_EVP_PKEY_CTX *ctx,
ret = wolfSSL_EC_KEY_generate_key(pkey->ecc);
if (ret == WOLFSSL_SUCCESS) {
pkey->ownEcc = 1;
if (ECC_populate_EVP_PKEY(pkey, pkey->ecc) != WOLFSSL_SUCCESS)
ret = WOLFSSL_FAILURE;
}
}
break;
@@ -9516,7 +9522,15 @@ static int ECC_populate_EVP_PKEY(WOLFSSL_EVP_PKEY* pkey, WOLFSSL_EC_KEY *key)
else
#endif /* HAVE_PKCS8 */
{
if (ecc->type == ECC_PRIVATEKEY_ONLY) {
if (ecc->type == ECC_PRIVATEKEY_ONLY ||
(ecc->type == ECC_PRIVATEKEY &&
mp_iszero(ecc->pubkey.x))) {
/* Reconstruct public key from private scalar. This covers
* both ECC_PRIVATEKEY_ONLY keys and ECC_PRIVATEKEY keys whose
* public-key point was never populated (e.g. when only
* EC_KEY_set_private_key was called, SetECKeyInternal copies
* the zero-initialized pub_key point and marks the type as
* ECC_PRIVATEKEY, leaving pubkey.x == 0). */
if (wc_ecc_make_pub(ecc, NULL) != MP_OKAY) {
return WOLFSSL_FAILURE;
}