Add method store cache flush and method removal to non-EVP operations

evp_method_store_flush() and evp_method_store_remove_all_provided()
only cover EVP operations, but not encoders, decoders and store loaders.
This adds corresponding methods for those as well.  Without this, their
method stores are never cleaned up when the corresponding providers are
deactivated or otherwise modified.

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/18151)
diff --git a/crypto/encode_decode/decoder_meth.c b/crypto/encode_decode/decoder_meth.c
index 06a6bda..d622fff 100644
--- a/crypto/encode_decode/decoder_meth.c
+++ b/crypto/encode_decode/decoder_meth.c
@@ -427,6 +427,25 @@
     return method;
 }
 
+int ossl_decoder_store_cache_flush(OSSL_LIB_CTX *libctx)
+{
+    OSSL_METHOD_STORE *store = get_decoder_store(libctx);
+
+    if (store != NULL)
+        return ossl_method_store_cache_flush_all(store);
+    return 1;
+}
+
+int ossl_decoder_store_remove_all_provided(const OSSL_PROVIDER *prov)
+{
+    OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
+    OSSL_METHOD_STORE *store = get_decoder_store(libctx);
+
+    if (store != NULL)
+        return ossl_method_store_remove_all_provided(store, prov);
+    return 1;
+}
+
 /*
  * Library of basic method functions
  */
diff --git a/crypto/encode_decode/encoder_meth.c b/crypto/encode_decode/encoder_meth.c
index aa5fb13..ad7df22 100644
--- a/crypto/encode_decode/encoder_meth.c
+++ b/crypto/encode_decode/encoder_meth.c
@@ -436,6 +436,25 @@
     return method;
 }
 
+int ossl_encoder_store_cache_flush(OSSL_LIB_CTX *libctx)
+{
+    OSSL_METHOD_STORE *store = get_encoder_store(libctx);
+
+    if (store != NULL)
+        return ossl_method_store_cache_flush_all(store);
+    return 1;
+}
+
+int ossl_encoder_store_remove_all_provided(const OSSL_PROVIDER *prov)
+{
+    OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
+    OSSL_METHOD_STORE *store = get_encoder_store(libctx);
+
+    if (store != NULL)
+        return ossl_method_store_remove_all_provided(store, prov);
+    return 1;
+}
+
 /*
  * Library of basic method functions
  */
diff --git a/crypto/provider_core.c b/crypto/provider_core.c
index 8e7ed62..3e2738f 100644
--- a/crypto/provider_core.c
+++ b/crypto/provider_core.c
@@ -15,7 +15,10 @@
 #include <openssl/params.h>
 #include <openssl/opensslv.h>
 #include "crypto/cryptlib.h"
+#include "crypto/decoder.h" /* ossl_decoder_store_cache_flush */
+#include "crypto/encoder.h" /* ossl_encoder_store_cache_flush */
 #include "crypto/evp.h" /* evp_method_store_cache_flush */
+#include "crypto/store.h" /* ossl_store_loader_store_cache_flush */
 #include "crypto/rand.h"
 #include "internal/nelem.h"
 #include "internal/thread_once.h"
@@ -1151,8 +1154,22 @@
     freeing = store->freeing;
     CRYPTO_THREAD_unlock(store->lock);
 
-    if (!freeing)
-        return evp_method_store_cache_flush(prov->libctx);
+    if (!freeing) {
+        int acc
+            = evp_method_store_cache_flush(prov->libctx)
+#ifndef FIPS_MODULE
+            + ossl_encoder_store_cache_flush(prov->libctx)
+            + ossl_decoder_store_cache_flush(prov->libctx)
+            + ossl_store_loader_store_cache_flush(prov->libctx)
+#endif
+            ;
+
+#ifndef FIPS_MODULE
+        return acc == 4;
+#else
+        return acc == 1;
+#endif
+    }
     return 1;
 }
 
