Commit f45bb99670 for openssl.org

commit f45bb9967069bdb37edfad9737d6b9d07ffb7db1
Author: Viktor Dukhovni <openssl-users@dukhovni.org>
Date:   Tue Apr 7 21:46:58 2026 +1000

    Precompute some helper objects in each SSL_CTX

    Instead of repeated fetching, precompute the below per the library
    context and properties of the SSL_CTX and use them for the lifetime of
    the SSL_CTX.

        - HMAC algorithm handle (session ticket HMAC)
        - SHA2-256 algorithm handle (session ticket HMAC)
        - AES_256-CBC algorithm handle (session ticket en/decryption)
        - TLS1 PRF (when TLS <= 1.2 is supported)

    The "sha1" and "md5" handles are no longer used, and those fields are
    removed.

    The `SSL_HMAC` objects used internally are now stack allocated, and the
    associated "new" and "free" functions are now called "construct" and
    "destruct" respectively.

    Reviewed-by: Matt Caswell <matt@openssl.foundation>
    Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
    MergeDate: Mon Apr 13 09:03:45 2026
    (Merged from https://github.com/openssl/openssl/pull/30696)

diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 1b7fe8cb6b..8fb76e96ad 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -20,6 +20,7 @@
 #include <openssl/ocsp.h>
 #include <openssl/dh.h>
 #include <openssl/async.h>
+#include <openssl/kdf.h>
 #include <openssl/ct.h>
 #include <openssl/trace.h>
 #include <openssl/core_names.h>
@@ -4262,6 +4263,17 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
             goto err;
     }

+    if ((ret->hmac = EVP_MAC_fetch(libctx, "HMAC", propq)) == NULL)
+        goto err;
+    if ((ret->sha256 = EVP_MD_fetch(libctx, "SHA2-256", propq)) == NULL)
+        goto err;
+    if ((ret->tktenc = EVP_CIPHER_fetch(libctx, "AES-256-CBC", propq)) == NULL)
+        goto err;
+#if defined(OPENSSL_HAVE_TLS1PRF)
+    if ((ret->tls1prf = EVP_KDF_fetch(libctx, OSSL_KDF_NAME_TLS1_PRF, propq)) == NULL)
+        goto err;
+#endif
+
     ret->method = meth;
     ret->min_proto_version = 0;
     ret->max_proto_version = 0;
@@ -4339,15 +4351,6 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq,
         goto err;
     }

-    /*
-     * If these aren't available from the provider we'll get NULL returns.
-     * That's fine but will cause errors later if SSLv3 is negotiated
-     */
-    ERR_set_mark();
-    ret->md5 = EVP_MD_fetch(libctx, "MD5", propq);
-    ret->sha1 = EVP_MD_fetch(libctx, "SHA1", propq);
-    ERR_pop_to_mark();
-
     if ((ret->ca_names = sk_X509_NAME_new_null()) == NULL) {
         ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
         goto err;
@@ -4589,6 +4592,13 @@ void SSL_CTX_free(SSL_CTX *a)
     if (a->sessions != NULL)
         SSL_CTX_flush_sessions_ex(a, 0);

+    EVP_MAC_free(a->hmac);
+    EVP_MD_free(a->sha256);
+    EVP_CIPHER_free(a->tktenc);
+#ifdef OPENSSL_HAVE_TLS1PRF
+    EVP_KDF_free(a->tls1prf);
+#endif
+
     CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_CTX, a, &a->ex_data);
     lh_SSL_SESSION_free(a->sessions);
     X509_STORE_free(a->cert_store);
@@ -4617,9 +4627,6 @@ void SSL_CTX_free(SSL_CTX *a)
     OPENSSL_free(a->ext.alpn);
     OPENSSL_secure_clear_free(a->ext.secure, sizeof(*a->ext.secure));

