]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Allow running individual FIPS self-tests
authorSimo Sorce <simo@redhat.com>
Tue, 30 Sep 2025 20:12:03 +0000 (16:12 -0400)
committerDmitry Belyavskiy <beldmit@gmail.com>
Sat, 25 Oct 2025 08:45:21 +0000 (10:45 +0200)
This introduces a new function, `SELF_TEST_kats_single()`, to the FIPS
provider. This allows for deferring running the Known Answer Tests (KATs)
for a specific algorithm. This is useful to avoid running
computationally costly tests upfront and instead run them only if the
algorithm is actually going to be used.

To support this, a `deferred` flag has been added to the test data
structures. The main self-test function, `SELF_TEST_kats()`, is updated to
skip tests marked for deferred execution, preserving its existing startup
behavior for all other tests.

Signed-off-by: Simo Sorce <simo@redhat.com>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/28725)

include/internal/fips.h
include/internal/threads_common.h
providers/fips/fipsprov.c
providers/fips/self_test.h
providers/fips/self_test_data.inc
providers/fips/self_test_kats.c

index 3f70c0de93c55e16ffbd19a2dc3bbaab9ad4d856..5760e0a9fd3a43db6c7de711b1cc4c2dba665e0c 100644 (file)
 /* 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
+ */
+#  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;
+
+int FIPS_deferred_self_tests(OSSL_LIB_CTX *libctx, FIPS_DEFERRED_TEST tests[]);
+
 # endif /* FIPS_MODULE */
 
 #endif
index 0497a9e1193f49c5bf49617b0be2feb7607c5e45..aa5f1b08acc726792835228a022d030ed66a76f8 100644 (file)
@@ -18,6 +18,7 @@ typedef enum {
     CRYPTO_THREAD_LOCAL_ASYNC_CTX_KEY,
     CRYPTO_THREAD_LOCAL_ASYNC_POOL_KEY,
     CRYPTO_THREAD_LOCAL_TEVENT_KEY,
+    CRYPTO_THREAD_LOCAL_FIPS_DEFERRED_KEY,
     CRYPTO_THREAD_LOCAL_KEY_MAX
 } CRYPTO_THREAD_LOCAL_KEY_ID;
 
index cb04b2a62ca1fee59cd2ae4374efbf78de570be7..fc1d369b1209fab631703ad0a0d20e86622839f9 100644 (file)
@@ -16,6 +16,7 @@
 #include <openssl/rand.h> /* RAND_get0_public() */
 #include <openssl/proverr.h>
 #include <openssl/indicator.h>
+#include <openssl/self_test.h>
 #include "internal/cryptlib.h"
 #include "internal/provider.h"
 #include "prov/implementations.h"
 #include "crypto/context.h"
 #include "fipscommon.h"
 #include "internal/core.h"
+#include "internal/fips.h"
 #include "internal/mem_alloc_utils.h"
+#include "internal/thread_once.h"
+#include "internal/threads_common.h"
 
 static const char FIPS_DEFAULT_PROPERTIES[] = "provider=fips,fips=yes";
 static const char FIPS_UNAPPROVED_PROPERTIES[] = "provider=fips,fips=no";
@@ -120,8 +124,12 @@ 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);
 }
 
@@ -1238,3 +1246,167 @@ void OSSL_INDICATOR_get_callback(OSSL_LIB_CTX *libctx,
             *cb = NULL;
     }
 }
