Commit 8c141a2cff for openssl.org

commit 8c141a2cffb58f9780615d259da35e8228656c0c
Author: huanghuihui0904 <625173@qq.com>
Date:   Thu Mar 12 19:16:12 2026 +0800

    crypto/evp/exchange.c: fix memory leak in EVP_PKEY_derive_SKEY()

    When mgmt == NULL, EVP_PKEY_derive_SKEY() fetches an EVP_SKEYMGMT into skeymgmt. Some early returns in the fallback derive path do not free this object, causing a leak. Route these paths through shared cleanup so skeymgmt is freed.

    Resolves: https://github.com/openssl/openssl/issues/30378
    Fixes #30378

    Signed-off-by: huanghuihui0904 <625173@qq.com>

    Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
    Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
    Reviewed-by: Paul Dale <paul.dale@oracle.com>
    Reviewed-by: Todd Short <todd.short@me.com>
    (Merged from https://github.com/openssl/openssl/pull/30389)

diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c
index 5bc34d12cf..a5eea9af1d 100644
--- a/crypto/evp/exchange.c
+++ b/crypto/evp/exchange.c
@@ -518,25 +518,25 @@ EVP_SKEY *EVP_PKEY_derive_SKEY(EVP_PKEY_CTX *ctx, EVP_SKEYMGMT *mgmt,

         if (ctx->op.kex.exchange->derive == NULL) {
             ERR_raise(ERR_R_EVP_LIB, ERR_R_UNSUPPORTED);
-            return NULL;
+            goto cleanup;
         }

         key = OPENSSL_zalloc(keylen);
         if (key == NULL) {
             ERR_raise(ERR_R_EVP_LIB, ERR_R_CRYPTO_LIB);
-            return NULL;
+            goto cleanup;
         }

         if (!ctx->op.kex.exchange->derive(ctx->op.kex.algctx, key, &tmplen,
                 tmplen)) {
             OPENSSL_free(key);
-            return NULL;
+            goto cleanup;
         }

         if (keylen != tmplen) {
             OPENSSL_free(key);
             ERR_raise(ERR_R_EVP_LIB, ERR_R_INTERNAL_ERROR);
-            return NULL;
+            goto cleanup;
         }
         import_params[0] = OSSL_PARAM_construct_octet_string(OSSL_SKEY_PARAM_RAW_BYTES,
             key, keylen);
@@ -544,30 +544,25 @@ EVP_SKEY *EVP_PKEY_derive_SKEY(EVP_PKEY_CTX *ctx, EVP_SKEYMGMT *mgmt,
         ret = EVP_SKEY_import_SKEYMGMT(ctx->libctx, skeymgmt,
             OSSL_SKEYMGMT_SELECT_SECRET_KEY, import_params);
         OPENSSL_clear_free(key, keylen);
-        if (mgmt != skeymgmt)
-            EVP_SKEYMGMT_free(skeymgmt);
-        return ret;
+        goto cleanup;
     }

     ret = evp_skey_alloc(skeymgmt);
-    if (ret == NULL) {
-        if (mgmt != skeymgmt)
-            EVP_SKEYMGMT_free(skeymgmt);
-        return NULL;
-    }
+    if (ret == NULL)
+        goto cleanup;

     ret->keydata = ctx->op.kex.exchange->derive_skey(ctx->op.kex.algctx, key_type,
         ossl_provider_ctx(skeymgmt->prov),
         skeymgmt->import, keylen, params);

-    if (mgmt != skeymgmt)
-        EVP_SKEYMGMT_free(skeymgmt);
-
     if (ret->keydata == NULL) {
         EVP_SKEY_free(ret);
-        return NULL;
+        ret = NULL;
+        goto cleanup;
     }
-
+cleanup:
+    if (mgmt != skeymgmt)
+        EVP_SKEYMGMT_free(skeymgmt);
     return ret;
 }