Commit 4024071950 for openssl.org

commit 40240719507cfc09870f0faa28cc6e70084d3ee7
Author: Simo Sorce <simo@redhat.com>
Date:   Tue Nov 25 17:16:50 2025 -0500

    Switch FIPS self tests to deferred execution

    Update the FIPS module to run self-tests on demand (deferred) rather
    than on module load. Change the test definitions in self_test_data.c
    from SELF_TEST_ONLOAD to SELF_TEST_DEFERRED.

    Add calls to ossl_deferred_self_test() in the newctx functions for
    ciphers, digests, signatures, KDFs, KEMs and DRBGs to trigger execution
    upon first instantiation. Introduce CIPHER_PROV_CHECK and
    DIGEST_PROV_CHECK macros in common headers to facilitate these checks.
    Define dependencies for composite tests to ensure prerequisite tests
    run when needed.

    Signed-off-by: Simo Sorce <simo@redhat.com>

    Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
    (Merged from https://github.com/openssl/openssl/pull/29222)

diff --git a/include/internal/fips.h b/include/internal/fips.h
index c2e1d94ace..67b5f7d151 100644
--- a/include/internal/fips.h
+++ b/include/internal/fips.h
@@ -11,6 +11,8 @@
 #define OSSL_INTERNAL_FIPS_H
 #pragma once

+#include <openssl/types.h>
+
 #ifdef FIPS_MODULE

 /* Return 1 if the FIPS self tests are running and 0 otherwise */
@@ -23,6 +25,7 @@ int ossl_fips_self_testing(void);
  */
 typedef enum {
     ST_ID_DIGEST_SHA1,
+    ST_ID_DIGEST_SHA256,
     ST_ID_DIGEST_SHA512,
     ST_ID_DIGEST_SHA3_256,
     ST_ID_CIPHER_AES_256_GCM,
@@ -111,6 +114,22 @@ typedef enum {
 int ossl_deferred_self_test(OSSL_LIB_CTX *libctx, self_test_id_t id);
 int ossl_self_test_in_progress(self_test_id_t id);

+/* Helper definitions to keep some of the ciphercommon.h macros simple */
+#define ST_ID_CIPHER_aes ST_ID_CIPHER_AES_128_ECB
+#define ST_ID_CIPHER_AES_128_CCM ST_ID_CIPHER_AES_128_ECB
+#define ST_ID_CIPHER_AES_128_OCB ST_ID_CIPHER_AES_128_ECB
+#define ST_ID_CIPHER_AES_128_WRP ST_ID_CIPHER_AES_128_ECB
+#define ST_ID_CIPHER_AES_128_XTS ST_ID_CIPHER_AES_128_ECB
+/* Helper definitions to keep some of the digestcommon.h macros simple */
+#define ST_ID_DIGEST_sha1 ST_ID_DIGEST_SHA1
+#define ST_ID_DIGEST_sha224 ST_ID_DIGEST_SHA256
+#define ST_ID_DIGEST_sha256 ST_ID_DIGEST_SHA256
+#define ST_ID_DIGEST_sha256_192_internal ST_ID_DIGEST_SHA256
+#define ST_ID_DIGEST_sha384 ST_ID_DIGEST_SHA512
+#define ST_ID_DIGEST_sha512 ST_ID_DIGEST_SHA512
+#define ST_ID_DIGEST_sha512_224 ST_ID_DIGEST_SHA512
+#define ST_ID_DIGEST_sha512_256 ST_ID_DIGEST_SHA512
+
 #endif /* FIPS_MODULE */

 #endif
diff --git a/providers/fips/self_test.h b/providers/fips/self_test.h
index cff506915e..44c47e669b 100644
--- a/providers/fips/self_test.h
+++ b/providers/fips/self_test.h
@@ -163,7 +163,7 @@ typedef struct self_test_st {
         ST_KAT_KAS kas;
         ST_KAT_DRBG drbg;
     } u;
-    self_test_id_t *depends_on;
+    const self_test_id_t *depends_on;
 } ST_DEFINITION;

 extern ST_DEFINITION st_all_tests[ST_ID_MAX];
diff --git a/providers/fips/self_test_data.c b/providers/fips/self_test_data.c
index 4a5fb3d8c2..c829e3d5af 100644
--- a/providers/fips/self_test_data.c
+++ b/providers/fips/self_test_data.c
@@ -49,6 +49,13 @@ static const unsigned char sha1_digest[] = {
     0xBA, 0x3E, 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C,
     0x9C, 0xD0, 0xD8, 0x9D
 };
+static const unsigned char sha256_pt[] = "abc";
+static const unsigned char sha256_digest[] = {
+    0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
+    0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
+    0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
+    0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD
+};
 static const unsigned char sha512_pt[] = "abc";
 static const unsigned char sha512_digest[] = {
     0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA, 0xCC, 0x41, 0x73, 0x49,
@@ -568,6 +575,12 @@ static const ST_KAT_PARAM kbkdf_kmac_params[] = {
 };
 #endif /* OPENSSL_NO_KBKDF */

+static const self_test_id_t kbkdf_depends_on[] = {
+    ST_ID_KDF_KBKDF,
+    ST_ID_KDF_KBKDF_KMAC,
+    ST_ID_MAX
+};
+
 static const char tls13_kdf_digest[] = "SHA256";
 static int tls13_kdf_extract_mode = EVP_KDF_HKDF_MODE_EXTRACT_ONLY;
 static int tls13_kdf_expand_mode = EVP_KDF_HKDF_MODE_EXPAND_ONLY;
@@ -621,10 +634,15 @@ static const ST_KAT_PARAM tls13_kdf_client_early_secret_params[] = {
 };

 /*
- * NOTES:
- * According to FIPS 140-3 10.3.A Note18: SSH KDF is not required, since it is
- * sufficient to self-test the underlying SHA hash functions.
+ * When calling the HKDF newctx function we do not necessarily know which of
+ * the variants will be used, so we just test them all at once
  */
+static const self_test_id_t hkdf_depends_on[] = {
+    ST_ID_KDF_KBKDF,
+    ST_ID_KDF_TLS13_EXTRACT,
+    ST_ID_KDF_TLS13_EXPAND,
+    ST_ID_MAX
+};

 /*-
  * DRBG test vectors are a small subset of
@@ -1276,6 +1294,13 @@ static const unsigned char rsa_asym_expected_encrypt[256] = {
     0x05, 0x52, 0x55, 0xc1, 0xc6, 0x06, 0x90, 0xab
 };

+static const self_test_id_t rsaenc_depends_on[] = {
+    ST_ID_ASYM_CIPHER_RSA_ENC,
+    ST_ID_ASYM_CIPHER_RSA_DEC,
+    ST_ID_ASYM_CIPHER_RSA_DEC_CRT,
+    ST_ID_MAX
+};
+
 #ifndef OPENSSL_NO_EC
 /* ECDSA key data */
 static const char ecd_prime_curve_name[] = "prime256v1";
@@ -1374,6 +1399,18 @@ static const ST_KAT_PARAM ecdsa_bin_key[] = {
 };
 #endif /* OPENSSL_NO_EC2M */

+/*
+ * ECDSA has 3 tests to run, so we use dependencies to cause
+ * all of them to be run if needed by simply calling one of them
+ */
+static const self_test_id_t ecdsa_depends_on[] = {
+    ST_ID_SIG_DET_ECDSA_SHA256,
+#ifndef OPENSSL_NO_EC2M
+    ST_ID_SIG_E2CM_ECDSA_SHA256,
+#endif
+    ST_ID_MAX
+};
+
 #ifndef OPENSSL_NO_ECX
 static const unsigned char ecx_sig_msg[] = {
     0x64, 0xa6, 0x5f, 0x3c, 0xde, 0xdc, 0xdd, 0x66,
@@ -3266,16 +3303,25 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "SHA1",
         OSSL_SELF_TEST_DESC_MD_SHA1,
         SELF_TEST_KAT_DIGEST,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF_STR(sha1_pt),
         ITM_BUF(sha1_digest),
     },
+    {
+        "SHA256",
+        OSSL_SELF_TEST_DESC_MD_SHA2,
+        SELF_TEST_KAT_DIGEST,
+        SELF_TEST_DEFERRED,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF_STR(sha256_pt),
+        ITM_BUF(sha256_digest),
+    },
     {
         "SHA512",
         OSSL_SELF_TEST_DESC_MD_SHA2,
         SELF_TEST_KAT_DIGEST,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF_STR(sha512_pt),
         ITM_BUF(sha512_digest),
@@ -3284,7 +3330,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "SHA3-256",
         OSSL_SELF_TEST_DESC_MD_SHA3,
         SELF_TEST_KAT_DIGEST,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF(sha3_256_pt),
         ITM_BUF(sha3_256_digest),
@@ -3292,7 +3338,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
     { "AES-256-GCM",
         OSSL_SELF_TEST_DESC_CIPHER_AES_GCM,
         SELF_TEST_KAT_CIPHER,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF(aes_256_gcm_pt),
         ITM_BUF(aes_256_gcm_ct),
@@ -3306,7 +3352,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "AES-128-ECB",
         OSSL_SELF_TEST_DESC_CIPHER_AES_ECB,
         SELF_TEST_KAT_CIPHER,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF(aes_128_ecb_pt),
         ITM_BUF(aes_128_ecb_ct),
@@ -3320,7 +3366,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "DES-EDE3-ECB",
         OSSL_SELF_TEST_DESC_CIPHER_TDES,
         SELF_TEST_KAT_CIPHER,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF(tdes_pt),
         ITM_BUF(tdes_ct),
@@ -3334,7 +3380,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "RSA-SHA256",
         OSSL_SELF_TEST_DESC_SIGN_RSA,
         SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF_STR(rsa_sig_msg),
         ITM_BUF(rsa_expected_sig),
@@ -3352,7 +3398,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "ECDSA-SHA256",
         OSSL_SELF_TEST_DESC_SIGN_ECDSA,
         SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF_STR(rsa_sig_msg),
         ITM_BUF(ecdsa_prime_expected_sig),
@@ -3364,13 +3410,14 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
             ITM_BUF(sig_kat_nonce),
             ITM_BUF(sig_kat_persstr),
         },
+        .depends_on = ecdsa_depends_on,
     },
 #ifndef OPENSSL_NO_HMAC_DRBG_KDF
     {
         "ECDSA-SHA256",
         OSSL_SELF_TEST_DESC_SIGN_DetECDSA,
         SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF_STR(rsa_sig_msg),
         ITM_BUF(ecdsa_prime_expected_detsig),
@@ -3387,7 +3434,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "ECDSA-SHA256",
         OSSL_SELF_TEST_DESC_SIGN_ECDSA,
         SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF_STR(rsa_sig_msg),
         ITM_BUF(ecdsa_bin_expected_sig),
@@ -3406,7 +3453,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "ED448",
         OSSL_SELF_TEST_DESC_SIGN_EDDSA,
         SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF(ecx_sig_msg),
         ITM_BUF(ed448_expected_sig),
@@ -3420,7 +3467,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "ED25519",
         OSSL_SELF_TEST_DESC_SIGN_EDDSA,
         SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF(ecx_sig_msg),
         ITM_BUF(ed25519_expected_sig),
@@ -3437,7 +3484,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "DSA-SHA256",
         OSSL_SELF_TEST_DESC_SIGN_DSA,
         SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF_STR(rsa_sig_msg),
         ITM_BUF(dsa_expected_sig),
@@ -3456,7 +3503,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "ML-DSA-65",
         OSSL_SELF_TEST_DESC_SIGN_ML_DSA,
         SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF(ml_dsa_65_msg),
         ITM_BUF(ml_dsa_65_sig),
@@ -3527,7 +3574,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "LMS",
         OSSL_SELF_TEST_DESC_SIGN_LMS,
         SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF(sha256_192_msg),
         ITM_BUF(sha256_192_sig),
@@ -3542,29 +3589,31 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         OSSL_KDF_NAME_TLS1_3_KDF,
         OSSL_SELF_TEST_DESC_KDF_TLS13_EXTRACT,
         SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(tls13_kdf_early_secret),
         .u.kdf = {
             tls13_kdf_early_secret_params,
         },
+        .depends_on = hkdf_depends_on,
     },
     {
         OSSL_KDF_NAME_TLS1_3_KDF,
         OSSL_SELF_TEST_DESC_KDF_TLS13_EXPAND,
         SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(tls13_kdf_client_early_traffic_secret),
         .u.kdf = {
             tls13_kdf_client_early_secret_params,
         },
+        .depends_on = hkdf_depends_on,
     },
     {
         OSSL_KDF_NAME_TLS1_PRF,
         OSSL_SELF_TEST_DESC_KDF_TLS12_PRF,
         SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(tls12prf_expected),
         .u.kdf = {
@@ -3575,7 +3624,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         OSSL_KDF_NAME_PBKDF2,
         OSSL_SELF_TEST_DESC_KDF_PBKDF2,
         SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(pbkdf2_expected),
         .u.kdf = {
@@ -3587,42 +3636,45 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         OSSL_KDF_NAME_KBKDF,
         OSSL_SELF_TEST_DESC_KDF_KBKDF,
         SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(kbkdf_expected),
         .u.kdf = {
             kbkdf_params,
         },
+        .depends_on = kbkdf_depends_on,
     },
     {
         OSSL_KDF_NAME_KBKDF,
         OSSL_SELF_TEST_DESC_KDF_KBKDF_KMAC,
         SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(kbkdf_kmac_expected),
         .u.kdf = {
             kbkdf_kmac_params,
         },
+        .depends_on = kbkdf_depends_on,
     },
 #endif
     {
         OSSL_KDF_NAME_HKDF,
         OSSL_SELF_TEST_DESC_KDF_HKDF,
         SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(hkdf_expected),
         .u.kdf = {
             hkdf_params,
         },
+        .depends_on = hkdf_depends_on,
     },
 #ifndef OPENSSL_NO_SNMPKDF
     {
         OSSL_KDF_NAME_SNMPKDF,
         OSSL_SELF_TEST_DESC_KDF_SNMPKDF,
         SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(snmpkdf_expected),
         .u.kdf = {
@@ -3635,7 +3687,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         OSSL_KDF_NAME_SRTPKDF,
         OSSL_SELF_TEST_DESC_KDF_SRTPKDF,
         SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(srtpkdf_expected),
         .u.kdf = {
@@ -3648,12 +3700,10 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         OSSL_KDF_NAME_SSKDF,
         OSSL_SELF_TEST_DESC_KDF_SSKDF,
         SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(sskdf_expected),
-        .u.kdf = {
-            sskdf_params,
-        },
+        .u.kdf = { sskdf_params },
     },
 #endif
 #ifndef OPENSSL_NO_X963KDF
@@ -3661,12 +3711,10 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         OSSL_KDF_NAME_X963KDF,
         OSSL_SELF_TEST_DESC_KDF_X963KDF,
         SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(x963kdf_expected),
-        .u.kdf = {
-            x963kdf_params,
-        },
+        .u.kdf = { x963kdf_params },
     },
 #endif
 #ifndef OPENSSL_NO_X942KDF
@@ -3674,7 +3722,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         OSSL_KDF_NAME_X942KDF_ASN1,
         OSSL_SELF_TEST_DESC_KDF_X942KDF,
         SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(x942kdf_expected),
         .u.kdf = {
@@ -3686,7 +3734,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "HASH-DRBG",
         OSSL_SELF_TEST_DESC_DRBG_HASH,
         SELF_TEST_DRBG,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(drbg_hash_sha256_pr_expected),
         .u.drbg = {
@@ -3705,7 +3753,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "CTR-DRBG",
         OSSL_SELF_TEST_DESC_DRBG_CTR,
         SELF_TEST_DRBG,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(drbg_ctr_aes128_pr_df_expected),
         .u.drbg = {
@@ -3724,7 +3772,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "HMAC-DRBG",
         OSSL_SELF_TEST_DESC_DRBG_HMAC,
         SELF_TEST_DRBG,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(drbg_hmac_sha2_pr_expected),
         .u.drbg = {
@@ -3744,7 +3792,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "DH",
         OSSL_SELF_TEST_DESC_KA_DH,
         SELF_TEST_KAT_KAS,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(dh_secret_expected),
         .u.kas = {
@@ -3759,7 +3807,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "EC",
         OSSL_SELF_TEST_DESC_KA_ECDH,
         SELF_TEST_KAT_KAS,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .expected = ITM_BUF(ecdh_secret_expected),
         .u.kas = {
@@ -3778,7 +3826,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "ML-KEM-512",
         OSSL_SELF_TEST_DESC_KEYGEN_ML_KEM,
         SELF_TEST_KAT_ASYM_KEYGEN,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .u.akgen = {
             ml_kem_keygen_params,
@@ -3791,7 +3839,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "ML-DSA-65",
         OSSL_SELF_TEST_DESC_KEYGEN_ML_DSA,
         SELF_TEST_KAT_ASYM_KEYGEN,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .u.akgen = {
             ml_dsa_keygen_params,
@@ -3817,7 +3865,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "ML-KEM-512",
         OSSL_SELF_TEST_DESC_KEM,
         SELF_TEST_KAT_KEM,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .u.kem = {
             ml_kem_key,
@@ -3832,7 +3880,7 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
         "RSA",
         OSSL_SELF_TEST_DESC_ASYM_RSA_ENC,
         SELF_TEST_KAT_ASYM_CIPHER,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF(rsa_asym_plaintext_encrypt),
         ITM_BUF(rsa_asym_expected_encrypt),
@@ -3841,12 +3889,13 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
             rsa_pub_key,
             rsa_enc_params,
         },
+        .depends_on = rsaenc_depends_on,
     },
     {
         "RSA",
         OSSL_SELF_TEST_DESC_ASYM_RSA_DEC,
         SELF_TEST_KAT_ASYM_CIPHER,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF(rsa_asym_expected_encrypt),
         ITM_BUF(rsa_asym_plaintext_encrypt),
@@ -3855,12 +3904,13 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
             rsa_priv_key,
             rsa_enc_params,
         },
+        .depends_on = rsaenc_depends_on,
     },
     {
         "RSA",
         OSSL_SELF_TEST_DESC_ASYM_RSA_DEC,
         SELF_TEST_KAT_ASYM_CIPHER,
-        SELF_TEST_ONLOAD,
+        SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         ITM_BUF(rsa_asym_expected_encrypt),
         ITM_BUF(rsa_asym_plaintext_encrypt),
@@ -3869,5 +3919,6 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = {
             rsa_crt_key,
             rsa_enc_params,
         },
+        .depends_on = rsaenc_depends_on,
     },
 };
diff --git a/providers/implementations/asymciphers/rsa_enc.c b/providers/implementations/asymciphers/rsa_enc.c
index 58c7671660..075209cdbe 100644
--- a/providers/implementations/asymciphers/rsa_enc.c
+++ b/providers/implementations/asymciphers/rsa_enc.c
@@ -25,6 +25,7 @@
 #include <openssl/prov_ssl.h>
 #include "internal/constant_time.h"
 #include "internal/cryptlib.h"
+#include "internal/fips.h"
 #include "internal/sizes.h"
 #include "crypto/rsa.h"
 #include "prov/provider_ctx.h"
@@ -86,6 +87,13 @@ static void *rsa_newctx(void *provctx)

     if (!ossl_prov_is_running())
         return NULL;
+
+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_ASYM_CIPHER_RSA_ENC))
+        return NULL;
+#endif
+
     prsactx = OPENSSL_zalloc(sizeof(PROV_RSA_CTX));
     if (prsactx == NULL)
         return NULL;
diff --git a/providers/implementations/ciphers/cipher_aes_cbc_hmac_sha.c b/providers/implementations/ciphers/cipher_aes_cbc_hmac_sha.c
index 9fe1c99dac..6d9c7214d8 100644
--- a/providers/implementations/ciphers/cipher_aes_cbc_hmac_sha.c
+++ b/providers/implementations/ciphers/cipher_aes_cbc_hmac_sha.c
@@ -287,6 +287,15 @@ static void *aes_cbc_hmac_sha1_newctx(void *provctx, size_t kbits,
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_CIPHER_AES_128_ECB))
+        return NULL;
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_DIGEST_SHA1))
+        return NULL;
+#endif
+
     ctx = OPENSSL_zalloc(sizeof(*ctx));
     if (ctx != NULL)
         base_init(provctx, &ctx->base_ctx,
@@ -327,6 +336,15 @@ static void *aes_cbc_hmac_sha256_newctx(void *provctx, size_t kbits,
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_CIPHER_AES_128_ECB))
+        return NULL;
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_DIGEST_SHA256))
+        return NULL;
+#endif
+
     ctx = OPENSSL_zalloc(sizeof(*ctx));
     if (ctx != NULL)
         base_init(provctx, &ctx->base_ctx,
diff --git a/providers/implementations/ciphers/cipher_aes_ccm.c b/providers/implementations/ciphers/cipher_aes_ccm.c
index 34d6bf468d..7138c9a0f5 100644
--- a/providers/implementations/ciphers/cipher_aes_ccm.c
+++ b/providers/implementations/ciphers/cipher_aes_ccm.c
@@ -24,9 +24,7 @@ static void *aes_ccm_newctx(void *provctx, size_t keybits)
 {
     PROV_AES_CCM_CTX *ctx;

-    if (!ossl_prov_is_running())
-        return NULL;
-
+    CIPHER_PROV_CHECK(provctx, AES_128_CCM);
     ctx = OPENSSL_zalloc(sizeof(*ctx));
     if (ctx != NULL)
         ossl_ccm_initctx(&ctx->base, keybits, ossl_prov_aes_hw_ccm(keybits));
diff --git a/providers/implementations/ciphers/cipher_aes_gcm.c b/providers/implementations/ciphers/cipher_aes_gcm.c
index 0a813de47a..1095db87bc 100644
--- a/providers/implementations/ciphers/cipher_aes_gcm.c
+++ b/providers/implementations/ciphers/cipher_aes_gcm.c
@@ -24,9 +24,7 @@ static void *aes_gcm_newctx(void *provctx, size_t keybits)
 {
     PROV_AES_GCM_CTX *ctx;

-    if (!ossl_prov_is_running())
-        return NULL;
-
+    CIPHER_PROV_CHECK(provctx, AES_256_GCM);
     ctx = OPENSSL_zalloc(sizeof(*ctx));
     if (ctx != NULL)
         ossl_gcm_initctx(provctx, &ctx->base, keybits,
diff --git a/providers/implementations/ciphers/cipher_aes_ocb.c b/providers/implementations/ciphers/cipher_aes_ocb.c
index 31ceb4b637..c59d0bc430 100644
--- a/providers/implementations/ciphers/cipher_aes_ocb.c
+++ b/providers/implementations/ciphers/cipher_aes_ocb.c
@@ -307,9 +307,7 @@ static void *aes_ocb_newctx(void *provctx, size_t kbits, size_t blkbits,
 {
     PROV_AES_OCB_CTX *ctx;

-    if (!ossl_prov_is_running())
-        return NULL;
-
+    CIPHER_PROV_CHECK(provctx, AES_128_OCB);
     ctx = OPENSSL_zalloc(sizeof(*ctx));
     if (ctx != NULL) {
         ossl_cipher_generic_initkey(ctx, kbits, blkbits, ivbits, mode, flags,
diff --git a/providers/implementations/ciphers/cipher_aes_wrp.c b/providers/implementations/ciphers/cipher_aes_wrp.c
index c947f5f694..61441a3e57 100644
--- a/providers/implementations/ciphers/cipher_aes_wrp.c
+++ b/providers/implementations/ciphers/cipher_aes_wrp.c
@@ -48,15 +48,13 @@ typedef struct prov_aes_wrap_ctx_st {

 } PROV_AES_WRAP_CTX;

-static void *aes_wrap_newctx(size_t kbits, size_t blkbits,
+static void *aes_wrap_newctx(void *provctx, size_t kbits, size_t blkbits,
     size_t ivbits, unsigned int mode, uint64_t flags)
 {
     PROV_AES_WRAP_CTX *wctx;
     PROV_CIPHER_CTX *ctx;

-    if (!ossl_prov_is_running())
-        return NULL;
-
+    CIPHER_PROV_CHECK(provctx, AES_128_WRP);
     wctx = OPENSSL_zalloc(sizeof(*wctx));
     ctx = (PROV_CIPHER_CTX *)wctx;
     if (ctx != NULL) {
@@ -310,7 +308,7 @@ static int aes_wrap_set_ctx_params(void *vctx, const OSSL_PARAM params[])
     static OSSL_FUNC_cipher_newctx_fn aes_##kbits##fname##_newctx;              \
     static void *aes_##kbits##fname##_newctx(void *provctx)                     \
     {                                                                           \
-        return aes_##mode##_newctx(kbits, blkbits, ivbits,                      \
+        return aes_##mode##_newctx(provctx, kbits, blkbits, ivbits,             \
             EVP_CIPH_##UCMODE##_MODE, flags);                                   \
     }                                                                           \
     const OSSL_DISPATCH ossl_##aes##kbits##fname##_functions[] = {              \
diff --git a/providers/implementations/ciphers/cipher_aes_xts.c b/providers/implementations/ciphers/cipher_aes_xts.c
index 464b641210..c5aef7987d 100644
--- a/providers/implementations/ciphers/cipher_aes_xts.c
+++ b/providers/implementations/ciphers/cipher_aes_xts.c
@@ -126,9 +126,7 @@ static void *aes_xts_newctx(void *provctx, unsigned int mode, uint64_t flags,
 {
     PROV_AES_XTS_CTX *ctx;

-    if (!ossl_prov_is_running())
-        return NULL;
-
+    CIPHER_PROV_CHECK(provctx, AES_128_XTS);
     ctx = OPENSSL_zalloc(sizeof(*ctx));
     if (ctx != NULL) {
         ossl_cipher_generic_initkey(&ctx->base, kbits, blkbits, ivbits, mode,
diff --git a/providers/implementations/ciphers/cipher_tdes_common.c b/providers/implementations/ciphers/cipher_tdes_common.c
index 328b58dc2e..bd5e2c9c56 100644
--- a/providers/implementations/ciphers/cipher_tdes_common.c
+++ b/providers/implementations/ciphers/cipher_tdes_common.c
@@ -25,8 +25,7 @@ void *ossl_tdes_newctx(void *provctx, int mode, size_t kbits, size_t blkbits,
 {
     PROV_TDES_CTX *tctx;

-    if (!ossl_prov_is_running())
-        return NULL;
+    CIPHER_PROV_CHECK(provctx, DES_EDE3_ECB);

     tctx = OPENSSL_zalloc(sizeof(*tctx));
     if (tctx != NULL) {
diff --git a/providers/implementations/digests/sha3_prov.c b/providers/implementations/digests/sha3_prov.c
index 67cc691708..57adcc2efd 100644
--- a/providers/implementations/digests/sha3_prov.c
+++ b/providers/implementations/digests/sha3_prov.c
@@ -506,48 +506,62 @@ static PROV_SHA3_METHOD shake_ARMSHA3_md = {
 #define SHAKE_SET_MD(uname, typ) ctx->meth = shake_generic_md;
 #endif /* S390_SHA3 */

-#define SHA3_newctx(typ, uname, name, bitlen, pad)                                  \
-    static OSSL_FUNC_digest_newctx_fn name##_newctx;                                \
-    static void *name##_newctx(void *provctx)                                       \
-    {                                                                               \
-        KECCAK1600_CTX *ctx = ossl_prov_is_running() ? OPENSSL_zalloc(sizeof(*ctx)) \
-                                                     : NULL;                        \
-                                                                                    \
-        if (ctx == NULL)                                                            \
-            return NULL;                                                            \
-        ossl_sha3_init(ctx, pad, bitlen);                                           \
-        SHA3_SET_MD(uname, typ)                                                     \
-        return ctx;                                                                 \
+#define SHA3_newctx(typ, uname, name, bitlen, pad)        \
+    static OSSL_FUNC_digest_newctx_fn name##_newctx;      \
+    static void *name##_newctx(void *provctx)             \
+    {                                                     \
+        KECCAK1600_CTX *ctx;                              \
+                                                          \
+        DIGEST_PROV_CHECK(provctx, SHA3_256);             \
+        if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) \
+            return NULL;                                  \
+        ossl_sha3_init(ctx, pad, bitlen);                 \
+        SHA3_SET_MD(uname, typ)                           \
+        return ctx;                                       \
     }

-#define SHAKE_newctx(typ, uname, name, bitlen, mdlen, pad)                          \
-    static OSSL_FUNC_digest_newctx_fn name##_newctx;                                \
-    static void *name##_newctx(void *provctx)                                       \
-    {                                                                               \
-        KECCAK1600_CTX *ctx = ossl_prov_is_running() ? OPENSSL_zalloc(sizeof(*ctx)) \
-                                                     : NULL;                        \
-                                                                                    \
-        if (ctx == NULL)                                                            \
-            return NULL;                                                            \
-        ossl_keccak_init(ctx, pad, bitlen, mdlen);                                  \
-        if (mdlen == 0)                                                             \
-            ctx->md_size = SIZE_MAX;                                                \
-        SHAKE_SET_MD(uname, typ)                                                    \
-        return ctx;                                                                 \
+#define SHAKE_newctx(typ, uname, name, bitlen, mdlen, pad) \
+    static OSSL_FUNC_digest_newctx_fn name##_newctx;       \
+    static void *name##_newctx(void *provctx)              \
+    {                                                      \
+        KECCAK1600_CTX *ctx;                               \
+                                                           \
+        DIGEST_PROV_CHECK(provctx, SHA3_256);              \
+        if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)  \
+            return NULL;                                   \
+        ossl_keccak_init(ctx, pad, bitlen, mdlen);         \
+        if (mdlen == 0)                                    \
+            ctx->md_size = SIZE_MAX;                       \
+        SHAKE_SET_MD(uname, typ)                           \
+        return ctx;                                        \
     }

-#define CSHAKE_KECCAK_newctx(uname, bitlen, pad)                                    \
-    static OSSL_FUNC_digest_newctx_fn uname##_newctx;                               \
-    static void *uname##_newctx(void *provctx)                                      \
-    {                                                                               \
-        KECCAK1600_CTX *ctx = ossl_prov_is_running() ? OPENSSL_zalloc(sizeof(*ctx)) \
-                                                     : NULL;                        \
-                                                                                    \
-        if (ctx == NULL)                                                            \
-            return NULL;                                                            \
-        ossl_keccak_init(ctx, pad, bitlen, 2 * bitlen);                             \
-        CSHAKE_KECCAK_SET_MD(bitlen)                                                \
-        return ctx;                                                                 \
+#define CSHAKE_KECCAK_newctx(uname, bitlen, pad)          \
+    static OSSL_FUNC_digest_newctx_fn uname##_newctx;     \
+    static void *uname##_newctx(void *provctx)            \
+    {                                                     \
+        KECCAK1600_CTX *ctx;                              \
+                                                          \
+        DIGEST_PROV_CHECK(provctx, SHA3_256);             \
+        if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) \
+            return NULL;                                  \
+        ossl_keccak_init(ctx, pad, bitlen, 2 * bitlen);   \
+        CSHAKE_KECCAK_SET_MD(bitlen)                      \
+        return ctx;                                       \
+    }
+
+#define KMAC_newctx(uname, bitlen, pad)                   \
+    static OSSL_FUNC_digest_newctx_fn uname##_newctx;     \
+    static void *uname##_newctx(void *provctx)            \
+    {                                                     \
+        KECCAK1600_CTX *ctx;                              \
+                                                          \
+        DIGEST_PROV_CHECK(provctx, SHA3_256);             \
+        if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) \
+            return NULL;                                  \
+        ossl_keccak_init(ctx, pad, bitlen, 2 * bitlen);   \
+        KMAC_SET_MD(bitlen)                               \
+        return ctx;                                       \
     }

 #define PROV_FUNC_SHA3_DIGEST_COMMON(name, bitlen, blksize, dgstsize, flags)  \
diff --git a/providers/implementations/exchange/dh_exch.c b/providers/implementations/exchange/dh_exch.c
index 209023ab0e..9720cc1ea2 100644
--- a/providers/implementations/exchange/dh_exch.c
+++ b/providers/implementations/exchange/dh_exch.c
@@ -22,6 +22,7 @@
 #include <openssl/proverr.h>
 #include <openssl/params.h>
 #include "internal/cryptlib.h"
+#include "internal/fips.h"
 #include "prov/providercommon.h"
 #include "prov/implementations.h"
 #include "prov/provider_ctx.h"
@@ -88,6 +89,12 @@ static void *dh_newctx(void *provctx)
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_KA_DH))
+        return NULL;
+#endif
+
     pdhctx = OPENSSL_zalloc(sizeof(PROV_DH_CTX));
     if (pdhctx == NULL)
         return NULL;
diff --git a/providers/implementations/exchange/ecdh_exch.c b/providers/implementations/exchange/ecdh_exch.c
index 400f0d5ba6..c5b0c185bc 100644
--- a/providers/implementations/exchange/ecdh_exch.c
+++ b/providers/implementations/exchange/ecdh_exch.c
@@ -23,6 +23,7 @@
 #include <openssl/err.h>
 #include <openssl/proverr.h>
 #include "internal/cryptlib.h"
+#include "internal/fips.h"
 #include "prov/provider_ctx.h"
 #include "prov/providercommon.h"
 #include "prov/implementations.h"
@@ -90,6 +91,12 @@ static void *ecdh_newctx(void *provctx)
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_KA_ECDH))
+        return NULL;
+#endif
+
     pectx = OPENSSL_zalloc(sizeof(*pectx));
     if (pectx == NULL)
         return NULL;
diff --git a/providers/implementations/include/prov/ciphercommon.h b/providers/implementations/include/prov/ciphercommon.h
index 3583a65afd..c2445289f9 100644
--- a/providers/implementations/include/prov/ciphercommon.h
+++ b/providers/implementations/include/prov/ciphercommon.h
@@ -191,26 +191,42 @@ void ossl_cipher_generic_initkey(void *vctx, size_t kbits, size_t blkbits,
         OSSL_DISPATCH_END                                                                       \
     };

-#define IMPLEMENT_generic_cipher_genfn(alg, UCALG, lcmode, UCMODE, flags,               \
-    kbits, blkbits, ivbits, typ)                                                        \
-    static OSSL_FUNC_cipher_get_params_fn alg##_##kbits##_##lcmode##_get_params;        \
-    static int alg##_##kbits##_##lcmode##_get_params(OSSL_PARAM params[])               \
-    {                                                                                   \
-        return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE,         \
-            flags, kbits, blkbits, ivbits);                                             \
-    }                                                                                   \
-    static OSSL_FUNC_cipher_newctx_fn alg##_##kbits##_##lcmode##_newctx;                \
-    static void *alg##_##kbits##_##lcmode##_newctx(void *provctx)                       \
-    {                                                                                   \
-        PROV_##UCALG##_CTX *ctx = ossl_prov_is_running() ? OPENSSL_zalloc(sizeof(*ctx)) \
-                                                         : NULL;                        \
-        if (ctx != NULL) {                                                              \
-            ossl_cipher_generic_initkey(ctx, kbits, blkbits, ivbits,                    \
-                EVP_CIPH_##UCMODE##_MODE, flags,                                        \
-                ossl_prov_cipher_hw_##alg##_##lcmode(kbits),                            \
-                provctx);                                                               \
-        }                                                                               \
-        return ctx;                                                                     \
+#if defined(FIPS_MODULE)
+#include "internal/fips.h"
+#include "prov/provider_ctx.h"
+#define CIPHER_PROV_CHECK(provctx, name)                  \
+    if (!ossl_prov_is_running())                          \
+        return NULL;                                      \
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx), \
+            ST_ID_CIPHER_##name))                         \
+    return NULL
+#else
+#define CIPHER_PROV_CHECK(_provtcx, _name) \
+    if (!ossl_prov_is_running())           \
+    return NULL
+#endif /* FIPS_MODULE && CIPHER_IS_FIPS */
+
+#define IMPLEMENT_generic_cipher_genfn(alg, UCALG, lcmode, UCMODE, flags,        \
+    kbits, blkbits, ivbits, typ)                                                 \
+    static OSSL_FUNC_cipher_get_params_fn alg##_##kbits##_##lcmode##_get_params; \
+    static int alg##_##kbits##_##lcmode##_get_params(OSSL_PARAM params[])        \
+    {                                                                            \
+        return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE,  \
+            flags, kbits, blkbits, ivbits);                                      \
+    }                                                                            \
+    static OSSL_FUNC_cipher_newctx_fn alg##_##kbits##_##lcmode##_newctx;         \
+    static void *alg##_##kbits##_##lcmode##_newctx(void *provctx)                \
+    {                                                                            \
+        PROV_##UCALG##_CTX *ctx;                                                 \
+        CIPHER_PROV_CHECK(provctx, alg);                                         \
+        ctx = OPENSSL_zalloc(sizeof(*ctx));                                      \
+        if (ctx != NULL) {                                                       \
+            ossl_cipher_generic_initkey(ctx, kbits, blkbits, ivbits,             \
+                EVP_CIPH_##UCMODE##_MODE, flags,                                 \
+                ossl_prov_cipher_hw_##alg##_##lcmode(kbits),                     \
+                provctx);                                                        \
+        }                                                                        \
+        return ctx;                                                              \
     }

 #define IMPLEMENT_generic_cipher(alg, UCALG, lcmode, UCMODE, flags, kbits,   \
diff --git a/providers/implementations/include/prov/digestcommon.h b/providers/implementations/include/prov/digestcommon.h
index 383fce3e43..6188d947f2 100644
--- a/providers/implementations/include/prov/digestcommon.h
+++ b/providers/implementations/include/prov/digestcommon.h
@@ -49,6 +49,21 @@ extern "C" {
         return 0;                                                                 \
     }

+#if defined(FIPS_MODULE)
+#include "internal/fips.h"
+#include "prov/provider_ctx.h"
+#define DIGEST_PROV_CHECK(provctx, name)                  \
+    if (!ossl_prov_is_running())                          \
+        return NULL;                                      \
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx), \
+            ST_ID_DIGEST_##name))                         \
+    return NULL
+#else
+#define DIGEST_PROV_CHECK(_provctx, _name) \
+    if (!ossl_prov_is_running())           \
+    return NULL
+#endif /* FIPS_MODULE && DIGEST_IS_FIPS */
+
 #define PROV_DISPATCH_FUNC_DIGEST_CONSTRUCT_START(                               \
     name, CTX, blksize, dgstsize, flags, upd, fin)                               \
     static OSSL_FUNC_digest_newctx_fn name##_newctx;                             \
@@ -56,8 +71,8 @@ extern "C" {
     static OSSL_FUNC_digest_dupctx_fn name##_dupctx;                             \
     static void *name##_newctx(void *prov_ctx)                                   \
     {                                                                            \
-        CTX *ctx = ossl_prov_is_running() ? OPENSSL_zalloc(sizeof(*ctx)) : NULL; \
-        return ctx;                                                              \
+        DIGEST_PROV_CHECK(prov_ctx, name);                                       \
+        return OPENSSL_zalloc(sizeof(CTX));                                      \
     }                                                                            \
     static void name##_freectx(void *vctx)                                       \
     {                                                                            \
diff --git a/providers/implementations/kdfs/hkdf.c b/providers/implementations/kdfs/hkdf.c
index a3f81019f9..5d7a0522d4 100644
--- a/providers/implementations/kdfs/hkdf.c
+++ b/providers/implementations/kdfs/hkdf.c
@@ -31,6 +31,7 @@
 #include "prov/provider_util.h"
 #include "prov/securitycheck.h"
 #include "internal/e_os.h"
+#include "internal/fips.h"
 #include "internal/params.h"
 #include "internal/sizes.h"

@@ -100,6 +101,12 @@ static void *kdf_hkdf_new(void *provctx)
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_KDF_HKDF))
+        return NULL;
+#endif
+
     if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL) {
         ctx->provctx = provctx;
         OSSL_FIPS_IND_INIT(ctx)
diff --git a/providers/implementations/kdfs/hmacdrbg_kdf.c b/providers/implementations/kdfs/hmacdrbg_kdf.c
index 1984438bdd..9462188095 100644
--- a/providers/implementations/kdfs/hmacdrbg_kdf.c
+++ b/providers/implementations/kdfs/hmacdrbg_kdf.c
@@ -15,6 +15,7 @@
 #include <openssl/proverr.h>
 #include <openssl/core_names.h>
 #include "internal/common.h"
+#include "internal/fips.h"
 #include "prov/providercommon.h"
 #include "prov/implementations.h"
 #include "prov/hmac_drbg.h"
@@ -43,6 +44,12 @@ static void *hmac_drbg_kdf_new(void *provctx)
 {
     KDF_HMAC_DRBG *ctx;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_DRBG_HMAC))
+        return NULL;
+#endif
+
     if (!ossl_prov_is_running())
         return NULL;

diff --git a/providers/implementations/kdfs/kbkdf.c b/providers/implementations/kdfs/kbkdf.c
index d51fb5d4fc..986b42e2f8 100644
--- a/providers/implementations/kdfs/kbkdf.c
+++ b/providers/implementations/kdfs/kbkdf.c
@@ -45,6 +45,7 @@
 #include "prov/providercommon.h"
 #include "prov/securitycheck.h"
 #include "internal/e_os.h"
+#include "internal/fips.h"
 #include "internal/params.h"

 #define ossl_min(a, b) ((a) < (b)) ? (a) : (b)
@@ -122,6 +123,12 @@ static void *kbkdf_new(void *provctx)
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_KDF_KBKDF))
+        return NULL;
+#endif
+
     ctx = OPENSSL_zalloc(sizeof(*ctx));
     if (ctx == NULL)
         return NULL;
diff --git a/providers/implementations/kdfs/pbkdf2.c b/providers/implementations/kdfs/pbkdf2.c
index 7f7b38beb2..4a300ac022 100644
--- a/providers/implementations/kdfs/pbkdf2.c
+++ b/providers/implementations/kdfs/pbkdf2.c
@@ -22,6 +22,7 @@
 #include <openssl/core_names.h>
 #include <openssl/proverr.h>
 #include "internal/cryptlib.h"
+#include "internal/fips.h"
 #include "internal/numbers.h"
 #include "crypto/evp.h"
 #include "prov/provider_ctx.h"
@@ -97,6 +98,12 @@ static void *kdf_pbkdf2_new_no_init(void *provctx)
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_KDF_PBKDF2))
+        return NULL;
+#endif
+
     ctx = OPENSSL_zalloc(sizeof(*ctx));
     if (ctx == NULL)
         return NULL;
diff --git a/providers/implementations/kdfs/snmpkdf.c b/providers/implementations/kdfs/snmpkdf.c
index 5e4831fdeb..fabcfc4b9f 100644
--- a/providers/implementations/kdfs/snmpkdf.c
+++ b/providers/implementations/kdfs/snmpkdf.c
@@ -16,6 +16,7 @@
 #include <openssl/core_names.h>
 #include <openssl/proverr.h>
 #include "internal/cryptlib.h"
+#include "internal/fips.h"
 #include "internal/numbers.h"
 #include "crypto/evp.h"
 #include "prov/provider_ctx.h"
@@ -61,6 +62,12 @@ static void *kdf_snmpkdf_new(void *provctx)
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_KDF_SNMPKDF))
+        return NULL;
+#endif
+
     if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL)
         ctx->provctx = provctx;
     return ctx;
diff --git a/providers/implementations/kdfs/srtpkdf.c b/providers/implementations/kdfs/srtpkdf.c
index 24d9f39935..8a4cb9c05d 100644
--- a/providers/implementations/kdfs/srtpkdf.c
+++ b/providers/implementations/kdfs/srtpkdf.c
@@ -16,6 +16,7 @@
 #include <openssl/core_names.h>
 #include <openssl/proverr.h>
 #include "internal/cryptlib.h"
+#include "internal/fips.h"
 #include "internal/numbers.h"
 #include "crypto/evp.h"
 #include "prov/provider_ctx.h"
@@ -75,6 +76,12 @@ static void *kdf_srtpkdf_new(void *provctx)
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_KDF_SRTPKDF))
+        return NULL;
+#endif
+
     if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL)
         ctx->provctx = provctx;
     return ctx;
diff --git a/providers/implementations/kdfs/sshkdf.c b/providers/implementations/kdfs/sshkdf.c
index b9432d72d5..1efba8c3a8 100644
--- a/providers/implementations/kdfs/sshkdf.c
+++ b/providers/implementations/kdfs/sshkdf.c
@@ -15,6 +15,7 @@
 #include <openssl/core_names.h>
 #include <openssl/proverr.h>
 #include "internal/cryptlib.h"
+#include "internal/fips.h"
 #include "internal/numbers.h"
 #include "crypto/evp.h"
 #include "prov/provider_ctx.h"
@@ -61,6 +62,16 @@ static void *kdf_sshkdf_new(void *provctx)
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    /*
+     * Normally we'd want a call to ossl_deferred_self_test() here, but
+     * according to FIPS 140-3 10.3.A Note18: SSH KDF is not required, since
+     * it is sufficient to self-test the underlying SHA hash functions.
+     * The underlying hash functions are implicitly tested when the hash is
+     * instantiated, so we do not need to have an explicit test here.
+     */
+#endif
+
     if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL) {
         ctx->provctx = provctx;
         OSSL_FIPS_IND_INIT(ctx)
diff --git a/providers/implementations/kdfs/sskdf.c b/providers/implementations/kdfs/sskdf.c
index 2e61cf3f21..1747d95c1a 100644
--- a/providers/implementations/kdfs/sskdf.c
+++ b/providers/implementations/kdfs/sskdf.c
@@ -44,6 +44,7 @@
 #include <openssl/params.h>
 #include <openssl/proverr.h>
 #include "internal/cryptlib.h"
+#include "internal/fips.h"
 #include "internal/numbers.h"
 #include "crypto/evp.h"
 #include "prov/provider_ctx.h"
@@ -86,7 +87,9 @@ struct sskdf_all_set_ctx_params_st {
     int num_info;
 };

+static OSSL_FUNC_kdf_newctx_fn sskdf_common_new;
 static OSSL_FUNC_kdf_newctx_fn sskdf_new;
+static OSSL_FUNC_kdf_newctx_fn x963_new;
 static OSSL_FUNC_kdf_dupctx_fn sskdf_dup;
 static OSSL_FUNC_kdf_freectx_fn sskdf_free;
 static OSSL_FUNC_kdf_reset_fn sskdf_reset;
@@ -317,7 +320,7 @@ end:
 }
 #endif /* OPENSSL_NO_SSKDF */

