Commit 66549b5eff for openssl.org

commit 66549b5effea96e53581f3adc3f767eab17a713c
Author: Simo Sorce <simo@redhat.com>
Date:   Tue Dec 2 13:24:41 2025 -0500

    Refactor FIPS self-tests to use ID-based lookup

    Consolidate separate self-test data arrays into a single `st_all_tests`
    array indexed by a new `self_test_id_t` enumeration.

    This replaces string-based algorithm lookups with direct array indexing
    for running self-tests, simplifying the code and state management. The
    `FIPS_DEFERRED_TEST` structure and `self_test_data.h` file are removed,
    and the FIPS provider and implementations are updated to use the new
    ID-based API.

    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 956a88cdbb..c2e1d94ace 100644
--- a/include/internal/fips.h
+++ b/include/internal/fips.h
@@ -16,41 +16,100 @@
 /* Return 1 if the FIPS self tests are running and 0 otherwise */
 int ossl_fips_self_testing(void);

-/* Deferred KAT tests categories */
-
 /*
- * The Integrity category is used to run test that are required by the
- * integrity check and are a special category that can therefore never
- * really be deferred. Keep it commented here as a reminder.
- * #  define FIPS_DEFERRED_KAT_INTEGRITY 0
+ * Each enum here corresponds to a test in the st_all_tests array
+ * in self_test_data.c, any change done here requires tests to be
+ * adjusted accordingly.
  */
-#define FIPS_DEFERRED_KAT_CIPHER 1
-#define FIPS_DEFERRED_KAT_ASYM_CIPHER 2
-#define FIPS_DEFERRED_KAT_ASYM_KEYGEN 3
-#define FIPS_DEFERRED_KAT_KEM 4
-#define FIPS_DEFERRED_KAT_DIGEST 5
-#define FIPS_DEFERRED_KAT_SIGNATURE 6
-#define FIPS_DEFERRED_KAT_KDF 7
-#define FIPS_DEFERRED_KAT_KA 8
-/* Currently unused because all MAC tests are satisfied through other tests */
-#define FIPS_DEFERRED_KAT_MAC 9
-#define FIPS_DEFERRED_DRBG 10
-#define FIPS_DEFERRED_MAX 11
-
-struct fips_deferred_test_st {
-    const char *algorithm;
-    int category;
-    int state;
-};
-
-#define FIPS_DEFERRED_TEST_INIT 0
-#define FIPS_DEFERRED_TEST_IN_PROGRESS 1
-#define FIPS_DEFERRED_TEST_PASSED 2
-#define FIPS_DEFERRED_TEST_FAILED 3
-
-typedef struct fips_deferred_test_st FIPS_DEFERRED_TEST;
+typedef enum {
+    ST_ID_DIGEST_SHA1,
+    ST_ID_DIGEST_SHA512,
+    ST_ID_DIGEST_SHA3_256,
+    ST_ID_CIPHER_AES_256_GCM,
+    ST_ID_CIPHER_AES_128_ECB,
+#ifndef OPENSSL_NO_DES
+    ST_ID_CIPHER_DES_EDE3_ECB,
+#endif
+    ST_ID_SIG_RSA_SHA256,
+#ifndef OPENSSL_NO_EC
+    ST_ID_SIG_ECDSA_SHA256,
+#ifndef OPENSSL_NO_HMAC_DRBG_KDF
+    ST_ID_SIG_DET_ECDSA_SHA256,
+#endif
+#ifndef OPENSSL_NO_EC2M
+    ST_ID_SIG_E2CM_ECDSA_SHA256,
+#endif
+#ifndef OPENSSL_NO_ECX
+    ST_ID_SIG_ED448,
+    ST_ID_SIG_ED25519,
+#endif
+#endif
+#ifndef OPENSSL_NO_DSA
+    ST_ID_SIG_DSA_SHA256,
+#endif
+#ifndef OPENSSL_NO_ML_DSA
+    ST_ID_SIG_ML_DSA_65,
+#endif
+#ifndef OPENSSL_NO_SLH_DSA
+    ST_ID_SIG_SLH_DSA_SHA2_128F,
+    ST_ID_SIG_SLH_DSA_SHAKE_128F,
+#endif /* OPENSSL_NO_SLH_DSA */
+#ifndef OPENSSL_NO_LMS
+    ST_ID_SIG_LMS,
+#endif
+    ST_ID_KDF_TLS13_EXTRACT,
+    ST_ID_KDF_TLS13_EXPAND,
+    ST_ID_KDF_TLS12_PRF,
+    ST_ID_KDF_PBKDF2,
+#ifndef OPENSSL_NO_KBKDF
+    ST_ID_KDF_KBKDF,
+    ST_ID_KDF_KBKDF_KMAC,
+#endif
+    ST_ID_KDF_HKDF,
+#ifndef OPENSSL_NO_SNMPKDF
+    ST_ID_KDF_SNMPKDF,
+#endif
+#ifndef OPENSSL_NO_SRTPKDF
+    ST_ID_KDF_SRTPKDF,
+#endif
+#ifndef OPENSSL_NO_SSKDF
+    ST_ID_KDF_SSKDF,
+#endif
+#ifndef OPENSSL_NO_X963KDF
+    ST_ID_KDF_X963KDF,
+#endif
+#ifndef OPENSSL_NO_X942KDF
+    ST_ID_KDF_X942KDF,
+#endif
+    ST_ID_DRBG_HASH,
+    ST_ID_DRBG_CTR,
+    ST_ID_DRBG_HMAC,
+#ifndef OPENSSL_NO_DH
+    ST_ID_KA_DH,
+#endif
+#ifndef OPENSSL_NO_EC
+    ST_ID_KA_ECDH,
+#endif
+#ifndef OPENSSL_NO_ML_KEM
+    ST_ID_ASYM_KEYGEN_ML_KEM,
+#endif
+#ifndef OPENSSL_NO_ML_DSA
+    ST_ID_ASYM_KEYGEN_ML_DSA,
+#endif
+#ifndef OPENSSL_NO_SLH_DSA
+    ST_ID_ASYM_KEYGEN_SLH_DSA,
+#endif
+#ifndef OPENSSL_NO_ML_KEM
+    ST_ID_KEM_ML_KEM,
+#endif
+    ST_ID_ASYM_CIPHER_RSA_ENC,
+    ST_ID_ASYM_CIPHER_RSA_DEC,
+    ST_ID_ASYM_CIPHER_RSA_DEC_CRT,
+    ST_ID_MAX
+} self_test_id_t;

-int FIPS_deferred_self_tests(OSSL_LIB_CTX *libctx, FIPS_DEFERRED_TEST tests[]);
+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);

 #endif /* FIPS_MODULE */

diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c
index 924cb613a7..933125a9b9 100644
--- a/providers/fips/fipsprov.c
+++ b/providers/fips/fipsprov.c
@@ -126,12 +126,8 @@ void *ossl_fips_prov_ossl_ctx_new(OSSL_LIB_CTX *libctx)
     return fgbl;
 }

-static void deferred_deinit(void);
-
 void ossl_fips_prov_ossl_ctx_free(void *fgbl)
 {
-    /* Also free deferred variables when the FIPS Global context is killed */
-    deferred_deinit();
     OPENSSL_free(fgbl);
 }

@@ -812,8 +808,12 @@ static const OSSL_ALGORITHM *fips_query_internal(void *provctx, int operation_id
     return fips_query(provctx, operation_id, no_cache);
 }

+static void deferred_deinit(void);
+
 static void fips_teardown(void *provctx)
 {
+    /* Also free deferred variables when the FIPS Global context is killed */
+    deferred_deinit();
     OSSL_LIB_CTX_free(PROV_LIBCTX_OF(provctx));
     ossl_prov_ctx_free(provctx);
 }
@@ -1315,27 +1315,39 @@ static void deferred_deinit(void)
     }
 }

-static int FIPS_kat_deferred(OSSL_LIB_CTX *libctx, FIPS_DEFERRED_TEST *test)
+static int FIPS_kat_deferred(OSSL_LIB_CTX *libctx, self_test_id_t id)
 {
-    int ret = FIPS_DEFERRED_TEST_FAILED;
+    int *rt = NULL;
+    int ret = 0;

     if (!CRYPTO_THREAD_run_once(&deferred_once, deferred_init))
-        return FIPS_DEFERRED_TEST_FAILED;
+        return 0;

     if (deferred_lock == NULL)
-        return FIPS_DEFERRED_TEST_FAILED;
+        return 0;

     /*
      * before we do anything, make sure a local test is not already in
      * progress or we'll deadlock
      */
-    if (CRYPTO_THREAD_get_local_ex(CRYPTO_THREAD_LOCAL_FIPS_DEFERRED_KEY,
-            libctx)
-        != NULL)
-        return FIPS_DEFERRED_TEST_IN_PROGRESS;
+    rt = CRYPTO_THREAD_get_local_ex(CRYPTO_THREAD_LOCAL_FIPS_DEFERRED_KEY,
+        libctx);
+    if (rt) {
+        /*
+         * record this test as invoked by the original test, for marking
+         * it later as also satisfied
+         */
+        rt[id] = 1;
+        /*
+         * A self test is in progress for this thread so we let this
+         * thread continue and perform the test while all other
+         * threads wait for it to complete.
+         */
+        return 1;
+    }

     if (CRYPTO_THREAD_write_lock(deferred_lock)) {
-        OSSL_SELF_TEST *ev = NULL;
+        OSSL_SELF_TEST *st = NULL;
         bool unset_key = false;
         OSSL_CALLBACK *cb = NULL;
         void *cb_arg = NULL;
@@ -1344,15 +1356,22 @@ static int FIPS_kat_deferred(OSSL_LIB_CTX *libctx, FIPS_DEFERRED_TEST *test)
          * check again as another thread may have just performed this
          * test and marked it as passed
          */
-        if (test->state == FIPS_DEFERRED_TEST_PASSED) {
-            ret = FIPS_DEFERRED_TEST_PASSED;
+        switch (st_all_tests[id].state) {
+        case SELF_TEST_STATE_INIT:
+            break;
+        case SELF_TEST_STATE_PASSED:
+            ret = 1;
+            goto done;
+        default:
+            /* should not happen, something is broken */
+            ret = 0;
             goto done;
         }

-        /*
-         * mark that we are executing a test on the local thread, does not
-         * matter what value, as long as it is not NULL, Cool?
-         */
+        if ((rt = OPENSSL_calloc(ST_ID_MAX, sizeof(int))) == NULL)
+            goto done;
+
+        /* mark that we are executing a test on the local thread */
         if (!CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_FIPS_DEFERRED_KEY,
                 libctx, (void *)0xC001))
             goto done;
@@ -1362,25 +1381,38 @@ static int FIPS_kat_deferred(OSSL_LIB_CTX *libctx, FIPS_DEFERRED_TEST *test)
         if (c_stcbfn != NULL && c_get_libctx != NULL)
             c_stcbfn(c_get_libctx(FIPS_get_core_handle(libctx)), &cb, &cb_arg);

-        if ((ev = OSSL_SELF_TEST_new(cb, cb_arg)) == NULL)
+        if ((st = OSSL_SELF_TEST_new(cb, cb_arg)) == NULL)
             goto done;

-        /* Mark test as in progress */
-        test->state = FIPS_DEFERRED_TEST_IN_PROGRESS;
+        /*
+         * Dependency chains may cause a test to be referenced multiple times
+         * immediately return if any state is present
+         */
+        if (st_all_tests[id].state == SELF_TEST_STATE_INIT) {

-        /* execute test */
-        if (SELF_TEST_kats_single(ev, libctx, test->category, test->algorithm))
-            ret = FIPS_DEFERRED_TEST_PASSED;
+            /* Mark test as in progress */
+            st_all_tests[id].state = SELF_TEST_STATE_IN_PROGRESS;

-    done:
-        /* Mark test as pass or fail */
-        test->state = ret;
+            /* execute test */
+            if (!SELF_TEST_kats_single(st, libctx, id))
+                goto done;
+        }

-        if (ev)
-            OSSL_SELF_TEST_free(ev);
+        /*
+         * now mark as passed all the algorithms that have been executed by
+         * this test and that we tracked as RECORDED_TESTS
+         */
+        if (st_all_tests[id].state == SELF_TEST_STATE_PASSED)
+            for (int i = 0; i < ST_ID_MAX; i++)
+                if (rt[i])
+                    st_all_tests[i].state = SELF_TEST_STATE_PASSED;
+
+    done:
+        OSSL_SELF_TEST_free(st);
         if (unset_key)
             CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_FIPS_DEFERRED_KEY,
                 libctx, NULL);
+        OPENSSL_free(rt);
         CRYPTO_THREAD_unlock(deferred_lock);
     }
     return ret;
