From: Simo Sorce Date: Fri, 5 Dec 2025 04:14:47 +0000 (-0500) Subject: Add dependency handling for FIPS self-tests X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0afbd6bfb3f6e95c6039c509135ff26b3b946502;p=thirdparty%2Fopenssl.git Add dependency handling for FIPS self-tests Some FIPS Known Answer Tests (KATs) rely on other cryptographic algorithms that also have their own KATs. This change introduces a formal mechanism to ensure these dependencies are met before a test is run. A `depends_on` field is added to the self-test definition to declare prerequisites. A new recursive function, `FIPS_kat_deferred_execute`, traverses this dependency chain, executing any required tests first. This new logic also prevents tests from being run multiple times if they are a dependency for several other tests. The `FIPS_kat_deferred` function is updated to use this new dependency-aware execution function. Signed-off-by: Simo Sorce Reviewed-by: Dmitry Belyavskiy (Merged from https://github.com/openssl/openssl/pull/29222) --- diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index 933125a9b98..3808eb5ad55 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -1315,6 +1315,43 @@ static void deferred_deinit(void) } } +static int FIPS_kat_deferred_execute(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx, + self_test_id_t id) +{ + /* + * 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) + return 1; + + /* Mark test as in progress */ + st_all_tests[id].state = SELF_TEST_STATE_IN_PROGRESS; + + /* check if there are dependent tests to run */ + if (st_all_tests[id].depends_on) { + for (int i = 0; st_all_tests[id].depends_on[i] != ST_ID_MAX; i++) { + self_test_id_t dep_id = st_all_tests[id].depends_on[i]; + + FIPS_kat_deferred_execute(st, libctx, dep_id); + switch (st_all_tests[dep_id].state) { + case SELF_TEST_STATE_PASSED: + case SELF_TEST_STATE_IN_PROGRESS: + continue; + default: + return 0; + } + } + } + + /* may have already been run as a dependency, recheck before executing */ + if (st_all_tests[id].state == SELF_TEST_STATE_IN_PROGRESS) + if (!SELF_TEST_kats_single(st, libctx, id)) + return 0; + + return 1; +} + static int FIPS_kat_deferred(OSSL_LIB_CTX *libctx, self_test_id_t id) { int *rt = NULL; @@ -1373,7 +1410,7 @@ static int FIPS_kat_deferred(OSSL_LIB_CTX *libctx, self_test_id_t id) /* 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)) + libctx, rt)) goto done; unset_key = true; @@ -1384,19 +1421,9 @@ static int FIPS_kat_deferred(OSSL_LIB_CTX *libctx, self_test_id_t id) if ((st = OSSL_SELF_TEST_new(cb, cb_arg)) == NULL) goto done; - /* - * 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) { - - /* Mark test as in progress */ - st_all_tests[id].state = SELF_TEST_STATE_IN_PROGRESS; - - /* execute test */ - if (!SELF_TEST_kats_single(st, libctx, id)) - goto done; - } + /* Handles dependencies via recursion */ + if (!(ret = FIPS_kat_deferred_execute(st, libctx, id))) + goto done; /* * now mark as passed all the algorithms that have been executed by @@ -1482,7 +1509,7 @@ int ossl_deferred_self_test(OSSL_LIB_CTX *libctx, self_test_id_t id) * in FIPS_kat_deferred() so this race is of no real consequence. */ ret = FIPS_kat_deferred(libctx, id); - if (!ret) + if (!ret || st_all_tests[id].state == SELF_TEST_STATE_FAILED) 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 2c19653b663..cff506915ea 100644 --- a/providers/fips/self_test.h +++ b/providers/fips/self_test.h @@ -163,6 +163,7 @@ typedef struct self_test_st { ST_KAT_KAS kas; ST_KAT_DRBG drbg; } u; + self_test_id_t *depends_on; } ST_DEFINITION; extern ST_DEFINITION st_all_tests[ST_ID_MAX];