-static void *sskdf_new(void *provctx)
+static void *sskdf_common_new(void *provctx)
 {
     KDF_SSKDF *ctx;

@@ -331,6 +334,28 @@ static void *sskdf_new(void *provctx)
     return ctx;
 }

+static void *sskdf_new(void *provctx)
+{
+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_KDF_SSKDF))
+        return NULL;
+#endif
+
+    return sskdf_common_new(provctx);
+}
+
+static void *x963_new(void *provctx)
+{
+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_KDF_X963KDF))
+        return NULL;
+#endif
+
+    return sskdf_common_new(provctx);
+}
+
 static void sskdf_reset(void *vctx)
 {
     KDF_SSKDF *ctx = (KDF_SSKDF *)vctx;
@@ -360,7 +385,7 @@ static void *sskdf_dup(void *vctx)
     const KDF_SSKDF *src = (const KDF_SSKDF *)vctx;
     KDF_SSKDF *dest;

-    dest = sskdf_new(src->provctx);
+    dest = sskdf_common_new(src->provctx);
     if (dest != NULL) {
         if (src->macctx != NULL) {
             dest->macctx = EVP_MAC_CTX_dup(src->macctx);
@@ -759,7 +784,7 @@ const OSSL_DISPATCH ossl_kdf_sskdf_functions[] = {

 #ifndef OPENSSL_NO_X963KDF
 const OSSL_DISPATCH ossl_kdf_x963_kdf_functions[] = {
-    { OSSL_FUNC_KDF_NEWCTX, (void (*)(void))sskdf_new },
+    { OSSL_FUNC_KDF_NEWCTX, (void (*)(void))x963_new },
     { OSSL_FUNC_KDF_DUPCTX, (void (*)(void))sskdf_dup },
     { OSSL_FUNC_KDF_FREECTX, (void (*)(void))sskdf_free },
     { OSSL_FUNC_KDF_RESET, (void (*)(void))sskdf_reset },
diff --git a/providers/implementations/kdfs/tls1_prf.c b/providers/implementations/kdfs/tls1_prf.c
index 77911c9591..48295bbf23 100644
--- a/providers/implementations/kdfs/tls1_prf.c
+++ b/providers/implementations/kdfs/tls1_prf.c
@@ -69,6 +69,7 @@
 #include "prov/provider_util.h"
 #include "prov/securitycheck.h"
 #include "internal/e_os.h"
+#include "internal/fips.h"
 #include "internal/params.h"
 #include "internal/safe_math.h"

@@ -122,6 +123,12 @@ static void *kdf_tls1_prf_new(void *provctx)
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_KDF_TLS12_PRF))
+        return NULL;
+#endif
+
     if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) != NULL) {
         ctx->provctx = provctx;
         OSSL_FIPS_IND_INIT(ctx)
diff --git a/providers/implementations/kdfs/x942kdf.c b/providers/implementations/kdfs/x942kdf.c
index 5d17914e74..0a178de883 100644
--- a/providers/implementations/kdfs/x942kdf.c
+++ b/providers/implementations/kdfs/x942kdf.c
@@ -18,6 +18,7 @@
 #include "internal/common.h"
 #include "internal/packet.h"
 #include "internal/der.h"
+#include "internal/fips.h"
 #include "internal/nelem.h"
 #include "prov/provider_ctx.h"
 #include "prov/providercommon.h"
@@ -339,6 +340,12 @@ static void *x942kdf_new(void *provctx)
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_KDF_X942KDF))
+        return NULL;
+#endif
+
     ctx = OPENSSL_zalloc(sizeof(*ctx));
     if (ctx == NULL)
         return NULL;