-    ssl_evp_md_free(a->md5);
-    ssl_evp_md_free(a->sha1);
-
     for (j = 0; j < SSL_ENC_NUM_IDX; j++)
         ssl_evp_cipher_free(a->ssl_cipher_methods[j]);
     for (j = 0; j < SSL_MD_NUM_IDX; j++)
diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
index a7159d3c19..7edef0bd40 100644
--- a/ssl/ssl_local.h
+++ b/ssl/ssl_local.h
@@ -740,8 +740,8 @@ typedef struct ssl_hmac_st {
 #endif
 } SSL_HMAC;

-SSL_HMAC *ssl_hmac_new(const SSL_CTX *ctx);
-void ssl_hmac_free(SSL_HMAC *ctx);
+SSL_HMAC *ssl_hmac_construct(const SSL_CTX *ctx, SSL_HMAC *hctx);
+void ssl_hmac_destruct(SSL_HMAC *ctx);
 #ifndef OPENSSL_NO_DEPRECATED_3_0
 HMAC_CTX *ssl_hmac_get0_HMAC_CTX(SSL_HMAC *ctx);
 #endif
@@ -807,6 +807,14 @@ typedef struct {

 #define TLS_GROUP_FFDHE_FOR_TLS1_3 (TLS_GROUP_FFDHE | TLS_GROUP_ONLY_FOR_TLS1_3)

+#if !defined(OPENSSL_NO_TLS1)      \
+    || !defined(OPENSSL_NO_TLS1_1) \
+    || !defined(OPENSSL_NO_TLS1_2) \
+    || !defined(OPENSSL_NO_DTLS1)  \
+    || !defined(OPENSSL_NO_DTLS1_2)
+#define OPENSSL_HAVE_TLS1PRF
+#endif
+
 struct ssl_ctx_st {
     OSSL_LIB_CTX *libctx;

@@ -818,6 +826,12 @@ struct ssl_ctx_st {
     STACK_OF(SSL_CIPHER) *tls13_ciphersuites;
     struct x509_store_st /* X509_STORE */ *cert_store;
     LHASH_OF(SSL_SESSION) *sessions;
+    EVP_MAC *hmac;
+    EVP_MD *sha256;
+    EVP_CIPHER *tktenc;
+#ifdef OPENSSL_HAVE_TLS1PRF
+    EVP_KDF *tls1prf;
+#endif
     /*
      * Most session-ids that will be cached, default is
      * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT. 0 is unlimited.
@@ -2923,8 +2937,8 @@ void ssl_evp_cipher_free(const EVP_CIPHER *cipher);
 int ssl_evp_md_up_ref(const EVP_MD *md);
 void ssl_evp_md_free(const EVP_MD *md);

-int ssl_hmac_old_new(SSL_HMAC *ret);
-void ssl_hmac_old_free(SSL_HMAC *ctx);
+SSL_HMAC *ssl_hmac_old_construct(SSL_HMAC *ret);
+void ssl_hmac_old_destruct(SSL_HMAC *ctx);
 int ssl_hmac_old_init(SSL_HMAC *ctx, void *key, size_t len, char *md);
 int ssl_hmac_old_update(SSL_HMAC *ctx, const unsigned char *data, size_t len);
 int ssl_hmac_old_final(SSL_HMAC *ctx, unsigned char *md, size_t *len);
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 36c698c163..538094478b 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -3088,7 +3088,6 @@ MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL_CONNECTION *s,
     unsigned int sess_len;
     RAW_EXTENSION *exts = NULL;
     PACKET nonce;
-    EVP_MD *sha256 = NULL;
     SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);

     PACKET_null_init(&nonce);
@@ -3198,25 +3197,16 @@ MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL_CONNECTION *s,
      * We choose the former approach because this fits in with assumptions
      * elsewhere in OpenSSL. The session ID is set to the SHA256 hash of the
      * ticket.
-     */
-    sha256 = EVP_MD_fetch(sctx->libctx, "SHA2-256", sctx->propq);
-    if (sha256 == NULL) {
-        /* Error is already recorded */
-        SSLfatal_alert(s, SSL_AD_INTERNAL_ERROR);
-        goto err;
-    }
-    /*
+     *
      * We use sess_len here because EVP_Digest expects an int
      * but s->session->session_id_length is a size_t
      */
     if (!EVP_Digest(s->session->ext.tick, ticklen,
             s->session->session_id, &sess_len,
-            sha256, NULL)) {
+            sctx->sha256, NULL)) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
         goto err;
     }
-    EVP_MD_free(sha256);
-    sha256 = NULL;
     s->session->session_id_length = sess_len;
     s->session->not_resumable = 0;

@@ -3255,7 +3245,6 @@ MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL_CONNECTION *s,

     return MSG_PROCESS_CONTINUE_READING;
 err:
-    EVP_MD_free(sha256);
     OPENSSL_free(exts);
     return MSG_PROCESS_ERROR;
 }
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 8197b60530..97455842ec 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -4247,7 +4247,7 @@ static CON_FUNC_RETURN construct_stateless_ticket(SSL_CONNECTION *s,
 {
     unsigned char *senc = NULL;
     EVP_CIPHER_CTX *ctx = NULL;
-    SSL_HMAC *hctx = NULL;
+    SSL_HMAC hctx, *constructed_hctx = NULL;
     unsigned char *p, *encdata1, *encdata2, *macdata1, *macdata2;
     const unsigned char *const_p;
     int len, slen_full, slen, lenfinal;
@@ -4283,8 +4283,7 @@ static CON_FUNC_RETURN construct_stateless_ticket(SSL_CONNECTION *s,
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
         goto err;
     }
-    hctx = ssl_hmac_new(tctx);
-    if (hctx == NULL) {
+    if ((constructed_hctx = ssl_hmac_construct(tctx, &hctx)) == NULL) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_SSL_LIB);
         goto err;
     }
@@ -4335,13 +4334,13 @@ static CON_FUNC_RETURN construct_stateless_ticket(SSL_CONNECTION *s,

         if (tctx->ext.ticket_key_evp_cb != NULL)
             ret = tctx->ext.ticket_key_evp_cb(ssl, key_name, iv, ctx,
-                ssl_hmac_get0_EVP_MAC_CTX(hctx),
+                ssl_hmac_get0_EVP_MAC_CTX(&hctx),
                 1);
 #ifndef OPENSSL_NO_DEPRECATED_3_0
         else if (tctx->ext.ticket_key_cb != NULL)
             /* if 0 is returned, write an empty ticket */
             ret = tctx->ext.ticket_key_cb(ssl, key_name, iv, ctx,
-                ssl_hmac_get0_HMAC_CTX(hctx), 1);
+                ssl_hmac_get0_HMAC_CTX(&hctx), 1);
 #endif

         if (ret == 0) {
@@ -4362,7 +4361,7 @@ static CON_FUNC_RETURN construct_stateless_ticket(SSL_CONNECTION *s,
             }
             OPENSSL_free(senc);
             EVP_CIPHER_CTX_free(ctx);
-            ssl_hmac_free(hctx);
+            ssl_hmac_destruct(constructed_hctx);
             return CON_FUNC_SUCCESS;
         }
         if (ret < 0) {
@@ -4375,28 +4374,17 @@ static CON_FUNC_RETURN construct_stateless_ticket(SSL_CONNECTION *s,
             goto err;
         }
     } else {
-        EVP_CIPHER *cipher = EVP_CIPHER_fetch(sctx->libctx, "AES-256-CBC",
-            sctx->propq);
-
-        if (cipher == NULL) {
-            /* Error is already recorded */
-            SSLfatal_alert(s, SSL_AD_INTERNAL_ERROR);
-            goto err;
-        }
-
-        iv_len = EVP_CIPHER_get_iv_length(cipher);
+        iv_len = EVP_CIPHER_get_iv_length(sctx->tktenc);
         if (iv_len < 0
             || RAND_bytes_ex(sctx->libctx, iv, iv_len, 0) <= 0
-            || !EVP_EncryptInit_ex(ctx, cipher, NULL,
+            || !EVP_EncryptInit_ex(ctx, sctx->tktenc, NULL,
                 tctx->ext.secure->tick_aes_key, iv)
-            || !ssl_hmac_init(hctx, tctx->ext.secure->tick_hmac_key,
+            || !ssl_hmac_init(&hctx, tctx->ext.secure->tick_hmac_key,
                 sizeof(tctx->ext.secure->tick_hmac_key),
                 "SHA256")) {
-            EVP_CIPHER_free(cipher);
             SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
             goto err;
         }
-        EVP_CIPHER_free(cipher);
         memcpy(key_name, tctx->ext.tick_key_name,
             sizeof(tctx->ext.tick_key_name));
     }
@@ -4422,11 +4410,11 @@ static CON_FUNC_RETURN construct_stateless_ticket(SSL_CONNECTION *s,
         || encdata1 + len != encdata2
         || len + lenfinal > slen + EVP_MAX_BLOCK_LENGTH
         || !WPACKET_get_total_written(pkt, &macendoffset)
-        || !ssl_hmac_update(hctx,
+        || !ssl_hmac_update(&hctx,
             (unsigned char *)s->init_buf->data + macoffset,
             macendoffset - macoffset)
         || !WPACKET_reserve_bytes(pkt, EVP_MAX_MD_SIZE, &macdata1)
-        || !ssl_hmac_final(hctx, macdata1, &hlen, EVP_MAX_MD_SIZE)
+        || !ssl_hmac_final(&hctx, macdata1, &hlen, EVP_MAX_MD_SIZE)
         || hlen > EVP_MAX_MD_SIZE
         || !WPACKET_allocate_bytes(pkt, hlen, &macdata2)
         || macdata1 != macdata2) {
@@ -4444,7 +4432,7 @@ static CON_FUNC_RETURN construct_stateless_ticket(SSL_CONNECTION *s,
 err:
     OPENSSL_free(senc);
     EVP_CIPHER_CTX_free(ctx);
-    ssl_hmac_free(hctx);
+    ssl_hmac_destruct(constructed_hctx);
     return ok;
 }

diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index fe5c0d8be3..bcd3082d6b 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -33,10 +33,7 @@ static int tls1_PRF(SSL_CONNECTION *s,
     unsigned char *out, size_t olen, int fatal)
 {
     const EVP_MD *md = ssl_prf_md(s);
-    EVP_KDF *kdf;
     EVP_KDF_CTX *kctx = NULL;
-    OSSL_PARAM params[9], *p = params;
-    const char *mdname;

     if (md == NULL) {
         /* Should never happen */
@@ -46,16 +43,13 @@ static int tls1_PRF(SSL_CONNECTION *s,
             ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
         return 0;
     }
-    kdf = EVP_KDF_fetch(SSL_CONNECTION_GET_CTX(s)->libctx,
-        OSSL_KDF_NAME_TLS1_PRF,
-        SSL_CONNECTION_GET_CTX(s)->propq);
-    if (kdf == NULL)
-        goto err;
-    kctx = EVP_KDF_CTX_new(kdf);
-    EVP_KDF_free(kdf);
+#ifdef OPENSSL_HAVE_TLS1PRF
+    kctx = EVP_KDF_CTX_new(SSL_CONNECTION_GET_CTX(s)->tls1prf);
     if (kctx == NULL)
         goto err;
-    mdname = EVP_MD_get0_name(md);
+
+    const char *mdname = EVP_MD_get0_name(md);
+    OSSL_PARAM params[9], *p = params;
     *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
         (char *)mdname, 0);
     *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SECRET,
@@ -85,6 +79,7 @@ static int tls1_PRF(SSL_CONNECTION *s,
     }

 err:
+#endif
     if (fatal)
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
     else
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index ee33c43be6..e21664b8ee 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -3208,7 +3208,7 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s,
     SSL_TICKET_STATUS ret = SSL_TICKET_FATAL_ERR_OTHER;
     size_t mlen;
     unsigned char tick_hmac[EVP_MAX_MD_SIZE];
-    SSL_HMAC *hctx = NULL;
+    SSL_HMAC hctx, *constructed_hctx = NULL;
     EVP_CIPHER_CTX *ctx = NULL;
     SSL_CTX *tctx = s->session_ctx;
     SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
@@ -3239,8 +3239,8 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s,
     }

     /* Initialize session ticket encryption and HMAC contexts */
-    hctx = ssl_hmac_new(tctx);
-    if (hctx == NULL) {
+
+    if ((constructed_hctx = ssl_hmac_construct(tctx, &hctx)) == NULL) {
         ret = SSL_TICKET_FATAL_ERR_MALLOC;
         goto end;
     }
@@ -3263,14 +3263,14 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s,
                 nctick,
                 nctick + TLSEXT_KEYNAME_LENGTH,
                 ctx,
-                ssl_hmac_get0_EVP_MAC_CTX(hctx),
+                ssl_hmac_get0_EVP_MAC_CTX(&hctx),
                 0);
 #ifndef OPENSSL_NO_DEPRECATED_3_0
         else if (tctx->ext.ticket_key_cb != NULL)
             /* if 0 is returned, write an empty ticket */
             rv = tctx->ext.ticket_key_cb(SSL_CONNECTION_GET_USER_SSL(s), nctick,
                 nctick + TLSEXT_KEYNAME_LENGTH,
-                ctx, ssl_hmac_get0_HMAC_CTX(hctx), 0);
+                ctx, ssl_hmac_get0_HMAC_CTX(&hctx), 0);
 #endif
         if (rv < 0) {
             ret = SSL_TICKET_FATAL_ERR_OTHER;
@@ -3283,8 +3283,6 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s,
         if (rv == 2)
             renew_ticket = 1;
     } else {
-        EVP_CIPHER *aes256cbc = NULL;
-
         /* Check key name matches */
         if (memcmp(etick, tctx->ext.tick_key_name,
                 TLSEXT_KEYNAME_LENGTH)
@@ -3293,22 +3291,16 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s,
             goto end;
         }

-        aes256cbc = EVP_CIPHER_fetch(sctx->libctx, "AES-256-CBC",
-            sctx->propq);
-        if (aes256cbc == NULL
-            || ssl_hmac_init(hctx, tctx->ext.secure->tick_hmac_key,
-                   sizeof(tctx->ext.secure->tick_hmac_key),
-                   "SHA256")
+        if (ssl_hmac_init(&hctx, tctx->ext.secure->tick_hmac_key,
+                sizeof(tctx->ext.secure->tick_hmac_key), "SHA256")
                 <= 0
-            || EVP_DecryptInit_ex(ctx, aes256cbc, NULL,
+            || EVP_DecryptInit_ex(ctx, tctx->tktenc, NULL,
                    tctx->ext.secure->tick_aes_key,
                    etick + TLSEXT_KEYNAME_LENGTH)
                 <= 0) {
-            EVP_CIPHER_free(aes256cbc);
             ret = SSL_TICKET_FATAL_ERR_OTHER;
             goto end;
         }
-        EVP_CIPHER_free(aes256cbc);
         if (SSL_CONNECTION_IS_TLS13(s))
             renew_ticket = 1;
     }
@@ -3316,7 +3308,7 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s,
      * Attempt to process session ticket, first conduct sanity and integrity
      * checks on ticket.
      */
-    mlen = ssl_hmac_size(hctx);
+    mlen = ssl_hmac_size(&hctx);
     if (mlen == 0) {
         ret = SSL_TICKET_FATAL_ERR_OTHER;
         goto end;
@@ -3335,8 +3327,8 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s,
     }
     eticklen -= mlen;
     /* Check HMAC of encrypted ticket */
-    if (ssl_hmac_update(hctx, etick, eticklen) <= 0
-        || ssl_hmac_final(hctx, tick_hmac, NULL, sizeof(tick_hmac)) <= 0) {
+    if (ssl_hmac_update(&hctx, etick, eticklen) <= 0
+        || ssl_hmac_final(&hctx, tick_hmac, NULL, sizeof(tick_hmac)) <= 0) {
         ret = SSL_TICKET_FATAL_ERR_OTHER;
         goto end;
     }
@@ -3398,7 +3390,7 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s,

 end:
     EVP_CIPHER_CTX_free(ctx);
-    ssl_hmac_free(hctx);
+    ssl_hmac_destruct(constructed_hctx);

     /*
      * If set, the decrypt_ticket_cb() is called unless a fatal error was
@@ -5012,41 +5004,28 @@ uint8_t SSL_SESSION_get_max_fragment_length(const SSL_SESSION *session)
 /*
  * Helper functions for HMAC access with legacy support included.
  */
-SSL_HMAC *ssl_hmac_new(const SSL_CTX *ctx)
+SSL_HMAC *ssl_hmac_construct(const SSL_CTX *ctx, SSL_HMAC *hctx)
 {
-    SSL_HMAC *ret = OPENSSL_zalloc(sizeof(*ret));
-    EVP_MAC *mac = NULL;
-
-    if (ret == NULL)
+    if (hctx == NULL)
         return NULL;
+    hctx->ctx = NULL;
 #ifndef OPENSSL_NO_DEPRECATED_3_0
+    hctx->old_ctx = NULL;
     if (ctx->ext.ticket_key_evp_cb == NULL
-        && ctx->ext.ticket_key_cb != NULL) {
-        if (!ssl_hmac_old_new(ret))
-            goto err;
-        return ret;
-    }
+        && ctx->ext.ticket_key_cb != NULL)
+        return ssl_hmac_old_construct(hctx);
 #endif
-    mac = EVP_MAC_fetch(ctx->libctx, "HMAC", ctx->propq);
-    if (mac == NULL || (ret->ctx = EVP_MAC_CTX_new(mac)) == NULL)
-        goto err;
-    EVP_MAC_free(mac);
-    return ret;
-err:
-    EVP_MAC_CTX_free(ret->ctx);
-    EVP_MAC_free(mac);
-    OPENSSL_free(ret);
-    return NULL;
+    hctx->ctx = EVP_MAC_CTX_new(ctx->hmac);
+    return hctx->ctx != NULL ? hctx : NULL;
 }

-void ssl_hmac_free(SSL_HMAC *ctx)
+void ssl_hmac_destruct(SSL_HMAC *ctx)
 {
     if (ctx != NULL) {
         EVP_MAC_CTX_free(ctx->ctx);
 #ifndef OPENSSL_NO_DEPRECATED_3_0
-        ssl_hmac_old_free(ctx);
+        ssl_hmac_old_destruct(ctx);
 #endif
-        OPENSSL_free(ctx);
     }
 }

diff --git a/ssl/tls_depr.c b/ssl/tls_depr.c
index 71d0c42495..194e06b33b 100644
--- a/ssl/tls_depr.c
+++ b/ssl/tls_depr.c
@@ -22,16 +22,13 @@
  * be removed.
  */
 #ifndef OPENSSL_NO_DEPRECATED_3_0
-int ssl_hmac_old_new(SSL_HMAC *ret)
+SSL_HMAC *ssl_hmac_old_construct(SSL_HMAC *ret)
 {
     ret->old_ctx = HMAC_CTX_new();
-    if (ret->old_ctx == NULL)
-        return 0;
-
-    return 1;
+    return ret->old_ctx != NULL ? ret : NULL;
 }

-void ssl_hmac_old_free(SSL_HMAC *ctx)
+void ssl_hmac_old_destruct(SSL_HMAC *ctx)
 {
     HMAC_CTX_free(ctx->old_ctx);
 }