From e32e926f4e789d04615e0edd8fa641058952d010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Sun, 5 Apr 2026 20:08:57 +0200 Subject: [PATCH] evp: fix EVP_PKEY2PKCS8 returning NULL for private-key-only EC keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- wolfcrypt/src/evp.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index b802958a9e..c37363a324 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -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; }