diff --git a/providers/implementations/kem/ml_kem_kem.c b/providers/implementations/kem/ml_kem_kem.c
index fea8b5b692..bec8521978 100644
--- a/providers/implementations/kem/ml_kem_kem.c
+++ b/providers/implementations/kem/ml_kem_kem.c
@@ -17,6 +17,7 @@
 #include <openssl/proverr.h>
 #include "crypto/ml_kem.h"
 #include "internal/cryptlib.h"
+#include "internal/fips.h"
 #include "prov/provider_ctx.h"
 #include "prov/implementations.h"
 #include "prov/securitycheck.h"
@@ -46,6 +47,12 @@ static void *ml_kem_newctx(void *provctx)
     if ((ctx = OPENSSL_malloc(sizeof(*ctx))) == NULL)
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_KEM_ML_KEM))
+        return NULL;
+#endif
+
     ctx->key = NULL;
     ctx->entropy = NULL;
     ctx->op = 0;
diff --git a/providers/implementations/kem/rsa_kem.c b/providers/implementations/kem/rsa_kem.c
index 169cc098c5..7b06a80281 100644
--- a/providers/implementations/kem/rsa_kem.c
+++ b/providers/implementations/kem/rsa_kem.c
@@ -23,6 +23,7 @@
 #include <openssl/proverr.h>
 #include "crypto/rsa.h"
 #include "internal/cryptlib.h"