@@ -1170,12 +1187,28 @@
     CRYPTO_THREAD_unlock(store->lock);
 
     if (!freeing) {
+        int acc;
+
+        if (!CRYPTO_THREAD_read_lock(prov->opbits_lock))
+            return 0;
         OPENSSL_free(prov->operation_bits);
         prov->operation_bits = NULL;
         prov->operation_bits_sz = 0;
         CRYPTO_THREAD_unlock(prov->opbits_lock);
 
-        return evp_method_store_remove_all_provided(prov);
+        acc = evp_method_store_remove_all_provided(prov)
+#ifndef FIPS_MODULE
+            + ossl_encoder_store_remove_all_provided(prov)
+            + ossl_decoder_store_remove_all_provided(prov)
+            + ossl_store_loader_store_remove_all_provided(prov)
+#endif
+            ;
+
+#ifndef FIPS_MODULE
+        return acc == 4;
+#else
+        return acc == 1;
+#endif
     }
     return 1;
 }
diff --git a/crypto/store/store_meth.c b/crypto/store/store_meth.c
index 51af5a0..fc9f1e6 100644
--- a/crypto/store/store_meth.c
+++ b/crypto/store/store_meth.c
@@ -376,6 +376,25 @@
     return method;
 }
 
+int ossl_store_loader_store_cache_flush(OSSL_LIB_CTX *libctx)
+{
+    OSSL_METHOD_STORE *store = get_loader_store(libctx);
+
+    if (store != NULL)
+        return ossl_method_store_cache_flush_all(store);
+    return 1;
+}
+
+int ossl_store_loader_store_remove_all_provided(const OSSL_PROVIDER *prov)
+{
+    OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
+    OSSL_METHOD_STORE *store = get_loader_store(libctx);
+
+    if (store != NULL)
+        return ossl_method_store_remove_all_provided(store, prov);
+    return 1;
+}
+
 /*
  * Library of basic method functions
  */
diff --git a/include/crypto/decoder.h b/include/crypto/decoder.h
index cc06ef2..95afd25 100644
--- a/include/crypto/decoder.h
+++ b/include/crypto/decoder.h
@@ -38,5 +38,7 @@
                                     const char *propquery);
 
 int ossl_decoder_get_number(const OSSL_DECODER *encoder);
+int ossl_decoder_store_cache_flush(OSSL_LIB_CTX *libctx);
+int ossl_decoder_store_remove_all_provided(const OSSL_PROVIDER *prov);
 
 #endif
diff --git a/include/crypto/encoder.h b/include/crypto/encoder.h
index 09d445d..ae56131 100644
--- a/include/crypto/encoder.h
+++ b/include/crypto/encoder.h
@@ -7,8 +7,16 @@
  * https://www.openssl.org/source/license.html
  */
 
-#include <openssl/types.h>
+#ifndef OSSL_CRYPTO_ENCODER_H
+# define OSSL_CRYPTO_ENCODER_H
+# pragma once
+
+# include <openssl/types.h>
 
 OSSL_ENCODER *ossl_encoder_fetch_by_number(OSSL_LIB_CTX *libctx, int id,
                                            const char *properties);
 int ossl_encoder_get_number(const OSSL_ENCODER *encoder);
+int ossl_encoder_store_cache_flush(OSSL_LIB_CTX *libctx);
+int ossl_encoder_store_remove_all_provided(const OSSL_PROVIDER *prov);
+
+#endif
diff --git a/include/crypto/store.h b/include/crypto/store.h
index 13d2646..9b7be71 100644
--- a/include/crypto/store.h
+++ b/include/crypto/store.h
@@ -17,5 +17,7 @@
 
 void ossl_store_cleanup_int(void);
 int ossl_store_loader_get_number(const OSSL_STORE_LOADER *loader);
+int ossl_store_loader_store_cache_flush(OSSL_LIB_CTX *libctx);
+int ossl_store_loader_store_remove_all_provided(const OSSL_PROVIDER *prov);
 
 #endif