Commit 8c8a80b00b for openssl.org

commit 8c8a80b00ba1edb481838021568cdcd126386bff
Author: Neil Horman <nhorman@openssl.org>
Date:   Mon Jun 29 17:27:53 2026 -0400

    Extend refcounting on evp objects to provider requesed no-caching

    We recently removed reference counting for EVP objects, but kept the
    refcounting when we build with no-cached-fetch.

    There is a corner case in which providers in builds that do caching may
    still request non-caching by setting *no_cache = 1 in their query
    operations.

    OQS tripped over this here:
    https://github.com/open-quantum-safe/oqs-provider/pull/787

    When a provider requests no caching, we need to treat those algorithms
    as though we are running in a no-cached-fetch build and still do ref
    counting on them.

    Teach our algorithms implementation to understand when a provider is
    requesting non-caching, mark them as such and ref count only those.

    Reviewed-by: Milan Broz <mbroz@openssl.org>
    Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
    MergeDate: Thu Jul  2 14:24:13 2026
    (Merged from https://github.com/openssl/openssl/pull/31782)

diff --git a/crypto/core_fetch.c b/crypto/core_fetch.c
index 3293f70372..3d09b384aa 100644
--- a/crypto/core_fetch.c
+++ b/crypto/core_fetch.c
@@ -107,7 +107,7 @@ static void ossl_method_construct_this(OSSL_PROVIDER *provider,
     struct construct_data_st *data = cbdata;
     void *method = NULL;

-    if ((method = data->mcm->construct(algo, provider, data->mcm_data))
+    if ((method = data->mcm->construct(algo, provider, data->mcm_data, no_store))
         == NULL)
         return;

diff --git a/crypto/encode_decode/decoder_meth.c b/crypto/encode_decode/decoder_meth.c
index 315c99d8c6..995cb675ba 100644
--- a/crypto/encode_decode/decoder_meth.c
+++ b/crypto/encode_decode/decoder_meth.c
@@ -79,7 +79,7 @@ int OSSL_DECODER_up_ref(OSSL_DECODER *decoder)
      * We can identify them based on the fact that they never have a registered nid (i.e.
      * its always zero)
      */
-    if (decoder->base.id == 0)
+    if (decoder->base.id == 0 || decoder->base.no_store != 0)
         return ossl_decoder_up_ref(decoder);
     return 1;
 #endif
@@ -90,7 +90,7 @@ void OSSL_DECODER_free(OSSL_DECODER *decoder)
 #ifdef OPENSSL_NO_CACHED_FETCH
     ossl_decoder_free(decoder);
 #else
-    if (decoder != NULL && decoder->base.id == 0)
+    if (decoder != NULL && (decoder->base.id == 0 || decoder->base.no_store != 0))
         ossl_decoder_free(decoder);
 #endif
 }
@@ -228,7 +228,7 @@ static int put_decoder_in_store(void *store, void *method,

 /* Create and populate a decoder method */
 void *ossl_decoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov)
+    OSSL_PROVIDER *prov, int no_store)
 {
     OSSL_DECODER *decoder = NULL;
     const OSSL_DISPATCH *fns = algodef->implementation;
@@ -237,6 +237,7 @@ void *ossl_decoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
     if ((decoder = ossl_decoder_new()) == NULL)
         return NULL;
     decoder->base.id = id;
+    decoder->base.no_store = no_store;
     if ((decoder->base.name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
         ossl_decoder_free(decoder);
         return NULL;
@@ -317,7 +318,7 @@ void *ossl_decoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
  * then call ossl_decoder_from_algorithm() with that identity number.
  */
 static void *construct_decoder(const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov, void *data)
+    OSSL_PROVIDER *prov, void *data, int no_store)
 {
     /*
      * This function is only called if get_decoder_from_store() returned
@@ -333,7 +334,7 @@ static void *construct_decoder(const OSSL_ALGORITHM *algodef,
     void *method = NULL;

     if (id != 0)
-        method = ossl_decoder_from_algorithm(id, algodef, prov);
+        method = ossl_decoder_from_algorithm(id, algodef, prov, no_store);

     /*
      * Flag to indicate that there was actual construction errors.  This
diff --git a/crypto/encode_decode/encoder_local.h b/crypto/encode_decode/encoder_local.h
index 789212746b..6ebbe1c513 100644
--- a/crypto/encode_decode/encoder_local.h
+++ b/crypto/encode_decode/encoder_local.h
@@ -24,6 +24,7 @@
 struct ossl_endecode_base_st {
     OSSL_PROVIDER *prov;
     int id;
+    int no_store;
     char *name;
     const OSSL_ALGORITHM *algodef;
     OSSL_PROPERTY_LIST *parsed_propdef;
diff --git a/crypto/encode_decode/encoder_meth.c b/crypto/encode_decode/encoder_meth.c
index 611dc787d7..f329d0a307 100644
--- a/crypto/encode_decode/encoder_meth.c
+++ b/crypto/encode_decode/encoder_meth.c
@@ -72,6 +72,8 @@ int OSSL_ENCODER_up_ref(OSSL_ENCODER *encoder)
 #ifdef OPENSSL_NO_CACHED_FETCH
     return ossl_encoder_up_ref(encoder);
 #else
+    if (encoder->base.no_store != 0)
+        return ossl_encoder_up_ref(encoder);
     return 1;
 #endif
 }
@@ -80,6 +82,9 @@ void OSSL_ENCODER_free(OSSL_ENCODER *encoder)
 {
 #ifdef OPENSSL_NO_CACHED_FETCH
     ossl_encoder_free(encoder);
+#else
+    if (encoder != NULL && (encoder->base.no_store != 0))
+        ossl_encoder_free(encoder);
 #endif
 }

@@ -216,7 +221,7 @@ static int put_encoder_in_store(void *store, void *method,

 /* Create and populate a encoder method */
 static void *encoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov)
+    OSSL_PROVIDER *prov, int no_store)
 {
     OSSL_ENCODER *encoder = NULL;
     const OSSL_DISPATCH *fns = algodef->implementation;
@@ -225,6 +230,7 @@ static void *encoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
     if ((encoder = ossl_encoder_new()) == NULL)
         return NULL;
     encoder->base.id = id;
+    encoder->base.no_store = no_store;
     if ((encoder->base.name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
         ossl_encoder_free(encoder);
         return NULL;
@@ -311,7 +317,7 @@ static void *encoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
  * then call encoder_from_algorithm() with that identity number.
  */
 static void *construct_encoder(const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov, void *data)
+    OSSL_PROVIDER *prov, void *data, int no_store)
 {
     /*
      * This function is only called if get_encoder_from_store() returned
@@ -327,7 +333,7 @@ static void *construct_encoder(const OSSL_ALGORITHM *algodef,
     void *method = NULL;

     if (id != 0)
-        method = encoder_from_algorithm(id, algodef, prov);
+        method = encoder_from_algorithm(id, algodef, prov, no_store);

     /*
      * Flag to indicate that there was actual construction errors.  This
diff --git a/crypto/evp/asymcipher.c b/crypto/evp/asymcipher.c
index c449848ae0..1665efd3e2 100644
--- a/crypto/evp/asymcipher.c
+++ b/crypto/evp/asymcipher.c
@@ -342,7 +342,7 @@ static EVP_ASYM_CIPHER *evp_asym_cipher_new(OSSL_PROVIDER *prov)

 static void *evp_asym_cipher_from_algorithm(int name_id,
     const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov)
+    OSSL_PROVIDER *prov, int no_store)
 {
     const OSSL_DISPATCH *fns = algodef->implementation;
     EVP_ASYM_CIPHER *cipher = NULL;
@@ -355,6 +355,7 @@ static void *evp_asym_cipher_from_algorithm(int name_id,
     }

     cipher->name_id = name_id;
+    cipher->no_store = no_store;
     if ((cipher->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
         goto err;
     cipher->description = algodef->algorithm_description;
@@ -461,6 +462,9 @@ void EVP_ASYM_CIPHER_free(EVP_ASYM_CIPHER *cipher)
 {
 #ifdef OPENSSL_NO_CACHED_FETCH
     evp_asym_cipher_free(cipher);
+#else
+    if (cipher != NULL && (cipher->no_store != 0))
+        evp_asym_cipher_free(cipher);
 #endif
 }

@@ -469,6 +473,8 @@ int EVP_ASYM_CIPHER_up_ref(EVP_ASYM_CIPHER *cipher)
 #ifdef OPENSSL_NO_CACHED_FETCH
     return evp_asym_cipher_up_ref(cipher);
 #else
+    if (cipher->no_store != 0)
+        return evp_asym_cipher_up_ref(cipher);
     return 1;
 #endif
 }
diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c
index d18b707380..2cb490b279 100644
--- a/crypto/evp/digest.c
+++ b/crypto/evp/digest.c
@@ -831,7 +831,7 @@ static int evp_md_cache_constants(EVP_MD *md)

 static void *evp_md_from_algorithm(int name_id,
     const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov)
+    OSSL_PROVIDER *prov, int no_store)
 {
     const OSSL_DISPATCH *fns = algodef->implementation;
     EVP_MD *md = NULL;
@@ -843,6 +843,9 @@ static void *evp_md_from_algorithm(int name_id,
         return NULL;
     }

+    if (no_store != 0)
+        md->flags |= EVP_MD_FLAG_NO_STORE;
+
 #ifndef FIPS_MODULE
     md->type = NID_undef;
     if (!evp_names_do_all(prov, name_id, set_legacy_nid, &md->type)
@@ -1013,6 +1016,8 @@ int EVP_MD_up_ref(EVP_MD *md)
 #ifdef OPENSSL_NO_CACHED_FETCH
     return evp_md_up_ref(md);
 #else
+    if (md->flags & EVP_MD_FLAG_NO_STORE)
+        return evp_md_up_ref(md);
     return 1;
 #endif
 }
@@ -1022,6 +1027,8 @@ void EVP_MD_free(EVP_MD *md)
 #ifdef OPENSSL_NO_CACHED_FETCH
     evp_md_free(md);
 #else
+    if (md != NULL && (md->flags & EVP_MD_FLAG_NO_STORE))
+        evp_md_free(md);
     return;
 #endif
 }
diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c
index 07efde94e9..830cfdb8d8 100644
--- a/crypto/evp/evp_enc.c
+++ b/crypto/evp/evp_enc.c
@@ -1366,7 +1366,7 @@ static void evp_cipher_free(void *c)

 static void *evp_cipher_from_algorithm(const int name_id,
     const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov)
+    OSSL_PROVIDER *prov, int no_store)
 {
     const OSSL_DISPATCH *fns = algodef->implementation;
     EVP_CIPHER *cipher = NULL;
@@ -1377,6 +1377,9 @@ static void *evp_cipher_from_algorithm(const int name_id,
         return NULL;
     }

+    if (no_store != 0)
+        cipher->flags |= EVP_CIPH_FLAG_NO_STORE;
+
 #ifndef FIPS_MODULE
     cipher->nid = NID_undef;
     if (!evp_names_do_all(prov, name_id, set_legacy_nid, &cipher->nid)
@@ -1574,6 +1577,8 @@ int EVP_CIPHER_up_ref(EVP_CIPHER *cipher)
 #ifdef OPENSSL_NO_CACHED_FETCH
     return evp_cipher_up_ref(cipher);
 #else
+    if (cipher->flags & EVP_CIPH_FLAG_NO_STORE)
+        return evp_cipher_up_ref(cipher);
     return 1;
 #endif
 }
@@ -1590,6 +1595,9 @@ void EVP_CIPHER_free(EVP_CIPHER *cipher)
 {
 #ifdef OPENSSL_NO_CACHED_FETCH
     evp_cipher_free(cipher);
+#else
+    if (cipher != NULL && (cipher->flags & EVP_CIPH_FLAG_NO_STORE))
+        evp_cipher_free(cipher);
 #endif
 }

diff --git a/crypto/evp/evp_fetch.c b/crypto/evp/evp_fetch.c
index 9fa049cdce..15204628db 100644
--- a/crypto/evp/evp_fetch.c
+++ b/crypto/evp/evp_fetch.c
@@ -11,6 +11,7 @@
 #include <openssl/types.h>
 #include <openssl/evp.h>
 #include <openssl/core.h>
+#include <openssl/kdf.h>
 #include "internal/cryptlib.h"
 #include "internal/thread_once.h"
 #include "internal/property.h"
@@ -36,7 +37,7 @@ struct evp_method_data_st {
     unsigned int flag_construct_error_occurred : 1;

     void *(*method_from_algorithm)(int name_id, const OSSL_ALGORITHM *,
-        OSSL_PROVIDER *);
+        OSSL_PROVIDER *, int);
     int (*refcnt_up_method)(void *method);
     void (*destruct_method)(void *method);
 };
@@ -208,7 +209,7 @@ static int put_evp_method_in_store(void *store, void *method,
  * This function is responsible to getting an identity number for it.
  */
 static void *construct_evp_method(const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov, void *data)
+    OSSL_PROVIDER *prov, void *data, int no_store)
 {
     /*
      * This function is only called if get_evp_method_from_store() returned
@@ -227,7 +228,7 @@ static void *construct_evp_method(const OSSL_ALGORITHM *algodef,
     if (name_id == 0)
         return NULL;

-    method = methdata->method_from_algorithm(name_id, algodef, prov);
+    method = methdata->method_from_algorithm(name_id, algodef, prov, no_store);

     /*
      * Flag to indicate that there was actual construction errors.  This
@@ -253,7 +254,7 @@ inner_evp_generic_fetch(struct evp_method_data_st *methdata,
     const char *name, ossl_unused const char *properties,
     void *(*new_method)(int name_id,
         const OSSL_ALGORITHM *algodef,
-        OSSL_PROVIDER *prov),
+        OSSL_PROVIDER *prov, int no_store),
     int (*up_ref_method)(void *),
     void (*free_method)(void *))
 {
@@ -363,9 +364,70 @@ inner_evp_generic_fetch(struct evp_method_data_st *methdata,
                  * cached end up in ->tmp_store when provider asks not
                  * to cache the result (see ossl_method_construct_reserve_store())
                  */
-                if (meth_id != 0 && methdata->tmp_store == NULL)
+                if (meth_id != 0 && methdata->tmp_store == NULL) {
                     ossl_method_store_cache_set(store, prov, meth_id, propq,
                         method, up_ref_method, free_method);
+                } else {
+#ifndef OPENSSL_NO_CACHED_FETCH
+                    /*
+                     * There is a corner case we need to handle here.  IF:
+                     * 1) we are fetching an algorithm and plan to return it to the caller
+                     * 2) The provider we fetched from requested no_cache
+                     * Then we are in a situation in which this method that was constructed
+                     * only lives in the tmp_store, and has a reference count of 1.
+                     * On return from this function, that tmp_store is going to be deallocated,
+                     * Which will drop the methods ref count to 0 and free it, after which the
+                     * method will be returned to the called, as an already freed object.
+                     *
+                     * That's bad.  We need to grab an extra ref count on the method before returning
+                     * so that the requestor via EVP_*_fetch has ownership.
+                     *
+                     * BUT we only want to do this in the event that the algorithm is uncached.
+                     * Unfortunately, we don't know that here, because it was the provider that
+                     * made that request.  However, each algorithm type does store that information
+                     * so we have a path forward.  Based on the operation id, call the appropriate
+                     * up_ref method.  That implementation knows how to query its algorithm type and
+                     * decide if a reference needs to be taken here
+                     */
+                    switch (operation_id) {
+                    case OSSL_OP_DIGEST:
+                        EVP_MD_up_ref((EVP_MD *)method);
+                        break;
+                    case OSSL_OP_CIPHER:
+                        EVP_CIPHER_up_ref((EVP_CIPHER *)method);
+                        break;
+                    case OSSL_OP_MAC:
+                        EVP_MAC_up_ref((EVP_MAC *)method);
+                        break;
+                    case OSSL_OP_KDF:
+                        EVP_KDF_up_ref((EVP_KDF *)method);
+                        break;
+                    case OSSL_OP_RAND:
+                        EVP_RAND_up_ref((EVP_RAND *)method);
+                        break;
+                    case OSSL_OP_KEYMGMT:
+                        EVP_KEYMGMT_up_ref((EVP_KEYMGMT *)method);
+                        break;
+                    case OSSL_OP_KEYEXCH:
+                        EVP_KEYEXCH_up_ref((EVP_KEYEXCH *)method);
+                        break;
+                    case OSSL_OP_SIGNATURE:
+                        EVP_SIGNATURE_up_ref((EVP_SIGNATURE *)method);
+                        break;
+                    case OSSL_OP_ASYM_CIPHER:
+                        EVP_ASYM_CIPHER_up_ref((EVP_ASYM_CIPHER *)method);
+                        break;
+                    case OSSL_OP_KEM:
+                        EVP_KEM_up_ref((EVP_KEM *)method);
+                        break;
+                    case OSSL_OP_SKEYMGMT:
+                        EVP_SKEYMGMT_up_ref((EVP_SKEYMGMT *)method);
+                        break;
+                    default:
+                        break;
+                    }
+#endif
+                }
             }
         }

@@ -400,7 +462,7 @@ void *evp_generic_fetch(OSSL_LIB_CTX *libctx, int operation_id,
     const char *name, const char *properties,
     void *(*new_method)(int name_id,
         const OSSL_ALGORITHM *algodef,
-        OSSL_PROVIDER *prov),
+        OSSL_PROVIDER *prov, int no_store),
     int (*up_ref_method)(void *),
     void (*free_method)(void *))
 {
@@ -426,7 +488,7 @@ void *evp_generic_fetch_from_prov(OSSL_PROVIDER *prov, int operation_id,
     const char *name, const char *properties,
     void *(*new_method)(int name_id,
         const OSSL_ALGORITHM *algodef,
-        OSSL_PROVIDER *prov),
+        OSSL_PROVIDER *prov, int no_store),
     int (*up_ref_method)(void *),
     void (*free_method)(void *))
 {
@@ -640,7 +702,7 @@ void evp_generic_do_all(OSSL_LIB_CTX *libctx, int operation_id,
     void *user_arg,
     void *(*new_method)(int name_id,
         const OSSL_ALGORITHM *algodef,
-        OSSL_PROVIDER *prov),
+        OSSL_PROVIDER *prov, int no_store),
     int (*up_ref_method)(void *),
     void (*free_method)(void *))
 {
diff --git a/crypto/evp/evp_lib.c b/crypto/evp/evp_lib.c
index 076efb30d1..644772bf37 100644
--- a/crypto/evp/evp_lib.c
+++ b/crypto/evp/evp_lib.c
@@ -310,6 +310,7 @@ int evp_cipher_cache_constants(EVP_CIPHER *cipher)
     size_t blksz = 0;
     size_t keylen = 0;
     unsigned int mode = 0;
+    int no_store = cipher->flags & EVP_CIPH_FLAG_NO_STORE;
     OSSL_PARAM params[11];

     params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_BLOCK_SIZE, &blksz);
@@ -332,7 +333,7 @@ int evp_cipher_cache_constants(EVP_CIPHER *cipher)
         cipher->block_size = (int)blksz;
         cipher->iv_len = (int)ivlen;
         cipher->key_len = (int)keylen;
-        cipher->flags = mode;
+        cipher->flags = mode | no_store;
         if (aead)
             cipher->flags |= EVP_CIPH_FLAG_AEAD_CIPHER;
         if (custom_iv)
diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h
index d4a72b7527..1f41cfe644 100644
--- a/crypto/evp/evp_local.h
+++ b/crypto/evp/evp_local.h
@@ -102,6 +102,7 @@ struct evp_keymgmt_st {
     int id; /* libcrypto internal */

     int name_id;
+    int no_store;
     /* NID for the legacy alg if there is one */
     int legacy_alg;
     char *type_name;
@@ -148,6 +149,7 @@ struct evp_keymgmt_st {

 struct evp_keyexch_st {
     int name_id;
+    int no_store;
     char *type_name;
     const char *description;
     OSSL_PROVIDER *prov;
@@ -168,6 +170,7 @@ struct evp_keyexch_st {

 struct evp_signature_st {
     int name_id;
+    int no_store;
     char *type_name;
     const char *description;
     OSSL_PROVIDER *prov;
@@ -211,6 +214,7 @@ struct evp_signature_st {

 struct evp_skeymgmt_st {
     int name_id;
+    int no_store;
     char *type_name;
     const char *description;
     OSSL_PROVIDER *prov;
@@ -234,6 +238,7 @@ struct evp_skeymgmt_st {

 struct evp_asym_cipher_st {
     int name_id;
+    int no_store;
     char *type_name;
     const char *description;
     OSSL_PROVIDER *prov;
@@ -254,6 +259,7 @@ struct evp_asym_cipher_st {

 struct evp_kem_st {
     int name_id;
+    int no_store;
     char *type_name;
     const char *description;
     OSSL_PROVIDER *prov;
@@ -305,14 +311,14 @@ void *evp_generic_fetch(OSSL_LIB_CTX *ctx, int operation_id,
     const char *name, const char *properties,
     void *(*new_method)(int name_id,
         const OSSL_ALGORITHM *algodef,
-        OSSL_PROVIDER *prov),
+        OSSL_PROVIDER *prov, int no_store),
     int (*up_ref_method)(void *),
     void (*free_method)(void *));
 void *evp_generic_fetch_from_prov(OSSL_PROVIDER *prov, int operation_id,
     const char *name, const char *properties,
     void *(*new_method)(int name_id,
         const OSSL_ALGORITHM *algodef,
-        OSSL_PROVIDER *prov),
+        OSSL_PROVIDER *prov, int no_store),
     int (*up_ref_method)(void *),
     void (*free_method)(void *));
 void evp_generic_do_all_prefetched(OSSL_LIB_CTX *libctx, int operation_id,
@@ -323,7 +329,7 @@ void evp_generic_do_all(OSSL_LIB_CTX *libctx, int operation_id,
     void *user_arg,
     void *(*new_method)(int name_id,
         const OSSL_ALGORITHM *algodef,
-        OSSL_PROVIDER *prov),
+        OSSL_PROVIDER *prov, int no_store),
     int (*up_ref_method)(void *),
     void (*free_method)(void *));

diff --git a/crypto/evp/evp_rand.c b/crypto/evp/evp_rand.c
index 857ffb3350..a0041719b5 100644
--- a/crypto/evp/evp_rand.c
+++ b/crypto/evp/evp_rand.c
@@ -24,6 +24,7 @@
 struct evp_rand_st {
     OSSL_PROVIDER *prov;
     int name_id;
+    int no_store;
     char *type_name;
     const char *description;
     CRYPTO_REF_COUNT refcnt;
@@ -116,7 +117,7 @@ static void evp_rand_unlock(EVP_RAND_CTX *rand)

 static void *evp_rand_from_algorithm(int name_id,
     const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov)
+    OSSL_PROVIDER *prov, int no_store)
 {
     const OSSL_DISPATCH *fns = algodef->implementation;
     EVP_RAND *rand = NULL;
@@ -130,6 +131,7 @@ static void *evp_rand_from_algorithm(int name_id,
         return NULL;
     }
     rand->name_id = name_id;
+    rand->no_store = no_store;
     if ((rand->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
         evp_rand_free(rand);
         return NULL;
@@ -292,6 +294,8 @@ int EVP_RAND_up_ref(EVP_RAND *rand)
 #ifdef OPENSSL_NO_CACHED_FETCH
     return evp_rand_up_ref(rand);
 #else
+    if (rand->no_store != 0)
+        return evp_rand_up_ref(rand);
     return 1;
 #endif
 }
@@ -300,6 +304,9 @@ void EVP_RAND_free(EVP_RAND *rand)
 {
 #ifdef OPENSSL_NO_CACHED_FETCH
     evp_rand_free(rand);
+#else
+    if (rand != NULL && (rand->no_store != 0))
+        evp_rand_free(rand);
 #endif
 }

diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c
index 535493c244..83fcbeb104 100644
--- a/crypto/evp/exchange.c
+++ b/crypto/evp/exchange.c
@@ -64,7 +64,7 @@ static EVP_KEYEXCH *evp_keyexch_new(OSSL_PROVIDER *prov)

 static void *evp_keyexch_from_algorithm(int name_id,
     const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov)
+    OSSL_PROVIDER *prov, int no_store)
 {
     const OSSL_DISPATCH *fns = algodef->implementation;
     EVP_KEYEXCH *exchange = NULL;
@@ -76,6 +76,7 @@ static void *evp_keyexch_from_algorithm(int name_id,
     }

     exchange->name_id = name_id;
+    exchange->no_store = no_store;
     if ((exchange->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
         goto err;
     exchange->description = algodef->algorithm_description;
@@ -177,6 +178,9 @@ void EVP_KEYEXCH_free(EVP_KEYEXCH *exchange)
 {
 #ifdef OPENSSL_NO_CACHED_FETCH
     evp_keyexch_free(exchange);
+#else
+    if (exchange != NULL && (exchange->no_store != 0))
+        evp_keyexch_free(exchange);
 #endif
 }

@@ -185,6 +189,8 @@ int EVP_KEYEXCH_up_ref(EVP_KEYEXCH *exchange)
 #ifdef OPENSSL_NO_CACHED_FETCH
     return evp_keyexch_up_ref(exchange);
 #else
+    if (exchange->no_store != 0)
+        return evp_keyexch_up_ref(exchange);
     return 1;
 #endif
 }
diff --git a/crypto/evp/kdf_meth.c b/crypto/evp/kdf_meth.c
index fba2f9fc75..e0741450e9 100644
--- a/crypto/evp/kdf_meth.c
+++ b/crypto/evp/kdf_meth.c
@@ -57,7 +57,7 @@ static void *evp_kdf_new(void)

 static void *evp_kdf_from_algorithm(int name_id,
     const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov)
+    OSSL_PROVIDER *prov, int no_store)
 {
     const OSSL_DISPATCH *fns = algodef->implementation;
     EVP_KDF *kdf = NULL;
@@ -68,6 +68,8 @@ static void *evp_kdf_from_algorithm(int name_id,
         return NULL;
     }
     kdf->name_id = name_id;
+    kdf->no_store = no_store;
+
     if ((kdf->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
         goto err;

@@ -179,6 +181,8 @@ int EVP_KDF_up_ref(EVP_KDF *kdf)
 #ifdef OPENSSL_NO_CACHED_FETCH
     return evp_kdf_up_ref(kdf);
 #else
+    if (kdf->no_store != 0)
+        return evp_kdf_up_ref(kdf);
     return 1;
 #endif
 }
@@ -187,6 +191,9 @@ void EVP_KDF_free(EVP_KDF *kdf)
 {
 #ifdef OPENSSL_NO_CACHED_FETCH
     evp_kdf_free(kdf);
+#else
+    if (kdf != NULL && (kdf->no_store != 0))
+        evp_kdf_free(kdf);
 #endif
 }

diff --git a/crypto/evp/kem.c b/crypto/evp/kem.c
index ec83236ab4..4041390106 100644
--- a/crypto/evp/kem.c
+++ b/crypto/evp/kem.c
@@ -317,7 +317,7 @@ static EVP_KEM *evp_kem_new(OSSL_PROVIDER *prov)
 }

 static void *evp_kem_from_algorithm(int name_id, const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov)
+    OSSL_PROVIDER *prov, int no_store)
 {
     const OSSL_DISPATCH *fns = algodef->implementation;
     EVP_KEM *kem = NULL;
@@ -330,6 +330,8 @@ static void *evp_kem_from_algorithm(int name_id, const OSSL_ALGORITHM *algodef,
     }

     kem->name_id = name_id;
+    kem->no_store = no_store;
+
     if ((kem->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
         goto err;
     kem->description = algodef->algorithm_description;
@@ -450,6 +452,9 @@ void EVP_KEM_free(EVP_KEM *kem)
 {
 #ifdef OPENSSL_NO_CACHED_FETCH
     evp_kem_free(kem);
+#else
+    if (kem != NULL && (kem->no_store != 0))
+        evp_kem_free(kem);
 #endif
 }

@@ -458,6 +463,8 @@ int EVP_KEM_up_ref(EVP_KEM *kem)
 #ifdef OPENSSL_NO_CACHED_FETCH
     return evp_kem_up_ref(kem);
 #else
+    if (kem->no_store != 0)
+        return evp_kem_up_ref(kem);
     return 1;
 #endif
 }
diff --git a/crypto/evp/keymgmt_meth.c b/crypto/evp/keymgmt_meth.c
index 3a6a5d0644..07ea8f8b9e 100644
--- a/crypto/evp/keymgmt_meth.c
+++ b/crypto/evp/keymgmt_meth.c
@@ -78,7 +78,7 @@ static int get_legacy_alg_type_from_keymgmt(const EVP_KEYMGMT *keymgmt)

 static void *keymgmt_from_algorithm(int name_id,
     const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov)
+    OSSL_PROVIDER *prov, int no_store)
 {
     const OSSL_DISPATCH *fns = algodef->implementation;
     EVP_KEYMGMT *keymgmt = NULL;
@@ -92,6 +92,8 @@ static void *keymgmt_from_algorithm(int name_id,
         return NULL;

     keymgmt->name_id = name_id;
+    keymgmt->no_store = no_store;
+
     if ((keymgmt->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
         evp_keymgmt_free(keymgmt);
         return NULL;
@@ -312,6 +314,8 @@ int EVP_KEYMGMT_up_ref(EVP_KEYMGMT *keymgmt)
 #ifdef OPENSSL_NO_CACHED_FETCH
     return evp_keymgmt_up_ref(keymgmt);
 #else
+    if (keymgmt->no_store != 0)
+        return evp_keymgmt_up_ref(keymgmt);
     return 1;
 #endif
 }
@@ -320,6 +324,9 @@ void EVP_KEYMGMT_free(EVP_KEYMGMT *keymgmt)
 {
 #ifdef OPENSSL_NO_CACHED_FETCH
     evp_keymgmt_free(keymgmt);
+#else
+    if (keymgmt != NULL && (keymgmt->no_store != 0))
+        evp_keymgmt_free(keymgmt);
 #endif
 }

diff --git a/crypto/evp/mac_meth.c b/crypto/evp/mac_meth.c
index 439a6fc2cf..62d94de45c 100644
--- a/crypto/evp/mac_meth.c
+++ b/crypto/evp/mac_meth.c
@@ -56,7 +56,7 @@ static void *evp_mac_new(void)

 static void *evp_mac_from_algorithm(int name_id,
     const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov)
+    OSSL_PROVIDER *prov, int no_store)
 {
     const OSSL_DISPATCH *fns = algodef->implementation;
     EVP_MAC *mac = NULL;
@@ -67,6 +67,7 @@ static void *evp_mac_from_algorithm(int name_id,
         goto err;
     }
     mac->name_id = name_id;
+    mac->no_store = no_store;

     if ((mac->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
         goto err;
@@ -185,6 +186,8 @@ int EVP_MAC_up_ref(EVP_MAC *mac)
 #ifdef OPENSSL_NO_CACHED_FETCH
     return evp_mac_up_ref(mac);
 #else
+    if (mac->no_store != 0)
+        return evp_mac_up_ref(mac);
     return 1;
 #endif
 }
@@ -193,6 +196,9 @@ void EVP_MAC_free(EVP_MAC *mac)
 {
 #ifdef OPENSSL_NO_CACHED_FETCH
     evp_mac_free(mac);
+#else
+    if (mac != NULL && (mac->no_store != 0))
+        evp_mac_free(mac);
 #endif
 }

diff --git a/crypto/evp/signature.c b/crypto/evp/signature.c
index cd8e00d77e..f2e405aaa3 100644
--- a/crypto/evp/signature.c
+++ b/crypto/evp/signature.c
@@ -66,7 +66,7 @@ static EVP_SIGNATURE *evp_signature_new(OSSL_PROVIDER *prov)

 static void *evp_signature_from_algorithm(int name_id,
     const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov)
+    OSSL_PROVIDER *prov, int no_store)
 {
     const OSSL_DISPATCH *fns = algodef->implementation;
     EVP_SIGNATURE *signature = NULL;
@@ -85,6 +85,7 @@ static void *evp_signature_from_algorithm(int name_id,
     }

     signature->name_id = name_id;
+    signature->no_store = no_store;
     if ((signature->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL)
         goto err;
     signature->description = algodef->algorithm_description;
@@ -471,6 +472,9 @@ void EVP_SIGNATURE_free(EVP_SIGNATURE *signature)
 {
 #ifdef OPENSSL_NO_CACHED_FETCH
     evp_signature_free(signature);
+#else
+    if (signature != NULL && (signature->no_store != 0))
+        evp_signature_free(signature);
 #endif
 }

@@ -479,6 +483,8 @@ int EVP_SIGNATURE_up_ref(EVP_SIGNATURE *signature)
 #ifdef OPENSSL_NO_CACHED_FETCH
     return evp_signature_up_ref(signature);
 #else
+    if (signature->no_store != 0)
+        return evp_signature_up_ref(signature);
     return 1;
 #endif
 }
diff --git a/crypto/evp/skeymgmt_meth.c b/crypto/evp/skeymgmt_meth.c
index 88f0a6a133..d1e5c9d446 100644
--- a/crypto/evp/skeymgmt_meth.c
+++ b/crypto/evp/skeymgmt_meth.c
@@ -62,7 +62,7 @@ static void *skeymgmt_new(void)

 static void *skeymgmt_from_algorithm(int name_id,
     const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov)
+    OSSL_PROVIDER *prov, int no_store)
 {
     const OSSL_DISPATCH *fns = algodef->implementation;
     EVP_SKEYMGMT *skeymgmt = NULL;
@@ -71,6 +71,7 @@ static void *skeymgmt_from_algorithm(int name_id,
         return NULL;

     skeymgmt->name_id = name_id;
+    skeymgmt->no_store = no_store;
     if ((skeymgmt->type_name = ossl_algorithm_get1_first_name(algodef)) == NULL) {
         evp_skeymgmt_free(skeymgmt);
         return NULL;
@@ -181,6 +182,8 @@ int EVP_SKEYMGMT_up_ref(EVP_SKEYMGMT *skeymgmt)
 #ifdef OPENSSL_NO_CACHED_FETCH
     return evp_skeymgmt_up_ref(skeymgmt);
 #else
+    if (skeymgmt->no_store != 0)
+        return evp_skeymgmt_up_ref(skeymgmt);
     return 1;
 #endif
 }
@@ -189,6 +192,9 @@ void EVP_SKEYMGMT_free(EVP_SKEYMGMT *skeymgmt)
 {
 #ifdef OPENSSL_NO_CACHED_FETCH
     evp_skeymgmt_free(skeymgmt);
+#else
+    if (skeymgmt != NULL && (skeymgmt->no_store != 0))
+        evp_skeymgmt_free(skeymgmt);
 #endif
 }

diff --git a/crypto/store/store_local.h b/crypto/store/store_local.h
index f668d4bbbc..995024d5c9 100644
--- a/crypto/store/store_local.h
+++ b/crypto/store/store_local.h
@@ -104,6 +104,7 @@ struct ossl_store_loader_st {
     const char *propdef;
     const char *description;

+    int no_store;
     CRYPTO_REF_COUNT refcnt;

     OSSL_FUNC_store_open_fn *p_open;
diff --git a/crypto/store/store_meth.c b/crypto/store/store_meth.c
index 840ddc1a4a..96b092e5bb 100644
--- a/crypto/store/store_meth.c
+++ b/crypto/store/store_meth.c
@@ -47,6 +47,8 @@ int OSSL_STORE_LOADER_up_ref(OSSL_STORE_LOADER *loader)
 #ifdef OPENSSL_NO_CACHED_FETCH
     return up_ref_loader(loader);
 #else
+    if (loader->no_store != 0)
+        return up_ref_loader(loader);
     return 1;
 #endif
 }
@@ -55,6 +57,9 @@ void OSSL_STORE_LOADER_free(OSSL_STORE_LOADER *loader)
 {
 #ifdef OPENSSL_NO_CACHED_FETCH
     free_loader(loader);
+#else
+    if (loader != NULL && (loader->no_store != 0))
+        free_loader(loader);
 #endif
 }

@@ -185,7 +190,7 @@ static int put_loader_in_store(void *store, void *method,
 }

 static void *loader_from_algorithm(int scheme_id, const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov)
+    OSSL_PROVIDER *prov, int no_store)
 {
     OSSL_STORE_LOADER *loader = NULL;
     const OSSL_DISPATCH *fns = algodef->implementation;
@@ -195,6 +200,7 @@ static void *loader_from_algorithm(int scheme_id, const OSSL_ALGORITHM *algodef,
     loader->scheme_id = scheme_id;
     loader->propdef = algodef->property_definition;
     loader->description = algodef->algorithm_description;
+    loader->no_store = no_store;

     for (; fns->function_id != 0; fns++) {
         switch (fns->function_id) {
@@ -259,7 +265,7 @@ static void *loader_from_algorithm(int scheme_id, const OSSL_ALGORITHM *algodef,
  * then call loader_from_algorithm() with that identity number.
  */
 static void *construct_loader(const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov, void *data)
+    OSSL_PROVIDER *prov, void *data, int no_store)
 {
     /*
      * This function is only called if get_loader_from_store() returned
@@ -275,7 +281,7 @@ static void *construct_loader(const OSSL_ALGORITHM *algodef,
     void *method = NULL;

     if (id != 0)
-        method = loader_from_algorithm(id, algodef, prov);
+        method = loader_from_algorithm(id, algodef, prov, no_store);

     /*
      * Flag to indicate that there was actual construction errors.  This
diff --git a/include/crypto/decoder.h b/include/crypto/decoder.h
index fcb914faeb..dafb143593 100644
--- a/include/crypto/decoder.h
+++ b/include/crypto/decoder.h
@@ -20,7 +20,7 @@
  * (provider-object(7)).
  */
 void *ossl_decoder_from_algorithm(int id, const OSSL_ALGORITHM *algodef,
-    OSSL_PROVIDER *prov);
+    OSSL_PROVIDER *prov, int no_store);

 OSSL_DECODER_INSTANCE *
 ossl_decoder_instance_new_forprov(OSSL_DECODER *decoder, void *provctx,
diff --git a/include/crypto/evp.h b/include/crypto/evp.h
index aec23fb013..eca29a7438 100644
--- a/include/crypto/evp.h
+++ b/include/crypto/evp.h
@@ -141,6 +141,7 @@ void evp_pkey_set_cb_translate(BN_GENCB *cb, EVP_PKEY_CTX *ctx);
 struct evp_mac_st {
     OSSL_PROVIDER *prov;
     int name_id;
+    int no_store;
     char *type_name;
     const char *description;

@@ -164,6 +165,7 @@ struct evp_mac_st {
 struct evp_kdf_st {
     OSSL_PROVIDER *prov;
     int name_id;
+    int no_store;
     char *type_name;
     const char *description;
     CRYPTO_REF_COUNT refcnt;
diff --git a/include/internal/core.h b/include/internal/core.h
index 5c9ffc657b..33a16395e2 100644
--- a/include/internal/core.h
+++ b/include/internal/core.h
@@ -44,7 +44,7 @@ typedef struct ossl_method_construct_method_st {
         const char *name, const char *propdef, void *data);
     /* Construct a new method */
     void *(*construct)(const OSSL_ALGORITHM *algodef, OSSL_PROVIDER *prov,
-        void *data);
+        void *data, int no_store);
     /* Destruct a method */
     void (*destruct)(void *method, void *data);
 } OSSL_METHOD_CONSTRUCT_METHOD;
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 6ab3f556cd..dcbc5b26d3 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -155,6 +155,8 @@ int EVP_default_properties_enable_fips(OSSL_LIB_CTX *libctx, int enable);
 /* Note if suitable for use in FIPS mode */
 #define EVP_MD_FLAG_FIPS 0x0400

+#define EVP_MD_FLAG_NO_STORE 0x0800
+
 /* Digest ctrls */

 #define EVP_MD_CTRL_DIGALGID 0x1
@@ -267,6 +269,8 @@ int EVP_default_properties_enable_fips(OSSL_LIB_CTX *libctx, int enable);
 #define EVP_CIPH_FLAG_GET_WRAP_CIPHER 0x4000000
 #define EVP_CIPH_FLAG_INVERSE_CIPHER 0x8000000
 #define EVP_CIPH_FLAG_ENC_THEN_MAC 0x10000000
+/* flag to indicate that this cipher isn't cached, and so should be refcounted*/
+#define EVP_CIPH_FLAG_NO_STORE 0x20000000

 /*
  * Cipher context flag to indicate we can handle wrap mode: if allowed in
diff --git a/providers/implementations/storemgmt/file_store.c b/providers/implementations/storemgmt/file_store.c
index 2df5406699..894685ce8c 100644
--- a/providers/implementations/storemgmt/file_store.c
+++ b/providers/implementations/storemgmt/file_store.c
@@ -505,7 +505,7 @@ static int file_setup_decoders(struct file_ctx_st *ctx)
              * The decoder doesn't need any identification or to be
              * attached to any provider, since it's only used locally.
              */
-            to_obj = ossl_decoder_from_algorithm(0, to_algo, NULL);
+            to_obj = ossl_decoder_from_algorithm(0, to_algo, NULL, 0);
             if (to_obj != NULL)
                 to_obj_inst = ossl_decoder_instance_new_forprov(to_obj, ctx->provctx,
                     input_structure);
diff --git a/providers/implementations/storemgmt/winstore_store.c b/providers/implementations/storemgmt/winstore_store.c
index c33763b8d9..59318e7547 100644
--- a/providers/implementations/storemgmt/winstore_store.c
+++ b/providers/implementations/storemgmt/winstore_store.c
@@ -209,7 +209,7 @@ static int setup_decoder(struct winstore_ctx_st *ctx)
          * The decoder doesn't need any identification or to be
          * attached to any provider, since it's only used locally.
          */
-        to_obj = ossl_decoder_from_algorithm(0, to_algo, NULL);
+        to_obj = ossl_decoder_from_algorithm(0, to_algo, NULL, 0);
         if (to_obj != NULL)
             to_obj_inst = ossl_decoder_instance_new_forprov(to_obj, ctx->provctx,
                 input_structure);