+#include "internal/fips.h"
 #include "prov/provider_ctx.h"
 #include "prov/providercommon.h"
 #include "prov/implementations.h"
@@ -90,6 +91,12 @@ static void *rsakem_newctx(void *provctx)
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_ASYM_CIPHER_RSA_ENC))
+        return NULL;
+#endif
+
     prsactx = OPENSSL_zalloc(sizeof(PROV_RSA_CTX));
     if (prsactx == NULL)
         return NULL;
diff --git a/providers/implementations/keymgmt/ml_dsa_kmgmt.c b/providers/implementations/keymgmt/ml_dsa_kmgmt.c
index 452a0d6328..75a5142d7a 100644
--- a/providers/implementations/keymgmt/ml_dsa_kmgmt.c
+++ b/providers/implementations/keymgmt/ml_dsa_kmgmt.c
@@ -61,7 +61,8 @@ static int ml_dsa_pairwise_test(const ML_DSA_KEY *key)
     int ret = 0;

     if (!ml_dsa_has(key, OSSL_KEYMGMT_SELECT_KEYPAIR)
-        || ossl_fips_self_testing())
+        || ossl_fips_self_testing()
+        || ossl_self_test_in_progress(ST_ID_ASYM_KEYGEN_ML_DSA))
         return 1;

     /*
@@ -107,6 +108,12 @@ ML_DSA_KEY *ossl_prov_ml_dsa_new(PROV_CTX *ctx, const char *propq, int evp_type)
     if (!ossl_prov_is_running())
         return 0;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(ctx),
+            ST_ID_ASYM_KEYGEN_ML_DSA))
+        return NULL;
+#endif
+
     key = ossl_ml_dsa_key_new(PROV_LIBCTX_OF(ctx), propq, evp_type);
     /*
      * When decoding, if the key ends up "loaded" into the same provider, these
diff --git a/providers/implementations/keymgmt/ml_kem_kmgmt.c b/providers/implementations/keymgmt/ml_kem_kmgmt.c
index 49f26f0dae..2f6e9b211d 100644
--- a/providers/implementations/keymgmt/ml_kem_kmgmt.c
+++ b/providers/implementations/keymgmt/ml_kem_kmgmt.c
@@ -90,7 +90,9 @@ static int ml_kem_pairwise_test(const ML_KEM_KEY *key, int key_flags)
         return 1;
 #ifdef FIPS_MODULE
     /* During self test, it is a waste to do this test */
