From: Simo Sorce Date: Tue, 30 Sep 2025 20:12:03 +0000 (-0400) Subject: Allow running individual FIPS self-tests X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=eb58322dc9d0013bffc662ab0360c6184abc8319;p=thirdparty%2Fopenssl.git Allow running individual FIPS self-tests 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 Reviewed-by: Paul Dale Reviewed-by: Shane Lontis Reviewed-by: Dmitry Belyavskiy (Merged from https://github.com/openssl/openssl/pull/28725) --- diff --git a/include/internal/fips.h b/include/internal/fips.h index 3f70c0de93c..5760e0a9fd3 100644 --- a/include/internal/fips.h +++ b/include/internal/fips.h @@ -16,6 +16,42 @@ /* 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 diff --git a/include/internal/threads_common.h b/include/internal/threads_common.h index 0497a9e1193..aa5f1b08acc 100644 --- a/include/internal/threads_common.h +++ b/include/internal/threads_common.h @@ -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; diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index cb04b2a62ca..fc1d369b120 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -16,6 +16,7 @@ #include /* RAND_get0_public() */ #include #include +#include #include "internal/cryptlib.h" #include "internal/provider.h" #include "prov/implementations.h" @@ -29,7 +30,10 @@ #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; +} diff --git a/providers/fips/self_test.h b/providers/fips/self_test.h index cdc90d8d040..99b1a28a92e 100644 --- a/providers/fips/self_test.h +++ b/providers/fips/self_test.h @@ -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); diff --git a/providers/fips/self_test_data.inc b/providers/fips/self_test_data.inc index e8dbe61c1e2..b864a47a56c 100644 --- a/providers/fips/self_test_data.inc +++ b/providers/fips/self_test_data.inc @@ -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, diff --git a/providers/fips/self_test_kats.c b/providers/fips/self_test_kats.c index f1a54c66093..2e94219bc5c 100644 --- a/providers/fips/self_test_kats.c +++ b/providers/fips/self_test_kats.c @@ -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; +}