@@ -1391,40 +1423,56 @@ static void deferred_test_error(int category)
     const char *category_name = "Unknown Category Test";

     switch (category) {
-    case FIPS_DEFERRED_KAT_CIPHER:
+    case SELF_TEST_KAT_CIPHER:
         category_name = OSSL_SELF_TEST_TYPE_KAT_CIPHER;
         break;
-    case FIPS_DEFERRED_KAT_ASYM_CIPHER:
+    case SELF_TEST_KAT_ASYM_CIPHER:
         category_name = OSSL_SELF_TEST_TYPE_KAT_ASYM_CIPHER;
         break;
-    case FIPS_DEFERRED_KAT_ASYM_KEYGEN:
+    case SELF_TEST_KAT_ASYM_KEYGEN:
         category_name = OSSL_SELF_TEST_TYPE_KAT_ASYM_KEYGEN;
         break;
-    case FIPS_DEFERRED_KAT_KEM:
+    case SELF_TEST_KAT_KEM:
         category_name = OSSL_SELF_TEST_TYPE_KAT_KEM;
         break;
-    case FIPS_DEFERRED_KAT_DIGEST:
+    case SELF_TEST_KAT_DIGEST:
         category_name = OSSL_SELF_TEST_TYPE_KAT_DIGEST;
         break;
-    case FIPS_DEFERRED_KAT_SIGNATURE:
+    case SELF_TEST_KAT_SIGNATURE:
         category_name = OSSL_SELF_TEST_TYPE_KAT_SIGNATURE;
         break;
-    case FIPS_DEFERRED_KAT_KDF:
+    case SELF_TEST_KAT_KDF:
         category_name = OSSL_SELF_TEST_TYPE_KAT_KDF;
         break;
-    case FIPS_DEFERRED_KAT_KA:
+    case SELF_TEST_KAT_KAS:
         category_name = OSSL_SELF_TEST_TYPE_KAT_KA;
         break;
-    case FIPS_DEFERRED_DRBG:
+    case SELF_TEST_DRBG:
         category_name = OSSL_SELF_TEST_TYPE_DRBG;
         break;
     }
     ossl_set_error_state(category_name);
 }

-int FIPS_deferred_self_tests(OSSL_LIB_CTX *libctx, FIPS_DEFERRED_TEST tests[])
+int ossl_deferred_self_test(OSSL_LIB_CTX *libctx, self_test_id_t id)
 {
-    int i;
+    int ret;
+
+    if (id >= ST_ID_MAX) {
+        ossl_set_error_state(NULL);
+        return 0;
+    }
+
+    /* return immediately if the test is marked as passed */
+    if (st_all_tests[id].state == SELF_TEST_STATE_PASSED)
+        return 1;
+
+    /*
+     * During the initial selftest we do not try to self-test individual
+     * algorithms, or we end up in loops.
+     */
+    if (ossl_fips_self_testing())
+        return 1;

     /*
      * NOTE: that the order in which we check the 'state' here is not important,
@@ -1433,30 +1481,8 @@ int FIPS_deferred_self_tests(OSSL_LIB_CTX *libctx, FIPS_DEFERRED_TEST tests[])
      * concurrent tests runs and saving state from multiple threads is handled
      * in FIPS_kat_deferred() so this race is of no real consequence.
      */
-    for (i = 0; tests[i].algorithm != NULL; i++) {
-        if (tests[i].state != FIPS_DEFERRED_TEST_PASSED) {
-            int state;
-
-            /* any other threads that request a self test will lock and wait */
-            state = FIPS_kat_deferred(libctx, &tests[i]);
-            switch (state) {
-            case FIPS_DEFERRED_TEST_IN_PROGRESS:
-                /*
-                 * A self test is in progress for this thread so we let this
-                 * thread continue and perform the test while all other
-                 * threads wait for it to complete.
-                 */
-                return 1;
-            case FIPS_DEFERRED_TEST_PASSED:
-                /* success, move on to the next */
-                break;
-            default:
-                deferred_test_error(tests[i].category);
-                return 0;
-            }
-        }
-    }
-
-    /* all tests passed */
-    return 1;
+    ret = FIPS_kat_deferred(libctx, id);
+    if (!ret)
+        deferred_test_error(st_all_tests[id].category);
+    return ret;
 }
diff --git a/providers/fips/self_test.h b/providers/fips/self_test.h
index 6ca547e5b2..2c19653b66 100644
--- a/providers/fips/self_test.h
+++ b/providers/fips/self_test.h
@@ -10,6 +10,7 @@
 #include <openssl/core_dispatch.h>
 #include <openssl/types.h>
 #include <openssl/self_test.h>
+#include "internal/fips.h"

 typedef struct self_test_post_params_st {
     /* FIPS module integrity check parameters */
@@ -32,30 +33,30 @@ typedef struct self_test_post_params_st {

 int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test);
 int SELF_TEST_kats(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx, int do_deferred);
-int SELF_TEST_kats_single(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx,
-    int type, const char *alg_name);
+int SELF_TEST_kats_single(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx, int id);

 void SELF_TEST_disable_conditional_error_state(void);

 /* KAT tests categories */
 enum st_test_category {
     SELF_TEST_INTEGRITY = 0, /* currently unused */
-    SELF_TEST_KAT_CIPHER,
-    SELF_TEST_KAT_ASYM_CIPHER,
-    SELF_TEST_KAT_ASYM_KEYGEN,
-    SELF_TEST_KAT_KEM,
     SELF_TEST_KAT_DIGEST,
+    SELF_TEST_KAT_CIPHER,
     SELF_TEST_KAT_SIGNATURE,
     SELF_TEST_KAT_KDF,
+    SELF_TEST_DRBG,
     SELF_TEST_KAT_KAS,
+    SELF_TEST_KAT_ASYM_KEYGEN,
+    SELF_TEST_KAT_KEM,
+    SELF_TEST_KAT_ASYM_CIPHER,
     SELF_TEST_KAT_MAC, /* currently unused */
-    SELF_TEST_DRBG
 };

 enum st_test_state {
     SELF_TEST_STATE_INIT = 0,
     SELF_TEST_STATE_IN_PROGRESS,
     SELF_TEST_STATE_PASSED,
+    SELF_TEST_STATE_FAILED,
 };

 #define SELF_TEST_ONLOAD 0
@@ -163,3 +164,5 @@ typedef struct self_test_st {
         ST_KAT_DRBG drbg;
     } u;
 } 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 8607c8d0bb..4a5fb3d8c2 100644
--- a/providers/fips/self_test_data.c
+++ b/providers/fips/self_test_data.c
@@ -65,42 +65,6 @@ static const unsigned char sha3_256_digest[] = {
     0x89, 0x77, 0x7f, 0x05, 0x1e, 0x40, 0x46, 0xae
 };

-/*
- * Note:
- *  SHA256 is tested by higher level algorithms so a
- *  CAST is not needed.
- */
-const ST_DEFINITION st_kat_digest_tests[] = {
-    {
-        "SHA1",
-        OSSL_SELF_TEST_DESC_MD_SHA1,
-        SELF_TEST_KAT_DIGEST,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        ITM_BUF_STR(sha1_pt),
-        ITM_BUF(sha1_digest),
-    },
-    {
-        "SHA512",
-        OSSL_SELF_TEST_DESC_MD_SHA2,
-        SELF_TEST_KAT_DIGEST,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        ITM_BUF_STR(sha512_pt),
-        ITM_BUF(sha512_digest),
-    },
-    {
-        "SHA3-256",
-        OSSL_SELF_TEST_DESC_MD_SHA3,
-        SELF_TEST_KAT_DIGEST,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        ITM_BUF(sha3_256_pt),
-        ITM_BUF(sha3_256_digest),
-    },
-};
-int st_kat_digest_tests_size = OSSL_NELEM(st_kat_digest_tests);
-
 /*- CIPHER TEST DATA */

 /* AES-256 GCM test data */
@@ -164,54 +128,6 @@ static const unsigned char tdes_pt[] = {
 };
 #endif