-    if (ossl_fips_self_testing())
+    if (ossl_fips_self_testing()
+        || ossl_self_test_in_progress(ST_ID_ASYM_KEYGEN_ML_KEM)
+        || ossl_self_test_in_progress(ST_ID_KEM_ML_KEM))
         return 1;

     /*
@@ -161,6 +163,13 @@ ML_KEM_KEY *ossl_prov_ml_kem_new(PROV_CTX *ctx, const char *propq, int evp_type)

     if (!ossl_prov_is_running())
         return NULL;
+
+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(ctx),
+            ST_ID_ASYM_KEYGEN_ML_KEM))
+        return NULL;
+#endif
+
     /*
      * When decoding, if the key ends up "loaded" into the same provider, these
      * are the correct config settings, otherwise, new values will be assigned
diff --git a/providers/implementations/rands/drbg_ctr.c b/providers/implementations/rands/drbg_ctr.c
index 0988d126bb..1cd6062d4e 100644
--- a/providers/implementations/rands/drbg_ctr.c
+++ b/providers/implementations/rands/drbg_ctr.c
@@ -24,6 +24,7 @@
 #include "crypto/evp/evp_local.h"
 #include "internal/provider.h"
 #include "internal/common.h"
+#include "internal/fips.h"

 #define drbg_ctr_get_ctx_params_st drbg_get_ctx_params_st
 #define drbg_ctr_set_ctx_params_st drbg_set_ctx_params_st
@@ -646,6 +647,12 @@ static int drbg_ctr_new(PROV_DRBG *drbg)
 static void *drbg_ctr_new_wrapper(void *provctx, void *parent,
     const OSSL_DISPATCH *parent_dispatch)
 {
+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_DRBG_CTR))
+        return NULL;
+#endif
+
     return ossl_rand_drbg_new(provctx, parent, parent_dispatch,
         &drbg_ctr_new, &drbg_ctr_free,
         &drbg_ctr_instantiate, &drbg_ctr_uninstantiate,
diff --git a/providers/implementations/rands/drbg_hash.c b/providers/implementations/rands/drbg_hash.c
index 439728a760..bc898abbad 100644
--- a/providers/implementations/rands/drbg_hash.c
+++ b/providers/implementations/rands/drbg_hash.c
@@ -25,6 +25,7 @@
 #include "prov/drbg.h"
 #include "crypto/evp.h"
 #include "crypto/evp/evp_local.h"
+#include "internal/fips.h"
 #include "internal/provider.h"

 #define drbg_hash_get_ctx_params_st drbg_get_ctx_params_st
@@ -454,6 +455,12 @@ static int drbg_hash_new(PROV_DRBG *ctx)
 static void *drbg_hash_new_wrapper(void *provctx, void *parent,
     const OSSL_DISPATCH *parent_dispatch)
 {
+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_DRBG_HASH))
+        return NULL;
+#endif
+
     return ossl_rand_drbg_new(provctx, parent, parent_dispatch,
         &drbg_hash_new, &drbg_hash_free,
         &drbg_hash_instantiate, &drbg_hash_uninstantiate,
diff --git a/providers/implementations/rands/drbg_hmac.c b/providers/implementations/rands/drbg_hmac.c
index 3dfc3140f7..121c0e28ce 100644
--- a/providers/implementations/rands/drbg_hmac.c
+++ b/providers/implementations/rands/drbg_hmac.c
@@ -22,6 +22,7 @@
 #include "prov/drbg.h"
 #include "crypto/evp.h"
 #include "crypto/evp/evp_local.h"
+#include "internal/fips.h"
 #include "internal/provider.h"

 #define drbg_hmac_get_ctx_params_st drbg_get_ctx_params_st
@@ -346,6 +347,12 @@ static int drbg_hmac_new(PROV_DRBG *drbg)
 static void *drbg_hmac_new_wrapper(void *provctx, void *parent,
     const OSSL_DISPATCH *parent_dispatch)
 {
+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_DRBG_HMAC))
+        return NULL;
+#endif
+
     return ossl_rand_drbg_new(provctx, parent, parent_dispatch,
         &drbg_hmac_new, &drbg_hmac_free,
         &drbg_hmac_instantiate, &drbg_hmac_uninstantiate,
diff --git a/providers/implementations/signature/dsa_sig.c b/providers/implementations/signature/dsa_sig.c
index 24244748a7..d9b73c65e0 100644
--- a/providers/implementations/signature/dsa_sig.c
+++ b/providers/implementations/signature/dsa_sig.c
@@ -23,6 +23,7 @@
 #include <openssl/params.h>
 #include <openssl/evp.h>
 #include <openssl/proverr.h>
+#include "internal/fips.h"
 #include "internal/nelem.h"
 #include "internal/sizes.h"
 #include "internal/cryptlib.h"
@@ -132,6 +133,12 @@ static void *dsa_newctx(void *provctx, const char *propq)
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_SIG_DSA_SHA256))
+        return NULL;
+#endif
+
     pdsactx = OPENSSL_zalloc(sizeof(PROV_DSA_CTX));
     if (pdsactx == NULL)
         return NULL;
diff --git a/providers/implementations/signature/ecdsa_sig.c b/providers/implementations/signature/ecdsa_sig.c
index eab82ac4ec..8691e2e15f 100644
--- a/providers/implementations/signature/ecdsa_sig.c
+++ b/providers/implementations/signature/ecdsa_sig.c
@@ -32,6 +32,7 @@
 #include "prov/securitycheck.h"
 #include "prov/der_ec.h"
 #include "crypto/ec.h"
+#include "internal/fips.h"

 struct ecdsa_all_set_ctx_params_st {
     OSSL_PARAM *digest; /* ecdsa_set_ctx_params */