+
+/* Deferred test infrastructure */
+
+/* Guards access to deferred self-test */
+static CRYPTO_RWLOCK *deferred_lock;
+
+static CRYPTO_ONCE deferred_once = CRYPTO_ONCE_STATIC_INIT;
+static void deferred_init(void)
+{
+    if ((deferred_lock = CRYPTO_THREAD_lock_new()) == NULL)
+        ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_CREATE_LOCK);
+}
+static void deferred_deinit(void)
+{
+    if (deferred_lock) {
+        CRYPTO_THREAD_lock_free(deferred_lock);
+        deferred_lock = NULL;
+    }
+}
+
+static int FIPS_kat_deferred(OSSL_LIB_CTX *libctx, FIPS_DEFERRED_TEST *test)
+{
+    int ret = FIPS_DEFERRED_TEST_FAILED;
+
+    if (!CRYPTO_THREAD_run_once(&deferred_once, deferred_init))
+        return FIPS_DEFERRED_TEST_FAILED;
+
+    if (deferred_lock == NULL)
+        return FIPS_DEFERRED_TEST_FAILED;
+
+    /*
+     * 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;
+
+    if (CRYPTO_THREAD_write_lock(deferred_lock)) {
+        OSSL_SELF_TEST *ev = NULL;
+        bool unset_key = false;
+        OSSL_CALLBACK *cb = NULL;
+        void *cb_arg = NULL;
+
+        /*
+         * 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;
+            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 (!CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_FIPS_DEFERRED_KEY,
+                                        libctx, (void *)0xC001))
+            goto done;
+
+        unset_key = true;
+
+        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)
+            goto done;
+
+        /* Mark test as in progress */
+        test->state = FIPS_DEFERRED_TEST_IN_PROGRESS;
+
+        /* execute test */
+        if (SELF_TEST_kats_single(ev, libctx, test->category, test->algorithm))
+            ret = FIPS_DEFERRED_TEST_PASSED;
+
+    done:
+        /* Mark test as pass or fail */
+        test->state = ret;
+
+        if (ev)
+            OSSL_SELF_TEST_free(ev);
+        if (unset_key)
+            CRYPTO_THREAD_set_local_ex(CRYPTO_THREAD_LOCAL_FIPS_DEFERRED_KEY,
+                                       libctx, NULL);
+        CRYPTO_THREAD_unlock(deferred_lock);
+    }
+    return ret;
+}
+
+static void deferred_test_error(int category)
+{
+    const char *category_name = "Unknown Category Test";
+
+    switch (category) {
+    case FIPS_DEFERRED_KAT_CIPHER:
+        category_name = OSSL_SELF_TEST_TYPE_KAT_CIPHER;
+        break;
+    case FIPS_DEFERRED_KAT_ASYM_CIPHER:
+        category_name = OSSL_SELF_TEST_TYPE_KAT_ASYM_CIPHER;
+        break;
+    case FIPS_DEFERRED_KAT_ASYM_KEYGEN:
+        category_name = OSSL_SELF_TEST_TYPE_KAT_ASYM_KEYGEN;
+        break;
+    case FIPS_DEFERRED_KAT_KEM:
+        category_name = OSSL_SELF_TEST_TYPE_KAT_KEM;
+        break;
+    case FIPS_DEFERRED_KAT_DIGEST:
+        category_name = OSSL_SELF_TEST_TYPE_KAT_DIGEST;
+        break;
+    case FIPS_DEFERRED_KAT_SIGNATURE:
+        category_name = OSSL_SELF_TEST_TYPE_KAT_SIGNATURE;
+        break;
+    case FIPS_DEFERRED_KAT_KDF:
+        category_name = OSSL_SELF_TEST_TYPE_KAT_KDF;
+        break;
+    case FIPS_DEFERRED_KAT_KA:
+        category_name = OSSL_SELF_TEST_TYPE_KAT_KA;
+        break;
+    case FIPS_DEFERRED_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 i;
+
+    /*
+     * NOTE: that the order in which we check the 'state' here is not important,
+     * if multiple threads are racing to check it the worst case scenario is
+     * that they will all try to run the tests. Proper locking for preventing
+     * 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;
+}
index cdc90d8d040641786c1aa1ed2aa3988f0789b525..99b1a28a92eb630ce1ca3cae2ad569752051c2a4 100644 (file)
@@ -32,5 +32,7 @@ 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 *event, OSSL_LIB_CTX *libctx);
+int SELF_TEST_kats_single(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx,
+                          int type, const char *alg_name);
 
 void SELF_TEST_disable_conditional_error_state(void);
index e8dbe61c1e25273bb01d57442ce5d9b90d49c7b2..b864a47a56c09200f9ec73cd4107b03997da653b 100644 (file)
@@ -43,6 +43,7 @@ typedef struct st_kat_param_st {
 typedef struct st_kat_st {
     const char *desc;
     const char *algorithm;
+    int deferred;
     const unsigned char *pt;
     size_t pt_len;
     const unsigned char *expected;
@@ -76,6 +77,7 @@ typedef struct st_kat_cipher_st {
 typedef struct st_kat_kdf_st {
     const char *desc;
     const char *algorithm;
+    int deferred;
     const ST_KAT_PARAM *params;
     const unsigned char *expected;
     size_t expected_len;
@@ -84,6 +86,7 @@ typedef struct st_kat_kdf_st {
 typedef struct st_kat_drbg_st {
     const char *desc;
     const char *algorithm;
+    int deferred;
     const char *param_name;
     char *param_value;
     const unsigned char *entropyin;
@@ -107,6 +110,7 @@ typedef struct st_kat_drbg_st {
 typedef struct st_kat_kas_st {
     const char *desc;
     const char *algorithm;
+    int deferred;
 
     const ST_KAT_PARAM *key_group;
     const ST_KAT_PARAM *key_host_data;
@@ -120,6 +124,7 @@ typedef struct st_kat_sign_st {
     const char *desc;
     const char *keytype;
     const char *sigalgorithm;
+    int deferred;
     int mode;
     const ST_KAT_PARAM *key;
     const unsigned char *msg;
@@ -139,6 +144,7 @@ typedef struct st_kat_sign_st {
 typedef struct st_kat_asym_cipher_st {
     const char *desc;
     const char *algorithm;
+    int deferred;
     int encrypt;
     const ST_KAT_PARAM *key;
     const ST_KAT_PARAM *postinit;
@@ -151,6 +157,7 @@ typedef struct st_kat_asym_cipher_st {
 typedef struct st_kat_keygen_st {
     const char *desc;
     const char *algorithm;
+    int deferred;
     const ST_KAT_PARAM *keygen_params;
     const ST_KAT_PARAM *expected_params;
 } ST_KAT_ASYM_KEYGEN;
@@ -158,6 +165,7 @@ typedef struct st_kat_keygen_st {
 typedef struct st_kat_kem_st {
     const char *desc;
     const char *algorithm;
+    int deferred;
     const ST_KAT_PARAM *key;
     const unsigned char *cipher_text;
     size_t cipher_text_len;
@@ -201,18 +209,21 @@ static const ST_KAT_DIGEST st_kat_digest_tests[] =
     {
          OSSL_SELF_TEST_DESC_MD_SHA1,
          "SHA1",
+         0,
          ITM_STR(sha1_pt),
          ITM(sha1_digest),
     },
     {
          OSSL_SELF_TEST_DESC_MD_SHA2,
          "SHA512",
+         0,
          ITM_STR(sha512_pt),
          ITM(sha512_digest),
     },
     {
          OSSL_SELF_TEST_DESC_MD_SHA3,
          "SHA3-256",
+         0,
          ITM(sha3_256_pt),
          ITM(sha3_256_digest),
     },
@@ -286,6 +297,7 @@ static const ST_KAT_CIPHER st_kat_cipher_tests[] = {
         {
             OSSL_SELF_TEST_DESC_CIPHER_AES_GCM,
             "AES-256-GCM",
+            0,
             ITM(aes_256_gcm_pt),
             ITM(aes_256_gcm_ct)
         },
@@ -299,6 +311,7 @@ static const ST_KAT_CIPHER st_kat_cipher_tests[] = {
         {
             OSSL_SELF_TEST_DESC_CIPHER_AES_ECB,
             "AES-128-ECB",
+            0,
             ITM(aes_128_ecb_pt),
             ITM(aes_128_ecb_ct)
         },
@@ -310,6 +323,7 @@ static const ST_KAT_CIPHER st_kat_cipher_tests[] = {
         {
             OSSL_SELF_TEST_DESC_CIPHER_TDES,
             "DES-EDE3-ECB",
+            0,
             ITM(tdes_pt),
             ITM(tdes_ct)
         },
@@ -321,6 +335,7 @@ static const ST_KAT_CIPHER st_kat_cipher_tests[] = {
 
 #ifndef OPENSSL_NO_LMS
 typedef struct st_kat_lms_s {
+    int deferred;
     const unsigned char *pub;
     size_t publen;
     const unsigned char *msg;
@@ -455,6 +470,7 @@ static const unsigned char sha256_192_sig[] = {
 };
 
 static const ST_KAT_LMS st_kat_lms_test = {
+    0,
     ITM(sha256_192_pub),
     ITM(sha256_192_msg),
     ITM(sha256_192_sig)
@@ -762,60 +778,70 @@ static const ST_KAT_KDF st_kat_kdf_tests[] =
     {
         OSSL_SELF_TEST_DESC_KDF_TLS13_EXTRACT,
         OSSL_KDF_NAME_TLS1_3_KDF,
+        0,
         tls13_kdf_early_secret_params,
         ITM(tls13_kdf_early_secret)
     },
     {
         OSSL_SELF_TEST_DESC_KDF_TLS13_EXPAND,
         OSSL_KDF_NAME_TLS1_3_KDF,
+        0,
         tls13_kdf_client_early_secret_params,
         ITM(tls13_kdf_client_early_traffic_secret)
     },
     {
         OSSL_SELF_TEST_DESC_KDF_TLS12_PRF,
         OSSL_KDF_NAME_TLS1_PRF,
+        0,
         tls12prf_params,
         ITM(tls12prf_expected)
     },
     {
         OSSL_SELF_TEST_DESC_KDF_PBKDF2,
         OSSL_KDF_NAME_PBKDF2,
+        0,
         pbkdf2_params,
         ITM(pbkdf2_expected)
     },
     {
         OSSL_SELF_TEST_DESC_KDF_KBKDF,
         OSSL_KDF_NAME_KBKDF,
+        0,
         kbkdf_params,
         ITM(kbkdf_expected)
     },
     {
         OSSL_SELF_TEST_DESC_KDF_KBKDF_KMAC,
         OSSL_KDF_NAME_KBKDF,
+        0,
         kbkdf_kmac_params,
         ITM(kbkdf_kmac_expected)
     },
     {
         OSSL_SELF_TEST_DESC_KDF_HKDF,
         OSSL_KDF_NAME_HKDF,
+        0,
         hkdf_params,
         ITM(hkdf_expected)
     },
     {
         OSSL_SELF_TEST_DESC_KDF_SSKDF,
         OSSL_KDF_NAME_SSKDF,
+        0,
         sskdf_params,
         ITM(sskdf_expected)
     },
     {
         OSSL_SELF_TEST_DESC_KDF_X963KDF,
         OSSL_KDF_NAME_X963KDF,
+        0,
         x963kdf_params,
         ITM(x963kdf_expected)
     },
     {
         OSSL_SELF_TEST_DESC_KDF_X942KDF,
         OSSL_KDF_NAME_X942KDF_ASN1,
+        0,
         x942kdf_params,
         ITM(x942kdf_expected)
     },
@@ -1014,7 +1040,9 @@ static const ST_KAT_DRBG st_kat_drbg_tests[] =
 {
     {
         OSSL_SELF_TEST_DESC_DRBG_HASH,
-        "HASH-DRBG", "digest", "SHA256",
+        "HASH-DRBG",
+        0,
+        "digest", "SHA256",
         ITM(drbg_hash_sha256_pr_entropyin),
         ITM(drbg_hash_sha256_pr_nonce),
         ITM(drbg_hash_sha256_pr_persstr),
@@ -1026,7 +1054,9 @@ static const ST_KAT_DRBG st_kat_drbg_tests[] =
     },
     {
         OSSL_SELF_TEST_DESC_DRBG_CTR,
-        "CTR-DRBG", "cipher", "AES-128-CTR",
+        "CTR-DRBG",
+        0,
+        "cipher", "AES-128-CTR",
         ITM(drbg_ctr_aes128_pr_df_entropyin),
         ITM(drbg_ctr_aes128_pr_df_nonce),
         ITM(drbg_ctr_aes128_pr_df_persstr),
@@ -1038,7 +1068,9 @@ static const ST_KAT_DRBG st_kat_drbg_tests[] =
     },
     {
         OSSL_SELF_TEST_DESC_DRBG_HMAC,
-        "HMAC-DRBG", "digest", "SHA256",
+        "HMAC-DRBG",
+        0,
+        "digest", "SHA256",
         ITM(drbg_hmac_sha2_pr_entropyin),
         ITM(drbg_hmac_sha2_pr_nonce),
         ITM(drbg_hmac_sha2_pr_persstr),
@@ -1245,6 +1277,7 @@ static const ST_KAT_KAS st_kat_kas_tests[] =
     {
         OSSL_SELF_TEST_DESC_KA_DH,
         "DH",
+        0,
         dh_group,
         dh_host_key,
         dh_peer_key,
@@ -1255,6 +1288,7 @@ static const ST_KAT_KAS st_kat_kas_tests[] =
     {
         OSSL_SELF_TEST_DESC_KA_ECDH,
         "EC",
+        0,
         ecdh_group,
         ecdh_host_key,
         ecdh_peer_key,
@@ -3146,7 +3180,7 @@ static const unsigned char sig_kat_persstr[] = {
 static const ST_KAT_SIGN st_kat_sign_tests[] = {
     {
         OSSL_SELF_TEST_DESC_SIGN_RSA,
-        "RSA", "RSA-SHA256", 0,
+        "RSA", "RSA-SHA256", 0, 0,
         rsa_crt_key,
         ITM_STR(rsa_sig_msg),
         ITM(sig_kat_entropyin),
@@ -3157,7 +3191,7 @@ static const ST_KAT_SIGN st_kat_sign_tests[] = {
 #ifndef OPENSSL_NO_EC
     {
         OSSL_SELF_TEST_DESC_SIGN_ECDSA,
-        "EC", "ECDSA-SHA256", 0,
+        "EC", "ECDSA-SHA256", 0, 0,
         ecdsa_prime_key,
         ITM_STR(rsa_sig_msg),
         ITM(sig_kat_entropyin),
@@ -3167,7 +3201,7 @@ static const ST_KAT_SIGN st_kat_sign_tests[] = {
     },
     {
         OSSL_SELF_TEST_DESC_SIGN_DetECDSA,
-        "EC", "ECDSA-SHA256", 0,
+        "EC", "ECDSA-SHA256", 0, 0,
         ecdsa_prime_key,
         ITM_STR(rsa_sig_msg),
         NULL, 0, NULL, 0, NULL, 0,
@@ -3177,7 +3211,7 @@ static const ST_KAT_SIGN st_kat_sign_tests[] = {
 # ifndef OPENSSL_NO_EC2M
     {
         OSSL_SELF_TEST_DESC_SIGN_ECDSA,
-        "EC", "ECDSA-SHA256", 0,
+        "EC", "ECDSA-SHA256", 0, 0,
         ecdsa_bin_key,
         ITM_STR(rsa_sig_msg),
         ITM(sig_kat_entropyin),
@@ -3189,7 +3223,7 @@ static const ST_KAT_SIGN st_kat_sign_tests[] = {
 # ifndef OPENSSL_NO_ECX
     {
         OSSL_SELF_TEST_DESC_SIGN_EDDSA,
-        "ED448", "ED448", 0,
+        "ED448", "ED448", 0, 0,
         ed448_key,
         ITM(ecx_sig_msg),
         NULL, 0, NULL, 0, NULL, 0,
@@ -3197,7 +3231,7 @@ static const ST_KAT_SIGN st_kat_sign_tests[] = {
     },
     {
         OSSL_SELF_TEST_DESC_SIGN_EDDSA,
-        "ED25519", "ED25519", 0,
+        "ED25519", "ED25519", 0, 0,
         ed25519_key,
         ITM(ecx_sig_msg),
         NULL, 0, NULL, 0, NULL, 0,
@@ -3208,7 +3242,7 @@ static const ST_KAT_SIGN st_kat_sign_tests[] = {
 #ifndef OPENSSL_NO_DSA
     {
         OSSL_SELF_TEST_DESC_SIGN_DSA,
-        "DSA", "DSA-SHA256", SIGNATURE_MODE_VERIFY_ONLY,
+        "DSA", "DSA-SHA256", 0, SIGNATURE_MODE_VERIFY_ONLY,
         dsa_key,
         ITM_STR(rsa_sig_msg),
         ITM(sig_kat_entropyin),
@@ -3221,7 +3255,7 @@ static const ST_KAT_SIGN st_kat_sign_tests[] = {
 #ifndef OPENSSL_NO_ML_DSA
     {
         OSSL_SELF_TEST_DESC_SIGN_ML_DSA,
-        "ML-DSA-65", "ML-DSA-65", 0,
+        "ML-DSA-65", "ML-DSA-65", 0, 0,
         ml_dsa_key,
         ITM(ml_dsa_65_msg),
         NULL, 0,
@@ -3245,7 +3279,8 @@ static const ST_KAT_SIGN st_kat_sign_tests[] = {
      */
     {
         OSSL_SELF_TEST_DESC_SIGN_SLH_DSA,
-        "SLH-DSA-SHA2-128f", "SLH-DSA-SHA2-128f", SIGNATURE_MODE_SIG_DIGESTED,
+        "SLH-DSA-SHA2-128f", "SLH-DSA-SHA2-128f",
+        0, SIGNATURE_MODE_SIG_DIGESTED,
         slh_dsa_sha2_128f_key_params,
         ITM(slh_dsa_sha2_sig_msg),
         NULL, 0, NULL, 0, NULL, 0,
@@ -3254,7 +3289,8 @@ static const ST_KAT_SIGN st_kat_sign_tests[] = {
     },
     {
         OSSL_SELF_TEST_DESC_SIGN_SLH_DSA,
-        "SLH-DSA-SHAKE-128f", "SLH-DSA-SHAKE-128f", SIGNATURE_MODE_SIG_DIGESTED,
+        "SLH-DSA-SHAKE-128f", "SLH-DSA-SHAKE-128f",
+        0, SIGNATURE_MODE_SIG_DIGESTED,
         slh_dsa_shake_128f_key_params,
         ITM(slh_dsa_shake_sig_msg),
         NULL, 0, NULL, 0, NULL, 0,
@@ -3634,7 +3670,7 @@ static const ST_KAT_PARAM ml_kem_key[] = {
 static const ST_KAT_KEM st_kat_kem_tests[] = {
     {
         OSSL_SELF_TEST_DESC_KEM,
-        "ML-KEM-512",
+        "ML-KEM-512", 0,
         ml_kem_key,
         ITM(ml_kem_512_cipher_text),
         ITM(ml_kem_512_entropy),
@@ -3653,7 +3689,7 @@ static const ST_KAT_ASYM_KEYGEN st_kat_asym_keygen_tests[] = {
      */
     {
         OSSL_SELF_TEST_DESC_KEYGEN_ML_KEM,
-        "ML-KEM-512",
+        "ML-KEM-512", 0,
         ml_kem_keygen_params,
         ml_kem_key
     },
@@ -3661,7 +3697,7 @@ static const ST_KAT_ASYM_KEYGEN st_kat_asym_keygen_tests[] = {
 # if !defined(OPENSSL_NO_ML_DSA)
     {
         OSSL_SELF_TEST_DESC_KEYGEN_ML_DSA,
-        "ML-DSA-65",
+        "ML-DSA-65", 0,
         ml_dsa_keygen_params,
         ml_dsa_key
     },
@@ -3669,7 +3705,7 @@ static const ST_KAT_ASYM_KEYGEN st_kat_asym_keygen_tests[] = {
 # if !defined(OPENSSL_NO_SLH_DSA)
     {
         OSSL_SELF_TEST_DESC_KEYGEN_SLH_DSA,
-        "SLH-DSA-SHA2-128f",
+        "SLH-DSA-SHA2-128f", 0,
         slh_dsa_sha2_128f_keygen_init_params,
         slh_dsa_128f_keygen_expected_params
     },
@@ -3680,7 +3716,7 @@ static const ST_KAT_ASYM_KEYGEN st_kat_asym_keygen_tests[] = {
 static const ST_KAT_ASYM_CIPHER st_kat_asym_cipher_tests[] = {
     {
         OSSL_SELF_TEST_DESC_ASYM_RSA_ENC,
-        "RSA",
+        "RSA", 0,
         1,
         rsa_pub_key,
         rsa_enc_params,
@@ -3689,7 +3725,7 @@ static const ST_KAT_ASYM_CIPHER st_kat_asym_cipher_tests[] = {
     },
     {
         OSSL_SELF_TEST_DESC_ASYM_RSA_DEC,
-        "RSA",
+        "RSA", 0,
         0,
         rsa_priv_key,
         rsa_enc_params,
@@ -3698,7 +3734,7 @@ static const ST_KAT_ASYM_CIPHER st_kat_asym_cipher_tests[] = {
     },
     {
         OSSL_SELF_TEST_DESC_ASYM_RSA_DEC,
-        "RSA",
+        "RSA", 0,
         0,
         rsa_crt_key,
         rsa_enc_params,
index f1a54c66093312015e62238188f2d09d7cfc1129..2e94219bc5c25a1a7d91514ca40d7536fe03db6f 100644 (file)
@@ -20,6 +20,7 @@
 #include "self_test.h"
 #include "crypto/ml_kem.h"
 #include "self_test_data.inc"
+#include "internal/fips.h"
 
 static int set_kat_drbg(OSSL_LIB_CTX *ctx,
                         const unsigned char *entropy, size_t entropy_len,
@@ -955,6 +956,8 @@ static int self_test_digests(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx)
     int i, ret = 1;
 
     for (i = 0; i < (int)OSSL_NELEM(st_kat_digest_tests); ++i) {
+        if (st_kat_digest_tests[i].deferred)
+            continue;
         if (!self_test_digest(&st_kat_digest_tests[i], st, libctx))
             ret = 0;
     }
@@ -966,6 +969,8 @@ static int self_test_ciphers(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx)
     int i, ret = 1;
 
     for (i = 0; i < (int)OSSL_NELEM(st_kat_cipher_tests); ++i) {
+        if (st_kat_cipher_tests[i].base.deferred)
+            continue;
         if (!self_test_cipher(&st_kat_cipher_tests[i], st, libctx))
             ret = 0;
     }
@@ -979,6 +984,8 @@ static int self_test_kems(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx)
     int i;
 
     for (i = 0; i < (int)OSSL_NELEM(st_kat_kem_tests); ++i) {
+        if (st_kat_kem_tests[i].deferred)
+            continue;
         if (!self_test_kem(&st_kat_kem_tests[i], st, libctx))
             ret = 0;
     }
@@ -991,6 +998,8 @@ static int self_test_asym_ciphers(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx)
     int i, ret = 1;
 
     for (i = 0; i < (int)OSSL_NELEM(st_kat_asym_cipher_tests); ++i) {
+        if (st_kat_asym_cipher_tests[i].deferred)
+            continue;
         if (!self_test_asym_cipher(&st_kat_asym_cipher_tests[i], st, libctx))
             ret = 0;
     }
@@ -1002,6 +1011,8 @@ static int self_test_kdfs(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx)
     int i, ret = 1;
 
     for (i = 0; i < (int)OSSL_NELEM(st_kat_kdf_tests); ++i) {
+        if (st_kat_kdf_tests[i].deferred)
+            continue;
         if (!self_test_kdf(&st_kat_kdf_tests[i], st, libctx))
             ret = 0;
     }
@@ -1013,6 +1024,8 @@ static int self_test_drbgs(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx)
     int i, ret = 1;
 
     for (i = 0; i < (int)OSSL_NELEM(st_kat_drbg_tests); ++i) {
+        if (st_kat_drbg_tests[i].deferred)
+            continue;
         if (!self_test_drbg(&st_kat_drbg_tests[i], st, libctx))
             ret = 0;
     }
@@ -1026,6 +1039,8 @@ static int self_test_kas(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx)
     int i;
 
     for (i = 0; i < (int)OSSL_NELEM(st_kat_kas_tests); ++i) {
+        if (st_kat_kas_tests[i].deferred)
+            continue;
         if (!self_test_ka(&st_kat_kas_tests[i], st, libctx))
             ret = 0;
     }
@@ -1039,6 +1054,8 @@ static int self_test_signatures(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx)
     int i, ret = 1;
 
     for (i = 0; i < (int)OSSL_NELEM(st_kat_sign_tests); ++i) {
+        if (st_kat_sign_tests[i].deferred)
+            continue;
         if (!self_test_digest_sign(&st_kat_sign_tests[i], st, libctx))
             ret = 0;
     }
@@ -1191,6 +1208,8 @@ static int self_test_asym_keygens(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx)
     int i, ret = 1;
 
     for (i = 0; i < (int)OSSL_NELEM(st_kat_asym_keygen_tests); ++i) {
+        if (st_kat_asym_keygen_tests[i].deferred)
+            continue;
         if (!self_test_asym_keygen(&st_kat_asym_keygen_tests[i], st, libctx))
             ret = 0;
     }
@@ -1256,3 +1275,160 @@ int SELF_TEST_kats(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx)
     return ret;
 }
 
+/*
+ * Run a single algorithm KAT.
+ * This is similar to SELF_TEST_kats() but only runs the test for a single
+ * algorithm.
+ * Return 1 is successful, otherwise return 0. If no test is found for the
+ * algorithm it also returns 0.
+ * This runs all the tests for the given algorithm regardless of if any fail.
+ *
+ * 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 ret = 1;
+    int i, found = 0;
+
+    if (alg_name == NULL)
+        return 0;
+
+    switch (type) {
+    case FIPS_DEFERRED_KAT_DIGEST:
+        for (i = 0; i < (int)OSSL_NELEM(st_kat_digest_tests); ++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;
+                }
+            }
+        }
+        break;
+
+    case FIPS_DEFERRED_KAT_CIPHER:
+        for (i = 0; i < (int)OSSL_NELEM(st_kat_cipher_tests); ++i) {
+            if (strcmp(st_kat_cipher_tests[i].base.algorithm, alg_name) == 0) {
+                found = 1;
+                if (!self_test_cipher(&st_kat_cipher_tests[i], st, libctx)) {
+                    ret = 0;
+                    goto done;
+                }
+            }
+        }
+        break;
+
+    case FIPS_DEFERRED_KAT_SIGNATURE:
+
+#ifndef OPENSSL_NO_LMS
+        if (strcmp("LMS", alg_name) == 0) {
+            found = 1;
+            if (!self_test_LMS(st, libctx)) {
+                ret = 0;
+                goto done;
+            }
+            break;
+        }
+#endif  /* OPENSSL_NO_LMS */
+
+        for (i = 0; i < (int)OSSL_NELEM(st_kat_sign_tests); ++i) {
+            if (strcmp(st_kat_sign_tests[i].sigalgorithm, alg_name) == 0
+                || strcmp(st_kat_sign_tests[i].keytype, alg_name) == 0) {
+                found = 1;
+                if (!self_test_digest_sign(&st_kat_sign_tests[i], st, libctx)) {
+                    ret = 0;
+                    goto done;
+                }
+            }
+        }
+        break;
+
+    case FIPS_DEFERRED_KAT_KDF:
+        for (i = 0; i < (int)OSSL_NELEM(st_kat_kdf_tests); ++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;
+                }
+            }
+        }
+        break;
+
+#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_EC)
+    case FIPS_DEFERRED_KAT_KA:
+        for (i = 0; i < (int)OSSL_NELEM(st_kat_kas_tests); ++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;
+                }
+            }
+        }
+        break;
+#endif
+
+#if !defined(OPENSSL_NO_ML_DSA) || !defined(OPENSSL_NO_SLH_DSA)
+    case FIPS_DEFERRED_KAT_ASYM_KEYGEN:
+        for (i = 0; i < (int)OSSL_NELEM(st_kat_asym_keygen_tests); ++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;
+                }
+            }
+        }
+        break;
+#endif /* OPENSSL_NO_ML_DSA */
+
+#ifndef OPENSSL_NO_ML_KEM
+    case FIPS_DEFERRED_KAT_KEM:
+        for (i = 0; i < (int)OSSL_NELEM(st_kat_kem_tests); ++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;
+                }
+            }
+        }
+        break;
+#endif
+
+    case FIPS_DEFERRED_KAT_ASYM_CIPHER:
+        for (i = 0; i < (int)OSSL_NELEM(st_kat_asym_cipher_tests); ++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;
+                }
+            }
+        }
+        break;
+
+    case FIPS_DEFERRED_DRBG:
+        for (i = 0; i < (int)OSSL_NELEM(st_kat_drbg_tests); ++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;
+                }
+            }
+        }
+        break;
+
+    default:
+        /* not tests yet, or bad type */
+        break;
+    }
+
+done:
+    /* If no test was found for alg_name, it is considered a failure */
+    return ret && found;
+}