-const ST_DEFINITION st_kat_cipher_tests[] = {
-    {
-        "AES-256-GCM",
-        OSSL_SELF_TEST_DESC_CIPHER_AES_GCM,
-        SELF_TEST_KAT_CIPHER,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        ITM_BUF(aes_256_gcm_pt),
-        ITM_BUF(aes_256_gcm_ct),
-        .u.cipher = {
-            CIPHER_MODE_ENCRYPT | CIPHER_MODE_DECRYPT,
-            ITM_BUF(aes_256_gcm_key),
-            ITM_BUF(aes_256_gcm_iv),
-            ITM_BUF(aes_256_gcm_aad),
-            ITM_BUF(aes_256_gcm_tag),
-        },
-    },
-    {
-        "AES-128-ECB",
-        OSSL_SELF_TEST_DESC_CIPHER_AES_ECB,
-        SELF_TEST_KAT_CIPHER,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        ITM_BUF(aes_128_ecb_pt),
-        ITM_BUF(aes_128_ecb_ct),
-        .u.cipher = {
-            CIPHER_MODE_DECRYPT,
-            ITM_BUF(aes_128_ecb_key),
-        },
-    },
-#ifndef OPENSSL_NO_DES
-    {
-        "DES-EDE3-ECB",
-        OSSL_SELF_TEST_DESC_CIPHER_TDES,
-        SELF_TEST_KAT_CIPHER,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        ITM_BUF(tdes_pt),
-        ITM_BUF(tdes_ct),
-        .u.cipher = {
-            CIPHER_MODE_DECRYPT,
-            ITM_BUF(tdes_key),
-        },
-    }
-#endif
-};
-int st_kat_cipher_tests_size = OSSL_NELEM(st_kat_cipher_tests);
-
 #ifndef OPENSSL_NO_LMS
 /*
  * Test vector from
@@ -342,30 +258,6 @@ static const ST_KAT_PARAM lms_key[] = {
     ST_KAT_PARAM_OCTET(OSSL_PKEY_PARAM_PUB_KEY, sha256_192_pub),
     ST_KAT_PARAM_END()
 };
-
-/*
- * FIPS 140-3 IG 10.3.A Note 5 mandates a CAST for LMS.
- *
- * It permits this to be omitted if HSS is also implemented and has
- * the relevant self tests.  Once HSS is implemented, this test can be
- * removed.  This IG permits the digest's CAST to be subsumed into this
- * test, however, because this will be removed, the underlying digest
- * test has been retained elsewhere lest it is accidentally omitted.
- */
-const ST_DEFINITION st_kat_lms_test = {
-    "LMS",
-    OSSL_SELF_TEST_DESC_SIGN_LMS,
-    SELF_TEST_KAT_SIGNATURE,
-    SELF_TEST_ONLOAD,
-    SELF_TEST_STATE_INIT,
-    ITM_BUF(sha256_192_msg),
-    ITM_BUF(sha256_192_sig),
-    .u.sig = {
-        "LMS",
-        SIGNATURE_MODE_VERIFY_ONLY,
-        lms_key,
-    }
-};
 #endif /* OPENSSL_NO_LMS */

 static const char hkdf_digest[] = "SHA256";