@@ -166,6 +167,12 @@ static void *ecdsa_newctx(void *provctx, const char *propq)
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_SIG_ECDSA_SHA256))
+        return NULL;
+#endif
+
     ctx = OPENSSL_zalloc(sizeof(PROV_ECDSA_CTX));
     if (ctx == NULL)
         return NULL;
diff --git a/providers/implementations/signature/eddsa_sig.c b/providers/implementations/signature/eddsa_sig.c
index ee5bac44af..ec08e460b9 100644
--- a/providers/implementations/signature/eddsa_sig.c
+++ b/providers/implementations/signature/eddsa_sig.c
@@ -23,6 +23,7 @@
 #include "prov/provider_ctx.h"
 #include "prov/der_ecx.h"
 #include "crypto/ecx.h"
+#include "internal/fips.h"

 #define eddsa_set_variant_ctx_params_st eddsa_set_ctx_params_st

@@ -67,7 +68,8 @@ enum ID_EdDSA_INSTANCE {
 #define EDDSA_MAX_CONTEXT_STRING_LEN 255
 #define EDDSA_PREHASH_OUTPUT_LEN 64

-static OSSL_FUNC_signature_newctx_fn eddsa_newctx;
+static OSSL_FUNC_signature_newctx_fn ed25519_newctx;
+static OSSL_FUNC_signature_newctx_fn ed448_newctx;
 static OSSL_FUNC_signature_sign_message_init_fn ed25519_signverify_message_init;
 static OSSL_FUNC_signature_sign_message_init_fn ed25519ph_signverify_message_init;
 static OSSL_FUNC_signature_sign_message_init_fn ed25519ctx_signverify_message_init;
@@ -167,13 +169,10 @@ typedef struct {

 } PROV_EDDSA_CTX;

-static void *eddsa_newctx(void *provctx, const char *propq_unused)
+static void *eddsa_newctx(void *provctx)
 {
     PROV_EDDSA_CTX *peddsactx;

-    if (!ossl_prov_is_running())
-        return NULL;
-
     peddsactx = OPENSSL_zalloc(sizeof(PROV_EDDSA_CTX));
     if (peddsactx == NULL)
         return NULL;
@@ -183,6 +182,34 @@ static void *eddsa_newctx(void *provctx, const char *propq_unused)
     return peddsactx;
 }

+static void *ed448_newctx(void *provctx, const char *propq_unused)
+{
+    if (!ossl_prov_is_running())
+        return NULL;
+
+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_SIG_ED448))
+        return NULL;
+#endif
+
+    return eddsa_newctx(provctx);
+}
+
+static void *ed25519_newctx(void *provctx, const char *propq_unused)
+{
+    if (!ossl_prov_is_running())
+        return NULL;
+
+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_SIG_ED25519))
+        return NULL;
+#endif
+
+    return eddsa_newctx(provctx);
+}
+
 static int eddsa_setup_instance(void *vpeddsactx, int instance_id,
     unsigned int instance_id_preset,
     unsigned int prehash_by_caller)
