From f79cb9007124e387f27a375dec6088d6b67fee6e Mon Sep 17 00:00:00 2001 From: Takashi Kojo Date: Fri, 7 Aug 2026 07:18:12 +0900 Subject: [PATCH] Do not free caller's EVP_PKEY until d2i has a replacement --- tests/api/test_ossl_pem.c | 28 ++++++++++++++++++++++++++++ wolfcrypt/src/evp_pk.c | 10 ++++------ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/tests/api/test_ossl_pem.c b/tests/api/test_ossl_pem.c index 526cc713c3..89b3b417e7 100644 --- a/tests/api/test_ossl_pem.c +++ b/tests/api/test_ossl_pem.c @@ -679,6 +679,34 @@ int test_wolfSSL_PEM_PrivateKey_mldsa(void) } BIO_free(bio); bio = NULL; + + /* A failed read into the same pointer must leave the held key + * untouched, not freed (the caller would otherwise be left with + * a dangling pointer and a later double free). */ + { + static const char badPem[] = + "-----BEGIN PRIVATE KEY-----\n" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n" + "-----END PRIVATE KEY-----\n"; + static const unsigned char junk[8] = + { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; + const unsigned char* jp = junk; + + ExpectNull(wolfSSL_d2i_PrivateKey(WC_EVP_PKEY_DILITHIUM, &pkey, + &jp, (long)sizeof(junk))); + ExpectNotNull(pkey); + ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM); + + ExpectNotNull(bio = BIO_new_mem_buf(badPem, + (int)sizeof(badPem) - 1)); + ExpectNull(wolfSSL_PEM_read_bio_PrivateKey(bio, &pkey, NULL, + NULL)); + ExpectNotNull(pkey); + ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM); + BIO_free(bio); + bio = NULL; + } + EVP_PKEY_free(pkey); pkey = NULL; } diff --git a/wolfcrypt/src/evp_pk.c b/wolfcrypt/src/evp_pk.c index defa3fc756..e70ca24c9f 100644 --- a/wolfcrypt/src/evp_pk.c +++ b/wolfcrypt/src/evp_pk.c @@ -1501,12 +1501,8 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out, } } - /* Dispose of any WOLFSSL_EVP_PKEY passed in. */ - if (out != NULL && *out != NULL) { - wolfSSL_EVP_PKEY_free(*out); - *out = NULL; - } - /* Create a new WOLFSSL_EVP_PKEY and populate. */ + /* Create a new WOLFSSL_EVP_PKEY and populate. Any WOLFSSL_EVP_PKEY + * passed in is replaced only on success. */ local = wolfSSL_EVP_PKEY_new(); if (local == NULL) { return NULL; @@ -1631,6 +1627,8 @@ static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out, *in += local->pkey_sz; } if (out != NULL) { + /* Dispose of any WOLFSSL_EVP_PKEY passed in. */ + wolfSSL_EVP_PKEY_free(*out); *out = local; } }