@@ -733,149 +625,6 @@ static const ST_KAT_PARAM tls13_kdf_client_early_secret_params[] = {
  * 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.
  */
-const ST_DEFINITION st_kat_kdf_tests[] = {
-    {
-        OSSL_KDF_NAME_TLS1_3_KDF,
-        OSSL_SELF_TEST_DESC_KDF_TLS13_EXTRACT,
-        SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .expected = ITM_BUF(tls13_kdf_early_secret),
-        .u.kdf = {
-            tls13_kdf_early_secret_params,
-        },
-    },
-    {
-        OSSL_KDF_NAME_TLS1_3_KDF,
-        OSSL_SELF_TEST_DESC_KDF_TLS13_EXPAND,
-        SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .expected = ITM_BUF(tls13_kdf_client_early_traffic_secret),
-        .u.kdf = {
-            tls13_kdf_client_early_secret_params,
-        },
-    },
-    {
-        OSSL_KDF_NAME_TLS1_PRF,
-        OSSL_SELF_TEST_DESC_KDF_TLS12_PRF,
-        SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .expected = ITM_BUF(tls12prf_expected),
-        .u.kdf = {
-            tls12prf_params,
-        },
-    },
-    {
-        OSSL_KDF_NAME_PBKDF2,
-        OSSL_SELF_TEST_DESC_KDF_PBKDF2,
-        SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .expected = ITM_BUF(pbkdf2_expected),
-        .u.kdf = {
-            pbkdf2_params,
-        },
-    },
-#ifndef OPENSSL_NO_KBKDF
-    {
-        OSSL_KDF_NAME_KBKDF,
-        OSSL_SELF_TEST_DESC_KDF_KBKDF,
-        SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .expected = ITM_BUF(kbkdf_expected),
-        .u.kdf = {
-            kbkdf_params,
-        },
-    },
-    {
-        OSSL_KDF_NAME_KBKDF,
-        OSSL_SELF_TEST_DESC_KDF_KBKDF_KMAC,
-        SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .expected = ITM_BUF(kbkdf_kmac_expected),
-        .u.kdf = {
-            kbkdf_kmac_params,
-        },
-    },
-#endif
-    {
-        OSSL_KDF_NAME_HKDF,
-        OSSL_SELF_TEST_DESC_KDF_HKDF,
-        SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .expected = ITM_BUF(hkdf_expected),
-        .u.kdf = {
-            hkdf_params,
-        },
-    },
-#ifndef OPENSSL_NO_SNMPKDF
-    {
-        OSSL_KDF_NAME_SNMPKDF,
-        OSSL_SELF_TEST_DESC_KDF_SNMPKDF,
-        SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .expected = ITM_BUF(snmpkdf_expected),
-        .u.kdf = {
-            snmpkdf_params,
-        },
-    },
-#endif
-#ifndef OPENSSL_NO_SRTPKDF
-    {
-        OSSL_SELF_TEST_DESC_KDF_SRTPKDF,
-        OSSL_KDF_NAME_SRTPKDF,
-        0,
-        srtpkdf_params,
-        ITM(srtpkdf_expected)
-    },
-#endif
-#ifndef OPENSSL_NO_SSKDF
-    {
-        OSSL_KDF_NAME_SSKDF,
-        OSSL_SELF_TEST_DESC_KDF_SSKDF,
-        SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .expected = ITM_BUF(sskdf_expected),
-        .u.kdf = {
-            sskdf_params,
-        },
-    },
-#endif
-#ifndef OPENSSL_NO_X963KDF
-    {
-        OSSL_KDF_NAME_X963KDF,
-        OSSL_SELF_TEST_DESC_KDF_X963KDF,
-        SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .expected = ITM_BUF(x963kdf_expected),
-        .u.kdf = {
-            x963kdf_params,
-        },
-    },
-#endif
-#ifndef OPENSSL_NO_X942KDF
-    {
-        OSSL_KDF_NAME_X942KDF_ASN1,
-        OSSL_SELF_TEST_DESC_KDF_X942KDF,
-        SELF_TEST_KAT_KDF,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .expected = ITM_BUF(x942kdf_expected),
-        .u.kdf = {
-            x942kdf_params,
-        },
-    },
-#endif
-};
-int st_kat_kdf_tests_size = OSSL_NELEM(st_kat_kdf_tests);

 /*-
  * DRBG test vectors are a small subset of
@@ -1066,67 +815,6 @@ static const unsigned char drbg_hmac_sha2_pr_expected[] = {
     0x8e, 0x30, 0x05, 0x0e, 0x04, 0x97, 0xfb, 0x0a
 };

-const ST_DEFINITION st_kat_drbg_tests[] = {
-    {
-        "HASH-DRBG",
-        OSSL_SELF_TEST_DESC_DRBG_HASH,
-        SELF_TEST_DRBG,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .expected = ITM_BUF(drbg_hash_sha256_pr_expected),
-        .u.drbg = {
-            "digest",
-            "SHA256",
-            ITM_BUF(drbg_hash_sha256_pr_entropyin),
-            ITM_BUF(drbg_hash_sha256_pr_nonce),
-            ITM_BUF(drbg_hash_sha256_pr_persstr),
-            ITM_BUF(drbg_hash_sha256_pr_entropyinpr0),
-            ITM_BUF(drbg_hash_sha256_pr_entropyinpr1),
-            ITM_BUF(drbg_hash_sha256_pr_addin0),
-            ITM_BUF(drbg_hash_sha256_pr_addin1),
-        },
-    },
-    {
-        "CTR-DRBG",
-        OSSL_SELF_TEST_DESC_DRBG_CTR,
-        SELF_TEST_DRBG,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .expected = ITM_BUF(drbg_ctr_aes128_pr_df_expected),
-        .u.drbg = {
-            "cipher",
-            "AES-128-CTR",
-            ITM_BUF(drbg_ctr_aes128_pr_df_entropyin),
-            ITM_BUF(drbg_ctr_aes128_pr_df_nonce),
-            ITM_BUF(drbg_ctr_aes128_pr_df_persstr),
-            ITM_BUF(drbg_ctr_aes128_pr_df_entropyinpr0),
-            ITM_BUF(drbg_ctr_aes128_pr_df_entropyinpr1),
-            ITM_BUF(drbg_ctr_aes128_pr_df_addin0),
-            ITM_BUF(drbg_ctr_aes128_pr_df_addin1),
-        },
-    },
-    {
-        "HMAC-DRBG",
-        OSSL_SELF_TEST_DESC_DRBG_HMAC,
-        SELF_TEST_DRBG,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .expected = ITM_BUF(drbg_hmac_sha2_pr_expected),
-        .u.drbg = {
-            "digest",
-            "SHA256",
-            ITM_BUF(drbg_hmac_sha2_pr_entropyin),
-            ITM_BUF(drbg_hmac_sha2_pr_nonce),
-            ITM_BUF(drbg_hmac_sha2_pr_persstr),
-            ITM_BUF(drbg_hmac_sha2_pr_entropyinpr0),
-            ITM_BUF(drbg_hmac_sha2_pr_entropyinpr1),
-            ITM_BUF(drbg_hmac_sha2_pr_addin0),
-            ITM_BUF(drbg_hmac_sha2_pr_addin1),
-        },
-    }
-};
-int st_kat_drbg_tests_size = OSSL_NELEM(st_kat_drbg_tests);
-
 /* KEY EXCHANGE TEST DATA */

 #ifndef OPENSSL_NO_DH
@@ -1314,39 +1002,6 @@ static const unsigned char ecdh_secret_expected[] = {
 };
 #endif /* OPENSSL_NO_EC */

-#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_EC)
-const ST_DEFINITION st_kat_kas_tests[] = {
-#ifndef OPENSSL_NO_DH
-    { "DH",
-        OSSL_SELF_TEST_DESC_KA_DH,
-        SELF_TEST_KAT_KAS,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .expected = ITM_BUF(dh_secret_expected),
-        .u.kas = {
-            dh_group,
-            dh_host_key,
-            dh_peer_key } },
-#endif /* OPENSSL_NO_DH */
-#ifndef OPENSSL_NO_EC
-    {
-        "EC",
-        OSSL_SELF_TEST_DESC_KA_ECDH,
-        SELF_TEST_KAT_KAS,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .expected = ITM_BUF(ecdh_secret_expected),
-        .u.kas = {
-            ecdh_group,
-            ecdh_host_key,
-            ecdh_peer_key,
-        },
-    },
-#endif /* OPENSSL_NO_EC */
-};
-int st_kat_kas_tests_size = OSSL_NELEM(st_kat_kas_tests);
-#endif /* !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_EC) */
-
 /* RSA key data */
 static const unsigned char rsa_n[] = {
     0xDB, 0x10, 0x1A, 0xC2, 0xA3, 0xF1, 0xDC, 0xFF,
@@ -3238,197 +2893,6 @@ static const unsigned char sig_kat_persstr[] = {
     0xac, 0x54, 0x4f, 0xce, 0x57, 0xf1, 0x5e, 0x11
 };

-const ST_DEFINITION st_kat_sign_tests[] = {
-    {
-        "RSA-SHA256",
-        OSSL_SELF_TEST_DESC_SIGN_RSA,
-        SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        ITM_BUF_STR(rsa_sig_msg),
-        ITM_BUF(rsa_expected_sig),
-        .u.sig = {
-            "RSA",
-            0,
-            rsa_crt_key,
-            ITM_BUF(sig_kat_entropyin),
-            ITM_BUF(sig_kat_nonce),
-            ITM_BUF(sig_kat_persstr),
-        },
-    },
-#ifndef OPENSSL_NO_EC
-    {
-        "ECDSA-SHA256",
-        OSSL_SELF_TEST_DESC_SIGN_ECDSA,
-        SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        ITM_BUF_STR(rsa_sig_msg),
-        ITM_BUF(ecdsa_prime_expected_sig),
-        .u.sig = {
-            "EC",
-            0,
-            ecdsa_prime_key,
-            ITM_BUF(sig_kat_entropyin),
-            ITM_BUF(sig_kat_nonce),
-            ITM_BUF(sig_kat_persstr),
-        },
-    },
-#ifndef OPENSSL_NO_HMAC_DRBG_KDF
-    {
-        "ECDSA-SHA256",
-        OSSL_SELF_TEST_DESC_SIGN_DetECDSA,
-        SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        ITM_BUF_STR(rsa_sig_msg),
-        ITM_BUF(ecdsa_prime_expected_detsig),
-        .u.sig = {
-            "EC",
-            0,
-            ecdsa_prime_key,
-            .init = ecdsa_sig_params,
-        },
-    },
-#endif
-#ifndef OPENSSL_NO_EC2M
-    {
-        "ECDSA-SHA256",
-        OSSL_SELF_TEST_DESC_SIGN_ECDSA,
-        SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        ITM_BUF_STR(rsa_sig_msg),
-        ITM_BUF(ecdsa_bin_expected_sig),
-        .u.sig = {
-            "EC",
-            0,
-            ecdsa_bin_key,
-            ITM_BUF(sig_kat_entropyin),
-            ITM_BUF(sig_kat_nonce),
-            ITM_BUF(sig_kat_persstr),
-        },
-    },
-#endif
-#ifndef OPENSSL_NO_ECX
-    {
-        "ED448",
-        OSSL_SELF_TEST_DESC_SIGN_EDDSA,
-        SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        ITM_BUF(ecx_sig_msg),
-        ITM_BUF(ed448_expected_sig),
-        .u.sig = {
-            "ED448",
-            0,
-            ed448_key,
-        },
-    },
-    {
-        "ED25519",
-        OSSL_SELF_TEST_DESC_SIGN_EDDSA,
-        SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        ITM_BUF(ecx_sig_msg),
-        ITM_BUF(ed25519_expected_sig),
-        .u.sig = {
-            "ED25519",
-            0,
-            ed25519_key,
-        },
-    },
-#endif /* OPENSSL_NO_ECX */
-#endif /* OPENSSL_NO_EC */
-#ifndef OPENSSL_NO_DSA
-    {
-        "DSA-SHA256",
-        OSSL_SELF_TEST_DESC_SIGN_DSA,
-        SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        ITM_BUF_STR(rsa_sig_msg),
-        ITM_BUF(dsa_expected_sig),
-        .u.sig = {
-            "DSA",
-            SIGNATURE_MODE_VERIFY_ONLY,
-            dsa_key,
-            ITM_BUF(sig_kat_entropyin),
-            ITM_BUF(sig_kat_nonce),
-            ITM_BUF(sig_kat_persstr),
-        },
-    },
-#endif /* OPENSSL_NO_DSA */
-
-#ifndef OPENSSL_NO_ML_DSA
-    {
-        "ML-DSA-65",
-        OSSL_SELF_TEST_DESC_SIGN_ML_DSA,
-        SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        ITM_BUF(ml_dsa_65_msg),
-        ITM_BUF(ml_dsa_65_sig),
-        .u.sig = {
-            "ML-DSA-65",
-            0,
-            ml_dsa_key,
-            .init = ml_dsa_sig_init,
-            .verify = ml_dsa_sig_init,
-        },
-    },
-#endif /* OPENSSL_NO_ML_DSA */
-#ifndef OPENSSL_NO_SLH_DSA
-    /*
-     * FIPS 140-3 IG 10.3.A.16 Note 29 says:
-     *
-     *  It is recommended (but not required) that if the module implements
-     *   both "s" and "f" algorithms, the module self-test at least one of
-     *   each "s" and "f" algorithm.
-     *
-     * Because the "s" version is so slow, we only test the "f" versions
-     * here.
-     */
-    {
-        "SLH-DSA-SHA2-128f",
-        OSSL_SELF_TEST_DESC_SIGN_SLH_DSA,
-        SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_DEFERRED,
-        SELF_TEST_STATE_INIT,
-        ITM_BUF(slh_dsa_sha2_sig_msg),
-        ITM_BUF(slh_dsa_sha2_128f_sig_digest),
-        .u.sig = {
-            "SLH-DSA-SHA2-128f",
-            SIGNATURE_MODE_SIG_DIGESTED,
-            slh_dsa_sha2_128f_key_params,
-            .init = slh_dsa_sig_params,
-            .verify = slh_dsa_sig_params,
-        },
-    },
-    {
-        "SLH-DSA-SHAKE-128f",
-        OSSL_SELF_TEST_DESC_SIGN_SLH_DSA,
-        SELF_TEST_KAT_SIGNATURE,
-        SELF_TEST_DEFERRED,
-        SELF_TEST_STATE_INIT,
-        ITM_BUF(slh_dsa_shake_sig_msg),
-        ITM_BUF(slh_dsa_shake_128f_sig_digest),
-        .u.sig = {
-            "SLH-DSA-SHAKE-128f",
-            SIGNATURE_MODE_SIG_DIGESTED,
-            slh_dsa_shake_128f_key_params,
-            .init = slh_dsa_sig_params,
-            .verify = slh_dsa_sig_params,
-        },
-    },
-#endif /* OPENSSL_NO_SLH_DSA */
-#ifndef OPENSSL_NO_LMS
-    st_kat_lms_test,
-#endif /* OPENSSL_NO_LMS */
-};
-int st_kat_sign_tests_size = OSSL_NELEM(st_kat_sign_tests);
-
 #if !defined(OPENSSL_NO_ML_DSA)
 static const ST_KAT_PARAM ml_dsa_keygen_params[] = {
     ST_KAT_PARAM_OCTET(OSSL_PKEY_PARAM_ML_DSA_SEED, sig_kat_entropyin),
@@ -3795,45 +3259,538 @@ static const ST_KAT_PARAM ml_kem_key[] = {
     ST_KAT_PARAM_OCTET(OSSL_PKEY_PARAM_PRIV_KEY, ml_kem_512_private_key),
     ST_KAT_PARAM_END()
 };
-
-const ST_DEFINITION st_kat_kem_tests[] = {
-    { "ML-KEM-512",
-        OSSL_SELF_TEST_DESC_KEM,
-        SELF_TEST_KAT_KEM,
-        SELF_TEST_ONLOAD,
-        SELF_TEST_STATE_INIT,
-        .u.kem = {
-            ml_kem_key,
-            ITM_BUF(ml_kem_512_cipher_text),
-            ITM_BUF(ml_kem_512_entropy),
-            ITM_BUF(ml_kem_512_secret),
-            ITM_BUF(ml_kem_512_reject_secret) } },
-};
-int st_kat_kem_tests_size = OSSL_NELEM(st_kat_kem_tests);
 #endif /* OPENSSL_NO_ML_KEM */

-#if !defined(OPENSSL_NO_ML_KEM) || !defined(OPENSSL_NO_ML_DSA) || !defined(OPENSSL_NO_SLH_DSA)
-const ST_DEFINITION st_kat_asym_keygen_tests[] = {
-#if !defined(OPENSSL_NO_ML_KEM)
-    /*
-     * FIPS 140-3 IG 10.3.A resolution 14 mandates a CAST for ML-KEM
-     * key generation.
-     */
+ST_DEFINITION st_all_tests[ST_ID_MAX] = {
+    {
+        "SHA1",
+        OSSL_SELF_TEST_DESC_MD_SHA1,
+        SELF_TEST_KAT_DIGEST,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF_STR(sha1_pt),
+        ITM_BUF(sha1_digest),
+    },
+    {
+        "SHA512",
+        OSSL_SELF_TEST_DESC_MD_SHA2,
+        SELF_TEST_KAT_DIGEST,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF_STR(sha512_pt),
+        ITM_BUF(sha512_digest),
+    },
+    {
+        "SHA3-256",
+        OSSL_SELF_TEST_DESC_MD_SHA3,
+        SELF_TEST_KAT_DIGEST,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF(sha3_256_pt),
+        ITM_BUF(sha3_256_digest),
+    },
+    { "AES-256-GCM",
+        OSSL_SELF_TEST_DESC_CIPHER_AES_GCM,
+        SELF_TEST_KAT_CIPHER,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF(aes_256_gcm_pt),
+        ITM_BUF(aes_256_gcm_ct),
+        .u.cipher = {
+            CIPHER_MODE_ENCRYPT | CIPHER_MODE_DECRYPT,
+            ITM_BUF(aes_256_gcm_key),
+            ITM_BUF(aes_256_gcm_iv),
+            ITM_BUF(aes_256_gcm_aad),
+            ITM_BUF(aes_256_gcm_tag) } },
+    {
+        "AES-128-ECB",
+        OSSL_SELF_TEST_DESC_CIPHER_AES_ECB,
+        SELF_TEST_KAT_CIPHER,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF(aes_128_ecb_pt),
+        ITM_BUF(aes_128_ecb_ct),
+        .u.cipher = {
+            CIPHER_MODE_DECRYPT,
+            ITM_BUF(aes_128_ecb_key),
+        },
+    },
+#ifndef OPENSSL_NO_DES
+    {
+        "DES-EDE3-ECB",
+        OSSL_SELF_TEST_DESC_CIPHER_TDES,
+        SELF_TEST_KAT_CIPHER,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF(tdes_pt),
+        ITM_BUF(tdes_ct),
+        .u.cipher = {
+            CIPHER_MODE_DECRYPT,
+            ITM_BUF(tdes_key),
+        },
+    },
+#endif
+    {
+        "RSA-SHA256",
+        OSSL_SELF_TEST_DESC_SIGN_RSA,
+        SELF_TEST_KAT_SIGNATURE,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF_STR(rsa_sig_msg),
+        ITM_BUF(rsa_expected_sig),
+        .u.sig = {
+            "RSA",
+            0,
+            rsa_crt_key,
+            ITM_BUF(sig_kat_entropyin),
+            ITM_BUF(sig_kat_nonce),
+            ITM_BUF(sig_kat_persstr),
+        },
+    },
+#ifndef OPENSSL_NO_EC
+    {
+        "ECDSA-SHA256",
+        OSSL_SELF_TEST_DESC_SIGN_ECDSA,
+        SELF_TEST_KAT_SIGNATURE,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF_STR(rsa_sig_msg),
+        ITM_BUF(ecdsa_prime_expected_sig),
+        .u.sig = {
+            "EC",
+            0,
+            ecdsa_prime_key,
+            ITM_BUF(sig_kat_entropyin),
+            ITM_BUF(sig_kat_nonce),
+            ITM_BUF(sig_kat_persstr),
+        },
+    },
+#ifndef OPENSSL_NO_HMAC_DRBG_KDF
+    {
+        "ECDSA-SHA256",
+        OSSL_SELF_TEST_DESC_SIGN_DetECDSA,
+        SELF_TEST_KAT_SIGNATURE,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF_STR(rsa_sig_msg),
+        ITM_BUF(ecdsa_prime_expected_detsig),
+        .u.sig = {
+            "EC",
+            0,
+            ecdsa_prime_key,
+            .init = ecdsa_sig_params,
+        },
+    },
+#endif
+#ifndef OPENSSL_NO_EC2M
+    {
+        "ECDSA-SHA256",
+        OSSL_SELF_TEST_DESC_SIGN_ECDSA,
+        SELF_TEST_KAT_SIGNATURE,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF_STR(rsa_sig_msg),
+        ITM_BUF(ecdsa_bin_expected_sig),
+        .u.sig = {
+            "EC",
+            0,
+            ecdsa_bin_key,
+            ITM_BUF(sig_kat_entropyin),
+            ITM_BUF(sig_kat_nonce),
+            ITM_BUF(sig_kat_persstr),
+        },
+    },
+#endif
+#ifndef OPENSSL_NO_ECX
+    {
+        "ED448",
+        OSSL_SELF_TEST_DESC_SIGN_EDDSA,
+        SELF_TEST_KAT_SIGNATURE,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF(ecx_sig_msg),
+        ITM_BUF(ed448_expected_sig),
+        .u.sig = {
+            "ED448",
+            0,
+            ed448_key,
+        },
+    },
+    {
+        "ED25519",
+        OSSL_SELF_TEST_DESC_SIGN_EDDSA,
+        SELF_TEST_KAT_SIGNATURE,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF(ecx_sig_msg),
+        ITM_BUF(ed25519_expected_sig),
+        .u.sig = {
+            "ED25519",
+            0,
+            ed25519_key,
+        },
+    },
+#endif /* OPENSSL_NO_ECX */
+#endif /* OPENSSL_NO_EC */
+#ifndef OPENSSL_NO_DSA
+    {
+        "DSA-SHA256",
+        OSSL_SELF_TEST_DESC_SIGN_DSA,
+        SELF_TEST_KAT_SIGNATURE,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF_STR(rsa_sig_msg),
+        ITM_BUF(dsa_expected_sig),
+        .u.sig = {
+            "DSA",
+            SIGNATURE_MODE_VERIFY_ONLY,
+            dsa_key,
+            ITM_BUF(sig_kat_entropyin),
+            ITM_BUF(sig_kat_nonce),
+            ITM_BUF(sig_kat_persstr),
+        },
+    },
+#endif /* OPENSSL_NO_DSA */
+#ifndef OPENSSL_NO_ML_DSA
+    {
+        "ML-DSA-65",
+        OSSL_SELF_TEST_DESC_SIGN_ML_DSA,
+        SELF_TEST_KAT_SIGNATURE,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF(ml_dsa_65_msg),
+        ITM_BUF(ml_dsa_65_sig),
+        .u.sig = {
+            "ML-DSA-65",
+            0,
+            ml_dsa_key,
+            .init = ml_dsa_sig_init,
+            .verify = ml_dsa_sig_init,
+        },
+    },
+#endif /* OPENSSL_NO_ML_DSA */
+#ifndef OPENSSL_NO_SLH_DSA
+    /*
+     * FIPS 140-3 IG 10.3.A.16 Note 29 says:
+     *
+     *  It is recommended (but not required) that if the module implements
+     *   both "s" and "f" algorithms, the module self-test at least one of
+     *   each "s" and "f" algorithm.
+     *
+     * Because the "s" version is so slow, we only test the "f" versions
+     * here.
+     */
+    {
+        "SLH-DSA-SHA2-128f",
+        OSSL_SELF_TEST_DESC_SIGN_SLH_DSA,
+        SELF_TEST_KAT_SIGNATURE,
+        SELF_TEST_DEFERRED,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF(slh_dsa_sha2_sig_msg),
+        ITM_BUF(slh_dsa_sha2_128f_sig_digest),
+        .u.sig = {
+            "SLH-DSA-SHA2-128f",
+            SIGNATURE_MODE_SIG_DIGESTED,
+            slh_dsa_sha2_128f_key_params,
+            .init = slh_dsa_sig_params,
+            .verify = slh_dsa_sig_params,
+        },
+    },
+    {
+        "SLH-DSA-SHAKE-128f",
+        OSSL_SELF_TEST_DESC_SIGN_SLH_DSA,
+        SELF_TEST_KAT_SIGNATURE,
+        SELF_TEST_DEFERRED,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF(slh_dsa_shake_sig_msg),
+        ITM_BUF(slh_dsa_shake_128f_sig_digest),
+        .u.sig = {
+            "SLH-DSA-SHAKE-128f",
+            SIGNATURE_MODE_SIG_DIGESTED,
+            slh_dsa_shake_128f_key_params,
+            .init = slh_dsa_sig_params,
+            .verify = slh_dsa_sig_params,
+        },
+    },
+#endif /* OPENSSL_NO_SLH_DSA */
+/*
+ * FIPS 140-3 IG 10.3.A Note 5 mandates a CAST for LMS.
+ *
+ * It permits this to be omitted if HSS is also implemented and has
+ * the relevant self tests.  Once HSS is implemented, this test can be
+ * removed.  This IG permits the digest's CAST to be subsumed into this
+ * test, however, because this will be removed, the underlying digest
+ * test has been retained elsewhere lest it is accidentally omitted.
+ */
+#ifndef OPENSSL_NO_LMS
+    {
+        "LMS",
+        OSSL_SELF_TEST_DESC_SIGN_LMS,
+        SELF_TEST_KAT_SIGNATURE,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        ITM_BUF(sha256_192_msg),
+        ITM_BUF(sha256_192_sig),
+        .u.sig = {
+            "LMS",
+            SIGNATURE_MODE_VERIFY_ONLY,
+            lms_key,
+        },
+    },
+#endif /* OPENSSL_NO_LMS */
+    {
+        OSSL_KDF_NAME_TLS1_3_KDF,
+        OSSL_SELF_TEST_DESC_KDF_TLS13_EXTRACT,
+        SELF_TEST_KAT_KDF,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(tls13_kdf_early_secret),
+        .u.kdf = {
+            tls13_kdf_early_secret_params,
+        },
+    },
+    {
+        OSSL_KDF_NAME_TLS1_3_KDF,
+        OSSL_SELF_TEST_DESC_KDF_TLS13_EXPAND,
+        SELF_TEST_KAT_KDF,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(tls13_kdf_client_early_traffic_secret),
+        .u.kdf = {
+            tls13_kdf_client_early_secret_params,
+        },
+    },
+    {
+        OSSL_KDF_NAME_TLS1_PRF,
+        OSSL_SELF_TEST_DESC_KDF_TLS12_PRF,
+        SELF_TEST_KAT_KDF,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(tls12prf_expected),
+        .u.kdf = {
+            tls12prf_params,
+        },
+    },
+    {
+        OSSL_KDF_NAME_PBKDF2,
+        OSSL_SELF_TEST_DESC_KDF_PBKDF2,
+        SELF_TEST_KAT_KDF,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(pbkdf2_expected),
+        .u.kdf = {
+            pbkdf2_params,
+        },
+    },
+#ifndef OPENSSL_NO_KBKDF
+    {
+        OSSL_KDF_NAME_KBKDF,
+        OSSL_SELF_TEST_DESC_KDF_KBKDF,
+        SELF_TEST_KAT_KDF,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(kbkdf_expected),
+        .u.kdf = {
+            kbkdf_params,
+        },
+    },
+    {
+        OSSL_KDF_NAME_KBKDF,
+        OSSL_SELF_TEST_DESC_KDF_KBKDF_KMAC,
+        SELF_TEST_KAT_KDF,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(kbkdf_kmac_expected),
+        .u.kdf = {
+            kbkdf_kmac_params,
+        },
+    },
+#endif
+    {
+        OSSL_KDF_NAME_HKDF,
+        OSSL_SELF_TEST_DESC_KDF_HKDF,
+        SELF_TEST_KAT_KDF,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(hkdf_expected),
+        .u.kdf = {
+            hkdf_params,
+        },
+    },
+#ifndef OPENSSL_NO_SNMPKDF
+    {
+        OSSL_KDF_NAME_SNMPKDF,
+        OSSL_SELF_TEST_DESC_KDF_SNMPKDF,
+        SELF_TEST_KAT_KDF,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(snmpkdf_expected),
+        .u.kdf = {
+            snmpkdf_params,
+        },
+    },
+#endif
+#ifndef OPENSSL_NO_SRTPKDF
+    {
+        OSSL_KDF_NAME_SRTPKDF,
+        OSSL_SELF_TEST_DESC_KDF_SRTPKDF,
+        SELF_TEST_KAT_KDF,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(srtpkdf_expected),
+        .u.kdf = {
+            srtpkdf_params,
+        },
+    },
+#endif
+#ifndef OPENSSL_NO_SSKDF
+    {
+        OSSL_KDF_NAME_SSKDF,
+        OSSL_SELF_TEST_DESC_KDF_SSKDF,
+        SELF_TEST_KAT_KDF,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(sskdf_expected),
+        .u.kdf = {
+            sskdf_params,
+        },
+    },
+#endif
+#ifndef OPENSSL_NO_X963KDF
+    {
+        OSSL_KDF_NAME_X963KDF,
+        OSSL_SELF_TEST_DESC_KDF_X963KDF,
+        SELF_TEST_KAT_KDF,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(x963kdf_expected),
+        .u.kdf = {
+            x963kdf_params,
+        },
+    },
+#endif
+#ifndef OPENSSL_NO_X942KDF
+    {
+        OSSL_KDF_NAME_X942KDF_ASN1,
+        OSSL_SELF_TEST_DESC_KDF_X942KDF,
+        SELF_TEST_KAT_KDF,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(x942kdf_expected),
+        .u.kdf = {
+            x942kdf_params,
+        },
+    },
+#endif
+    {
+        "HASH-DRBG",
+        OSSL_SELF_TEST_DESC_DRBG_HASH,
+        SELF_TEST_DRBG,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(drbg_hash_sha256_pr_expected),
+        .u.drbg = {
+            "digest",
+            "SHA256",
+            ITM_BUF(drbg_hash_sha256_pr_entropyin),
+            ITM_BUF(drbg_hash_sha256_pr_nonce),
+            ITM_BUF(drbg_hash_sha256_pr_persstr),
+            ITM_BUF(drbg_hash_sha256_pr_entropyinpr0),
+            ITM_BUF(drbg_hash_sha256_pr_entropyinpr1),
+            ITM_BUF(drbg_hash_sha256_pr_addin0),
+            ITM_BUF(drbg_hash_sha256_pr_addin1),
+        },
+    },
+    {
+        "CTR-DRBG",
+        OSSL_SELF_TEST_DESC_DRBG_CTR,
+        SELF_TEST_DRBG,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(drbg_ctr_aes128_pr_df_expected),
+        .u.drbg = {
+            "cipher",
+            "AES-128-CTR",
+            ITM_BUF(drbg_ctr_aes128_pr_df_entropyin),
+            ITM_BUF(drbg_ctr_aes128_pr_df_nonce),
+            ITM_BUF(drbg_ctr_aes128_pr_df_persstr),
+            ITM_BUF(drbg_ctr_aes128_pr_df_entropyinpr0),
+            ITM_BUF(drbg_ctr_aes128_pr_df_entropyinpr1),
+            ITM_BUF(drbg_ctr_aes128_pr_df_addin0),
+            ITM_BUF(drbg_ctr_aes128_pr_df_addin1),
+        },
+    },
+    {
+        "HMAC-DRBG",
+        OSSL_SELF_TEST_DESC_DRBG_HMAC,
+        SELF_TEST_DRBG,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(drbg_hmac_sha2_pr_expected),
+        .u.drbg = {
+            "digest",
+            "SHA256",
+            ITM_BUF(drbg_hmac_sha2_pr_entropyin),
+            ITM_BUF(drbg_hmac_sha2_pr_nonce),
+            ITM_BUF(drbg_hmac_sha2_pr_persstr),
+            ITM_BUF(drbg_hmac_sha2_pr_entropyinpr0),
+            ITM_BUF(drbg_hmac_sha2_pr_entropyinpr1),
+            ITM_BUF(drbg_hmac_sha2_pr_addin0),
+            ITM_BUF(drbg_hmac_sha2_pr_addin1),
+        },
+    },
+#ifndef OPENSSL_NO_DH
+    {
+        "DH",
+        OSSL_SELF_TEST_DESC_KA_DH,
+        SELF_TEST_KAT_KAS,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(dh_secret_expected),
+        .u.kas = {
+            dh_group,
+            dh_host_key,
+            dh_peer_key,
+        },
+    },
+#endif
+#ifndef OPENSSL_NO_EC
+    {
+        "EC",
+        OSSL_SELF_TEST_DESC_KA_ECDH,
+        SELF_TEST_KAT_KAS,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .expected = ITM_BUF(ecdh_secret_expected),
+        .u.kas = {
+            ecdh_group,
+            ecdh_host_key,
+            ecdh_peer_key,
+        },
+    },
+#endif
+#ifndef OPENSSL_NO_ML_KEM
+    /*
+     * FIPS 140-3 IG 10.3.A resolution 14 mandates a CAST for ML-KEM
+     * key generation.
+     */
     {
         "ML-KEM-512",
         OSSL_SELF_TEST_DESC_KEYGEN_ML_KEM,
-        SELF_TEST_KAT_ASYM_CIPHER,
+        SELF_TEST_KAT_ASYM_KEYGEN,
         SELF_TEST_ONLOAD,
         SELF_TEST_STATE_INIT,
         .u.akgen = {
             ml_kem_keygen_params,
-            ml_kem_key } },
+            ml_kem_key,
+        },
+    },
 #endif
-#if !defined(OPENSSL_NO_ML_DSA)
+#ifndef OPENSSL_NO_ML_DSA
     {
         "ML-DSA-65",
         OSSL_SELF_TEST_DESC_KEYGEN_ML_DSA,
-        SELF_TEST_KAT_ASYM_CIPHER,
+        SELF_TEST_KAT_ASYM_KEYGEN,
         SELF_TEST_ONLOAD,
         SELF_TEST_STATE_INIT,
         .u.akgen = {
@@ -3842,11 +3799,11 @@ const ST_DEFINITION st_kat_asym_keygen_tests[] = {
         },
     },
 #endif
-#if !defined(OPENSSL_NO_SLH_DSA)
+#ifndef OPENSSL_NO_SLH_DSA
     {
         "SLH-DSA-SHA2-128f",
         OSSL_SELF_TEST_DESC_KEYGEN_SLH_DSA,
-        SELF_TEST_KAT_ASYM_CIPHER,
+        SELF_TEST_KAT_ASYM_KEYGEN,
         SELF_TEST_DEFERRED,
         SELF_TEST_STATE_INIT,
         .u.akgen = {
@@ -3855,12 +3812,24 @@ const ST_DEFINITION st_kat_asym_keygen_tests[] = {
         },
     },
 #endif
-};
-int st_kat_asym_keygen_tests_size = OSSL_NELEM(st_kat_asym_keygen_tests);
-#endif /* !OPENSSL_NO_ML_DSA || !OPENSSL_NO_SLH_DSA */
-
-const ST_DEFINITION st_kat_asym_cipher_tests[] = {
-    { "RSA",
+#ifndef OPENSSL_NO_ML_KEM
+    {
+        "ML-KEM-512",
+        OSSL_SELF_TEST_DESC_KEM,
+        SELF_TEST_KAT_KEM,
+        SELF_TEST_ONLOAD,
+        SELF_TEST_STATE_INIT,
+        .u.kem = {
+            ml_kem_key,
+            ITM_BUF(ml_kem_512_cipher_text),
+            ITM_BUF(ml_kem_512_entropy),
+            ITM_BUF(ml_kem_512_secret),
+            ITM_BUF(ml_kem_512_reject_secret),
+        },
+    },
+#endif
+    {
+        "RSA",
         OSSL_SELF_TEST_DESC_ASYM_RSA_ENC,
         SELF_TEST_KAT_ASYM_CIPHER,
         SELF_TEST_ONLOAD,
@@ -3871,15 +3840,16 @@ const ST_DEFINITION st_kat_asym_cipher_tests[] = {
             1,
             rsa_pub_key,
             rsa_enc_params,
-        } },
+        },
+    },
     {
         "RSA",
         OSSL_SELF_TEST_DESC_ASYM_RSA_DEC,
         SELF_TEST_KAT_ASYM_CIPHER,
         SELF_TEST_ONLOAD,
         SELF_TEST_STATE_INIT,
-        ITM(rsa_asym_expected_encrypt),
-        ITM(rsa_asym_plaintext_encrypt),
+        ITM_BUF(rsa_asym_expected_encrypt),
+        ITM_BUF(rsa_asym_plaintext_encrypt),
         .u.ac = {
             0,
             rsa_priv_key,
@@ -3892,8 +3862,8 @@ const ST_DEFINITION st_kat_asym_cipher_tests[] = {
         SELF_TEST_KAT_ASYM_CIPHER,
         SELF_TEST_ONLOAD,
         SELF_TEST_STATE_INIT,
-        ITM(rsa_asym_expected_encrypt),
-        ITM(rsa_asym_plaintext_encrypt),
+        ITM_BUF(rsa_asym_expected_encrypt),
+        ITM_BUF(rsa_asym_plaintext_encrypt),
         .u.ac = {
             0,
             rsa_crt_key,
@@ -3901,4 +3871,3 @@ const ST_DEFINITION st_kat_asym_cipher_tests[] = {
         },
     },
 };
-int st_kat_asym_cipher_tests_size = OSSL_NELEM(st_kat_asym_cipher_tests);
diff --git a/providers/fips/self_test_data.h b/providers/fips/self_test_data.h
deleted file mode 100644
index bfa3d54ae5..0000000000
--- a/providers/fips/self_test_data.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved.
- *
- * Licensed under the Apache License 2.0 (the "License").  You may not use
- * this file except in compliance with the License.  You can obtain a copy
- * in the file LICENSE in the source distribution or at
- * https://www.openssl.org/source/license.html
- */
-
-/*
- * This file contains self test data required by FIPS 140-3 IG
- * 10.3.A Cryptographic Algorithm Self test Requirements
- *
- * Note that in the 'General CAST requirements': Note33 Allows individual
- * self tests for low level algorithms (such as digests) to be omitted, if
- * they are tested as part of a higher level algorithm (such as HMAC).
- */
-
-extern const ST_DEFINITION st_kat_digest_tests[];
-extern int st_kat_digest_tests_size;
-extern const ST_DEFINITION st_kat_cipher_tests[];
-extern int st_kat_cipher_tests_size;
-#ifndef OPENSSL_NO_LMS
-extern const ST_DEFINITION st_kat_lms_test;
-#endif
-extern const ST_DEFINITION st_kat_kdf_tests[];
-extern int st_kat_kdf_tests_size;
-extern const ST_DEFINITION st_kat_drbg_tests[];
-extern int st_kat_drbg_tests_size;
-#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_EC)
-extern const ST_DEFINITION st_kat_kas_tests[];
-extern int st_kat_kas_tests_size;
-#endif
-extern const ST_DEFINITION st_kat_sign_tests[];
-extern int st_kat_sign_tests_size;
-#ifndef OPENSSL_NO_ML_KEM
-extern const ST_DEFINITION st_kat_kem_tests[];
-extern int st_kat_kem_tests_size;
-#endif
-#if !defined(OPENSSL_NO_ML_KEM) || !defined(OPENSSL_NO_ML_DSA) || !defined(OPENSSL_NO_SLH_DSA)
-extern const ST_DEFINITION st_kat_asym_keygen_tests[];
-extern int st_kat_asym_keygen_tests_size;
-#endif
-extern const ST_DEFINITION st_kat_asym_cipher_tests[];
-extern int st_kat_asym_cipher_tests_size;
diff --git a/providers/fips/self_test_kats.c b/providers/fips/self_test_kats.c
index f4cda15d8d..1750c99609 100644
--- a/providers/fips/self_test_kats.c
+++ b/providers/fips/self_test_kats.c
@@ -17,8 +17,6 @@
 #include "crypto/rand.h"
 #include "internal/cryptlib.h"
 #include "self_test.h"
-#include "self_test_data.h"
-#include "internal/fips.h"

 static int set_kat_drbg(OSSL_LIB_CTX *ctx,
     const unsigned char *entropy, size_t entropy_len,
@@ -901,125 +899,6 @@ err:
     return ret;
 }

-#define RUN_TEST(test) \
-    ((test.deferred != SELF_TEST_DEFERRED) || do_deferred)
-
-/*
- * Test a data driven list of KAT's for digest algorithms.
- * All tests are run regardless of if they fail or not.
- * Return 0 if any test fails.
- */
-static int self_test_digests(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx,
-    int do_deferred)
-{
-    int i, ret = 1;
-
-    for (i = 0; i < st_kat_digest_tests_size; ++i) {
-        if (RUN_TEST(st_kat_digest_tests[i]))
-            if (!self_test_digest(&st_kat_digest_tests[i], st, libctx))
-                ret = 0;
-    }
-    return ret;
-}
-
-static int self_test_ciphers(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx,
-    int do_deferred)
-{
-    int i, ret = 1;
-
-    for (i = 0; i < st_kat_cipher_tests_size; ++i) {
-        if (RUN_TEST(st_kat_cipher_tests[i]))
-            if (!self_test_cipher(&st_kat_cipher_tests[i], st, libctx))
-                ret = 0;
-    }
-    return ret;
-}
-
-static int self_test_kems(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx,
-    int do_deferred)
-{
-    int ret = 1;
-#ifndef OPENSSL_NO_ML_KEM
-    int i;
-
-    for (i = 0; i < st_kat_kem_tests_size; ++i) {
-        if (RUN_TEST(st_kat_kem_tests[i]))
-            if (!self_test_kem(&st_kat_kem_tests[i], st, libctx))
-                ret = 0;
-    }
-#endif
-    return ret;
-}
-
-static int self_test_asym_ciphers(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx,
-    int do_deferred)
-{
-    int i, ret = 1;
-
-    for (i = 0; i < st_kat_asym_cipher_tests_size; ++i) {
-        if (RUN_TEST(st_kat_asym_cipher_tests[i]))
-            if (!self_test_asym_cipher(&st_kat_asym_cipher_tests[i], st, libctx))
-                ret = 0;
-    }
-    return ret;
-}
-
-static int self_test_kdfs(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx,
-    int do_deferred)
-{
-    int i, ret = 1;
-
-    for (i = 0; i < st_kat_kdf_tests_size; ++i) {
-        if (RUN_TEST(st_kat_kdf_tests[i]))
-            if (!self_test_kdf(&st_kat_kdf_tests[i], st, libctx))
-                ret = 0;
-    }
-    return ret;
-}
-
-static int self_test_drbgs(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx,
-    int do_deferred)
-{
-    int i, ret = 1;
-
-    for (i = 0; i < st_kat_drbg_tests_size; ++i) {
-        if (RUN_TEST(st_kat_drbg_tests[i]))
-            if (!self_test_drbg(&st_kat_drbg_tests[i], st, libctx))
-                ret = 0;
-    }
-    return ret;
-}
-
-static int self_test_kas(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx,
-    int do_deferred)
-{
-    int ret = 1;
-#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_EC)
-    int i;
-
-    for (i = 0; i < st_kat_kas_tests_size; ++i) {
-        if (RUN_TEST(st_kat_kas_tests[i]))
-            if (!self_test_ka(&st_kat_kas_tests[i], st, libctx))
-                ret = 0;
-    }
-#endif
-
-    return ret;
-}
-
-static int self_test_signatures(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx,
-    int do_deferred)
-{
-    int i, ret = 1;
-
-    for (i = 0; i < st_kat_sign_tests_size; ++i) {
-        if (RUN_TEST(st_kat_sign_tests[i]))
-            if (!self_test_digest_sign(&st_kat_sign_tests[i], st, libctx))
-                ret = 0;
-    }
-    return ret;
-}
-
 /*
  * Swap the library context DRBG for KAT testing
  *
@@ -1160,24 +1039,6 @@ err:
     return 0;
 }

-static int self_test_asym_keygens(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx,
-    int do_deferred)
-{
-#if !defined(OPENSSL_NO_ML_DSA) || !defined(OPENSSL_NO_SLH_DSA)
-    int i, ret = 1;
-
-    for (i = 0; i < st_kat_asym_keygen_tests_size; ++i) {
-        if (RUN_TEST(st_kat_asym_keygen_tests[i]))
-            continue;
-        if (!self_test_asym_keygen(&st_kat_asym_keygen_tests[i], st, libctx))
-            ret = 0;
-    }
-    return ret;
-#else
-    return 1;
-#endif /* OPENSSL_NO_ML_DSA */
-}
-
 /*
  * Run the algorithm KAT's.
  * Return 1 is successful, otherwise return 0.
@@ -1187,7 +1048,7 @@ static int self_test_asym_keygens(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx,
 int SELF_TEST_kats(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx, int do_deferred)
 {
     EVP_RAND_CTX *saved_rand = ossl_rand_get0_private_noncreating(libctx);
-    int ret = 1;
+    int i, ret = 1;

     if (saved_rand != NULL && !EVP_RAND_CTX_up_ref(saved_rand))
         return 0;
@@ -1201,24 +1062,49 @@ int SELF_TEST_kats(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx, int do_deferred)
         return 0;
     }

-    if (!self_test_digests(st, libctx, do_deferred))
-        ret = 0;
-    if (!self_test_ciphers(st, libctx, do_deferred))
-        ret = 0;
-    if (!self_test_signatures(st, libctx, do_deferred))
-        ret = 0;
-    if (!self_test_kdfs(st, libctx, do_deferred))
-        ret = 0;
-    if (!self_test_drbgs(st, libctx, do_deferred))
-        ret = 0;
-    if (!self_test_kas(st, libctx, do_deferred))
-        ret = 0;
-    if (!self_test_asym_keygens(st, libctx, do_deferred))
-        ret = 0;
-    if (!self_test_kems(st, libctx, do_deferred))
-        ret = 0;
-    if (!self_test_asym_ciphers(st, libctx, do_deferred))
-        ret = 0;
+    for (i = 0; i < ST_ID_MAX; i++) {
+        int res;
+
+        if (!do_deferred && (st_all_tests[i].deferred == SELF_TEST_DEFERRED))
+            continue;
+
+        switch (st_all_tests[i].category) {
+        case SELF_TEST_KAT_DIGEST:
+            res = self_test_digest(&st_all_tests[i], st, libctx);
+            break;
+        case SELF_TEST_KAT_CIPHER:
+            res = self_test_cipher(&st_all_tests[i], st, libctx);
+            break;
+        case SELF_TEST_KAT_SIGNATURE:
+            res = self_test_digest_sign(&st_all_tests[i], st, libctx);
+            break;
+        case SELF_TEST_KAT_KDF:
+            res = self_test_kdf(&st_all_tests[i], st, libctx);
+            break;
+        case SELF_TEST_DRBG:
+            res = self_test_drbg(&st_all_tests[i], st, libctx);
+            break;
+        case SELF_TEST_KAT_KAS:
+            res = self_test_ka(&st_all_tests[i], st, libctx);
+            break;
+        case SELF_TEST_KAT_ASYM_KEYGEN:
+            res = self_test_asym_keygen(&st_all_tests[i], st, libctx);
+            break;
+        case SELF_TEST_KAT_KEM:
+            res = self_test_kem(&st_all_tests[i], st, libctx);
+            break;
+        case SELF_TEST_KAT_ASYM_CIPHER:
+            res = self_test_asym_cipher(&st_all_tests[i], st, libctx);
+            break;
+        default:
+            res = 0;
+            break;
+        }
+        if (res)
+            st_all_tests[i].state = SELF_TEST_STATE_PASSED;
+        else
+            ret = 0;
+    }

     RAND_set0_private(libctx, saved_rand);
     /* The above call will cause main_rand to be freed */
@@ -1237,14 +1123,12 @@ int SELF_TEST_kats(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx, int do_deferred)
  * NOTE: currently tests that require the TEST RNG will not work, as we can't
  * replace the working DRBG with the TEST DRB after initialization.
  */
-int SELF_TEST_kats_single(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx,
-    int type, const char *alg_name)
+int SELF_TEST_kats_single(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx, int id)
 {
     EVP_RAND_CTX *saved_rand = ossl_rand_get0_private_noncreating(libctx);
-    int ret = 1;
-    int i, found = 0;
+    int ret;

-    if (alg_name == NULL)
+    if (id >= ST_ID_MAX)
         return 0;

     if (saved_rand != NULL && !EVP_RAND_CTX_up_ref(saved_rand))
@@ -1257,129 +1141,53 @@ int SELF_TEST_kats_single(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx,
         return 0;
     }

-    switch (type) {
-    case FIPS_DEFERRED_KAT_DIGEST:
-        for (i = 0; i < st_kat_digest_tests_size; ++i) {
-            if (strcmp(st_kat_digest_tests[i].algorithm, alg_name) == 0) {
-                found = 1;
-                if (!self_test_digest(&st_kat_digest_tests[i], st, libctx)) {
-                    ret = 0;
-                    goto done;
-                }
-            }
-        }
+    switch (st_all_tests[id].category) {
+    case SELF_TEST_KAT_DIGEST:
+        ret = self_test_digest(&st_all_tests[id], st, libctx);
         break;
-
-    case FIPS_DEFERRED_KAT_CIPHER:
-        for (i = 0; i < st_kat_cipher_tests_size; ++i) {
-            if (strcmp(st_kat_cipher_tests[i].algorithm, alg_name) == 0) {
-                found = 1;
-                if (!self_test_cipher(&st_kat_cipher_tests[i], st, libctx)) {
-                    ret = 0;
-                    goto done;
-                }
-            }
-        }
+    case SELF_TEST_KAT_CIPHER:
+        ret = self_test_cipher(&st_all_tests[id], st, libctx);
         break;
-
-    case FIPS_DEFERRED_KAT_SIGNATURE:
-        for (i = 0; i < st_kat_sign_tests_size; ++i) {
-            if (strcmp(st_kat_sign_tests[i].algorithm, alg_name) == 0
-                || strcmp(st_kat_sign_tests[i].u.sig.keytype, alg_name) == 0) {
-                found = 1;
-                if (!self_test_digest_sign(&st_kat_sign_tests[i], st, libctx)) {
-                    ret = 0;
-                    goto done;
-                }
-            }
-        }
+    case SELF_TEST_KAT_SIGNATURE:
+        ret = self_test_digest_sign(&st_all_tests[id], st, libctx);
         break;
-
-    case FIPS_DEFERRED_KAT_KDF:
-        for (i = 0; i < st_kat_kdf_tests_size; ++i) {
-            if (strcmp(st_kat_kdf_tests[i].algorithm, alg_name) == 0) {
-                found = 1;
-                if (!self_test_kdf(&st_kat_kdf_tests[i], st, libctx)) {
-                    ret = 0;
-                    goto done;
-                }
-            }
-        }
+    case SELF_TEST_KAT_KDF:
+        ret = self_test_kdf(&st_all_tests[id], st, libctx);
         break;
-
-#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_EC)
-    case FIPS_DEFERRED_KAT_KA:
-        for (i = 0; i < st_kat_kas_tests_size; ++i) {
-            if (strcmp(st_kat_kas_tests[i].algorithm, alg_name) == 0) {
-                found = 1;
-                if (!self_test_ka(&st_kat_kas_tests[i], st, libctx)) {
-                    ret = 0;
-                    goto done;
-                }
-            }
-        }
+    case SELF_TEST_DRBG:
+        ret = self_test_drbg(&st_all_tests[id], st, libctx);
         break;
-#endif
-
-#if !defined(OPENSSL_NO_ML_DSA) || !defined(OPENSSL_NO_SLH_DSA)
-    case FIPS_DEFERRED_KAT_ASYM_KEYGEN:
-        for (i = 0; i < st_kat_asym_keygen_tests_size; ++i) {
-            if (strcmp(st_kat_asym_keygen_tests[i].algorithm, alg_name) == 0) {
-                found = 1;
-                if (!self_test_asym_keygen(&st_kat_asym_keygen_tests[i], st, libctx)) {
-                    ret = 0;
-                    goto done;
-                }
-            }
-        }
+    case SELF_TEST_KAT_KAS:
+        ret = self_test_ka(&st_all_tests[id], st, libctx);
         break;
-#endif /* OPENSSL_NO_ML_DSA */
-
-#ifndef OPENSSL_NO_ML_KEM
-    case FIPS_DEFERRED_KAT_KEM:
-        for (i = 0; i < st_kat_kem_tests_size; ++i) {
-            if (strcmp(st_kat_kem_tests[i].algorithm, alg_name) == 0) {
-                found = 1;
-                if (!self_test_kem(&st_kat_kem_tests[i], st, libctx)) {
-                    ret = 0;
-                    goto done;
-                }
-            }
-        }
+    case SELF_TEST_KAT_ASYM_KEYGEN:
+        ret = self_test_asym_keygen(&st_all_tests[id], st, libctx);
         break;
-#endif
-
-    case FIPS_DEFERRED_KAT_ASYM_CIPHER:
-        for (i = 0; i < st_kat_asym_cipher_tests_size; ++i) {
-            if (strcmp(st_kat_asym_cipher_tests[i].algorithm, alg_name) == 0) {
-                found = 1;
-                if (!self_test_asym_cipher(&st_kat_asym_cipher_tests[i], st, libctx)) {
-                    ret = 0;
-                    goto done;
-                }
-            }
-        }
+    case SELF_TEST_KAT_KEM:
+        ret = self_test_kem(&st_all_tests[id], st, libctx);
         break;
-
-    case FIPS_DEFERRED_DRBG:
-        for (i = 0; i < st_kat_drbg_tests_size; ++i) {
-            if (strcmp(st_kat_drbg_tests[i].algorithm, alg_name) == 0) {
-                found = 1;
-                if (!self_test_drbg(&st_kat_drbg_tests[i], st, libctx)) {
-                    ret = 0;
-                    goto done;
-                }
-            }
-        }
+    case SELF_TEST_KAT_ASYM_CIPHER:
+        ret = self_test_asym_cipher(&st_all_tests[id], st, libctx);
         break;
-
     default:
-        /* not tests yet, or bad type */
+        ret = 0;
         break;
     }
+    if (ret)
+        st_all_tests[id].state = SELF_TEST_STATE_PASSED;
+    else
+        st_all_tests[id].state = SELF_TEST_STATE_FAILED;

-done:
     RAND_set0_private(libctx, saved_rand);
-    /* If no test was found for alg_name, it is considered a failure */
-    return ret && found;
+    return ret;
+}
+
+int ossl_self_test_in_progress(self_test_id_t id)
+{
+    if (id >= ST_ID_MAX)
+        return 0;
+
+    if (st_all_tests[id].state == SELF_TEST_STATE_IN_PROGRESS)
+        return 1;
+    return 0;
 }
diff --git a/providers/implementations/keymgmt/slh_dsa_kmgmt.c b/providers/implementations/keymgmt/slh_dsa_kmgmt.c
index c1c4ce5383..292ce22e9f 100644
--- a/providers/implementations/keymgmt/slh_dsa_kmgmt.c
+++ b/providers/implementations/keymgmt/slh_dsa_kmgmt.c
@@ -45,22 +45,13 @@ static OSSL_FUNC_keymgmt_dup_fn slh_dsa_dup_key;

 #define SLH_DSA_POSSIBLE_SELECTIONS (OSSL_KEYMGMT_SELECT_KEYPAIR)

-#ifdef FIPS_MODULE
-static FIPS_DEFERRED_TEST slh_key_gen_deferred_tests[] = {
-    { "SLH-DSA-SHA2-128f",
-        FIPS_DEFERRED_KAT_ASYM_KEYGEN,
-        FIPS_DEFERRED_TEST_INIT },
-    { NULL, 0, 0 },
-};
-#endif
-
 static int slh_dsa_self_check(OSSL_LIB_CTX *libctx)
 {
     if (!ossl_prov_is_running())
         return 0;

 #ifdef FIPS_MODULE
-    return FIPS_deferred_self_tests(libctx, slh_key_gen_deferred_tests);
+    return ossl_deferred_self_test(libctx, ST_ID_ASYM_KEYGEN_SLH_DSA);
 #else
     return 1;
 #endif
@@ -318,7 +309,7 @@ static int slh_dsa_fips140_pairwise_test(const SLH_DSA_KEY *key,

     /* During self test, it is a waste to do this test */
     if (ossl_fips_self_testing()
-        || slh_key_gen_deferred_tests[0].state == FIPS_DEFERRED_TEST_IN_PROGRESS)
+        || ossl_self_test_in_progress(ST_ID_ASYM_KEYGEN_SLH_DSA))
         return 1;

     if (ctx == NULL) {
diff --git a/providers/implementations/signature/slh_dsa_sig.c b/providers/implementations/signature/slh_dsa_sig.c
index 65796b03f9..600cf7f19e 100644
--- a/providers/implementations/signature/slh_dsa_sig.c
+++ b/providers/implementations/signature/slh_dsa_sig.c
@@ -39,25 +39,16 @@ static OSSL_FUNC_signature_dupctx_fn slh_dsa_dupctx;
 static OSSL_FUNC_signature_set_ctx_params_fn slh_dsa_set_ctx_params;
 static OSSL_FUNC_signature_settable_ctx_params_fn slh_dsa_settable_ctx_params;

-#ifdef FIPS_MODULE
-static FIPS_DEFERRED_TEST slh_sig_deferred_tests[] = {
-    { "SLH-DSA-SHA2-128f",
-        FIPS_DEFERRED_KAT_SIGNATURE,
-        FIPS_DEFERRED_TEST_INIT },
-    { "SLH-DSA-SHAKE-128f",
-        FIPS_DEFERRED_KAT_SIGNATURE,
-        FIPS_DEFERRED_TEST_INIT },
-    { NULL, 0, 0 },
-};
-#endif
-
-static int slh_dsa_self_check(OSSL_LIB_CTX *libctx)
+static int slh_dsa_self_check(OSSL_LIB_CTX *libctx, const char *alg)
 {
     if (!ossl_prov_is_running())
         return 0;

 #ifdef FIPS_MODULE
-    return FIPS_deferred_self_tests(libctx, slh_sig_deferred_tests);
+    if (strstr(alg, "SLH-DSA-SHAKE"))
+        return ossl_deferred_self_test(libctx, ST_ID_SIG_SLH_DSA_SHAKE_128F);
+    else
+        return ossl_deferred_self_test(libctx, ST_ID_SIG_SLH_DSA_SHA2_128F);
 #else
     return 1;
 #endif
@@ -97,7 +88,7 @@ static void *slh_dsa_newctx(void *provctx, const char *alg, const char *propq)
 {
     PROV_SLH_DSA_CTX *ctx;

-    if (!slh_dsa_self_check(PROV_LIBCTX_OF(provctx)))
+    if (!slh_dsa_self_check(PROV_LIBCTX_OF(provctx), alg))
         return NULL;

     ctx = OPENSSL_zalloc(sizeof(PROV_SLH_DSA_CTX));