@@ -1029,7 +1056,7 @@ static int eddsa_set_variant_ctx_params(void *vpeddsactx,
 /* vn = variant name, bn = base name */
 #define IMPL_EDDSA_DISPATCH(vn, bn)                                     \
     const OSSL_DISPATCH ossl_##vn##_signature_functions[] = {           \
-        { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))eddsa_newctx },   \
+        { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))bn##_newctx },    \
         { OSSL_FUNC_SIGNATURE_SIGN_MESSAGE_INIT,                        \
             (void (*)(void))vn##_signverify_message_init },             \
         { OSSL_FUNC_SIGNATURE_SIGN,                                     \
diff --git a/providers/implementations/signature/lms_signature.c b/providers/implementations/signature/lms_signature.c
index d1d605494f..65ebe68c00 100644
--- a/providers/implementations/signature/lms_signature.c
+++ b/providers/implementations/signature/lms_signature.c
@@ -18,6 +18,7 @@
 #include "prov/provider_ctx.h"
 #include "prov/implementations.h"
 #include "crypto/lms_sig.h"
+#include "internal/fips.h"

 static OSSL_FUNC_signature_newctx_fn lms_newctx;
 static OSSL_FUNC_signature_freectx_fn lms_freectx;
@@ -38,6 +39,12 @@ static void *lms_newctx(void *provctx, const char *propq)
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_SIG_LMS))
+        return NULL;
+#endif
+
     ctx = OPENSSL_zalloc(sizeof(PROV_LMS_CTX));
     if (ctx == NULL)
         return NULL;
diff --git a/providers/implementations/signature/ml_dsa_sig.c b/providers/implementations/signature/ml_dsa_sig.c
index 766465f839..5debe51818 100644
--- a/providers/implementations/signature/ml_dsa_sig.c
+++ b/providers/implementations/signature/ml_dsa_sig.c
@@ -23,6 +23,7 @@
 #include "internal/common.h"
 #include "internal/packet.h"
 #include "internal/sizes.h"
+#include "internal/fips.h"

 #define ml_dsa_set_ctx_params_st ml_dsa_verifymsg_set_ctx_params_st
 #define ml_dsa_set_ctx_params_decoder ml_dsa_verifymsg_set_ctx_params_decoder
@@ -88,6 +89,12 @@ static void *ml_dsa_newctx(void *provctx, int evp_type, const char *propq)
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_SIG_ML_DSA_65))
+        return NULL;
+#endif
+
     ctx = OPENSSL_zalloc(sizeof(PROV_ML_DSA_CTX));
     if (ctx == NULL)
         return NULL;
diff --git a/providers/implementations/signature/rsa_sig.c b/providers/implementations/signature/rsa_sig.c
index 96e631ae6c..4426543897 100644
--- a/providers/implementations/signature/rsa_sig.c
+++ b/providers/implementations/signature/rsa_sig.c
@@ -32,6 +32,7 @@
 #include "prov/provider_ctx.h"
 #include "prov/der_rsa.h"
 #include "prov/securitycheck.h"
+#include "internal/fips.h"

 #define rsa_set_ctx_params_no_digest_st rsa_set_ctx_params_st

@@ -236,6 +237,12 @@ static void *rsa_newctx(void *provctx, const char *propq)
     if (!ossl_prov_is_running())
         return NULL;

+#ifdef FIPS_MODULE
+    if (!ossl_deferred_self_test(PROV_LIBCTX_OF(provctx),
+            ST_ID_SIG_RSA_SHA256))
+        return NULL;
+#endif
+
     if ((prsactx = OPENSSL_zalloc(sizeof(PROV_RSA_CTX))) == NULL
         || (propq != NULL
             && (propq_copy = OPENSSL_strdup(propq)) == NULL)) {