### Changes between 3.6 and 4.0 [xx XXX xxxx]
+ * FIPS self tests can now be deferred and run as needed when installing
+ the fips module with the -defer_tests option.
+
+ *Simo Sorce*
+
* OPENSSL_cleanup() now runs in a global destructor, or not at all by default.
OpenSSL_cleanup() will no longer by default free global objects when run from
OPT_NO_PBKDF2_LOWER_BOUND_CHECK,
OPT_ECDH_COFACTOR_CHECK,
OPT_SELF_TEST_ONLOAD,
- OPT_SELF_TEST_ONINSTALL
+ OPT_SELF_TEST_ONINSTALL,
+ OPT_DEFER_TESTS
} OPTION_CHOICE;
const OPTIONS fipsinstall_options[] = {
"Disable lower bound check for PBKDF2" },
{ "ecdh_cofactor_check", OPT_ECDH_COFACTOR_CHECK, '-',
"Enable Cofactor check for ECDH" },
+ { "defer_tests", OPT_DEFER_TESTS, '-', "Enables test deferral" },
OPT_SECTION("Input"),
{ "in", OPT_IN, '<', "Input config file, used when verifying" },
unsigned int x942kdf_key_check : 1;
unsigned int pbkdf2_lower_bound_check : 1;
unsigned int ecdh_cofactor_check : 1;
+ unsigned int defer_tests : 1;
} FIPS_OPTS;
/* Pedantic FIPS compliance */
1, /* x942kdf_key_check */
1, /* pbkdf2_lower_bound_check */
1, /* ecdh_cofactor_check */
+ 0, /* defer_tests */
};
/* Default FIPS settings for backward compatibility */
0, /* x942kdf_key_check */
1, /* pbkdf2_lower_bound_check */
0, /* ecdh_cofactor_check */
+ 0, /* defer_tests */
};
static int check_non_pedantic_fips(int pedantic, const char *name)
opts->ecdh_cofactor_check ? "1" : "0")
<= 0
|| !print_mac(out, OSSL_PROV_FIPS_PARAM_MODULE_MAC, module_mac,
- module_mac_len))
+ module_mac_len)
+ || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_DEFER_TESTS,
+ opts->defer_tests ? "1" : "0")
+ <= 0)
goto end;
if (install_mac != NULL
set_selftest_onload_option = 1;
fips_opts.self_test_onload = 0;
break;
+ case OPT_DEFER_TESTS:
+ fips_opts.defer_tests = 1;
+ break;
}
}
[B<-corrupt_desc> I<selftest_description>]
[B<-corrupt_type> I<selftest_type>]
[B<-config> I<parent_config>]
+[B<-defer_tests>]
=head1 DESCRIPTION
See L<config(5)> for further information on how to set up a provider section.
All other options are ignored if '-config' is used.
+=item B<-defer_tests>
+
+Configure the module to not run all self-tests at startup and allow tests
+execution to be deferred to the first time the algorithm to be tested is
+invoked.
+
=back
=head1 NOTES
B<-x942kdf_key_check>,
B<-ecdh_cofactor_check>
+The following options was added in OpenSSL 4.0:
+
+B<-defer_tests>
+
=head1 COPYRIGHT
Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved.
continuous test will return an error code if its continuous test fails. The
operation may then be retried if the error mode has not been triggered.
+=item B<defer-tests>
+
+If set to C<1>, the module will not run the self tests during initialization.
+Instead, the self tests will be run on demand when a particular algorithm is
+used.
+The default value of C<0> runs the self tests during initialization.
+
=item B<module-mac>
The calculated MAC of the FIPS provider file.
*/
#define OSSL_PROV_FIPS_PARAM_CONDITIONAL_ERRORS "conditional-errors"
+/*
+ * A boolean that determines if all the FIPS conditional self-test are executed
+ * at module startup or deferred and run only when an algorithm is invoked
+ */
+#define OSSL_PROV_FIPS_PARAM_DEFER_TESTS "defer-tests"
+
/* The following are provided for backwards compatibility */
#define OSSL_PROV_FIPS_PARAM_SECURITY_CHECKS OSSL_PROV_PARAM_SECURITY_CHECKS
#define OSSL_PROV_FIPS_PARAM_TLS1_PRF_EMS_CHECK OSSL_PROV_PARAM_TLS1_PRF_EMS_CHECK
*/
static int fips_get_params_from_core(FIPS_GLOBAL *fgbl)
{
- OSSL_PARAM core_params[32], *p = core_params;
+ OSSL_PARAM core_params[33], *p = core_params;
#define OSSL_FIPS_PARAM(structname, paramname) \
*p++ = OSSL_PARAM_construct_utf8_ptr( \
* record this test as invoked by the original test, for marking
* it later as also satisfied
*/
- if (st_all_tests[id].state == SELF_TEST_STATE_INIT)
+ if (st_all_tests[id].state == SELF_TEST_STATE_DEFER)
st_all_tests[id].state = SELF_TEST_STATE_IMPLICIT;
/*
* A self test is in progress for this thread so we let this
* test and marked it as passed
*/
switch (st_all_tests[id].state) {
- case SELF_TEST_STATE_INIT:
+ case SELF_TEST_STATE_DEFER:
break;
case SELF_TEST_STATE_PASSED:
ret = 1;
* Immediately mark it and return.
*/
if (ossl_fips_self_testing()) {
- if (st_all_tests[id].state == SELF_TEST_STATE_INIT)
+ if (st_all_tests[id].state == SELF_TEST_STATE_DEFER)
st_all_tests[id].state = SELF_TEST_STATE_IMPLICIT;
return 1;
}
OSSL_FIPS_PARAM(module_filename, OSSL_PROV_PARAM_CORE_MODULE_FILENAME)
OSSL_FIPS_PARAM(module_checksum_data, OSSL_PROV_FIPS_PARAM_MODULE_MAC)
OSSL_FIPS_PARAM(conditional_error_check, OSSL_PROV_FIPS_PARAM_CONDITIONAL_ERRORS)
+OSSL_FIPS_PARAM(defer_tests, OSSL_PROV_FIPS_PARAM_DEFER_TESTS)
goto end;
}
- if (on_demand_test)
- /* ensure all states are cleared so all tests are repeated */
- for (int i = 0; i < ST_ID_MAX; i++)
+ if ((st->defer_tests != NULL)
+ && strcmp(st->defer_tests, "1") == 0) {
+ /* Mark all non executed tests as deferred */
+ for (int i = 0; i < ST_ID_MAX; i++) {
+ if (st_all_tests[i].state == SELF_TEST_STATE_INIT)
+ st_all_tests[i].state = SELF_TEST_STATE_DEFER;
+ }
+ }
+
+ if (on_demand_test) {
+ /* ensure all states are cleared so all tests are forcibly
+ * repeated */
+ for (int i = 0; i < ST_ID_MAX; i++) {
st_all_tests[i].state = SELF_TEST_STATE_INIT;
+ }
+ }
- if (on_demand_test && !SELF_TEST_kats(ev, st->libctx)) {
+ if (!SELF_TEST_kats(ev, st->libctx)) {
ERR_raise(ERR_LIB_PROV, PROV_R_SELF_TEST_KAT_FAILURE);
goto end;
}
/* Used for continuous tests */
const char *conditional_error_check;
+ /* Used to decide whether to defer tests or not */
+ const char *defer_tests;
+
/* BIO callbacks supplied to the FIPS provider */
OSSL_FUNC_BIO_new_file_fn *bio_new_file_cb;
OSSL_FUNC_BIO_new_membuf_fn *bio_new_buffer_cb;
};
enum st_test_state {
- SELF_TEST_STATE_INIT = 0,
- SELF_TEST_STATE_IN_PROGRESS,
- SELF_TEST_STATE_PASSED,
- SELF_TEST_STATE_FAILED,
- SELF_TEST_STATE_IMPLICIT,
+ SELF_TEST_STATE_INIT = 0, /* Test has not been execute yet */
+ SELF_TEST_STATE_IN_PROGRESS, /* Test is currently being executed */
+ SELF_TEST_STATE_PASSED, /* Test is marked as passed */
+ SELF_TEST_STATE_FAILED, /* Test failed */
+ SELF_TEST_STATE_IMPLICIT, /* Marks test as implicitly handled */
+ SELF_TEST_STATE_DEFER, /* Like INIT, but mark test as deferred */
};
/* used to store raw parameters for keys and algorithms */
*/
switch (st_all_tests[id].state) {
case SELF_TEST_STATE_INIT:
+ case SELF_TEST_STATE_DEFER:
break;
case SELF_TEST_STATE_FAILED:
return 0;
}
for (i = 0; i < ST_ID_MAX; i++)
- if (!SELF_TEST_kats_execute(st, libctx, i, 0))
- ret = 0;
+ if (st_all_tests[i].state == SELF_TEST_STATE_INIT)
+ if (!SELF_TEST_kats_execute(st, libctx, i, 0))
+ ret = 0;
RAND_set0_private(libctx, saved_rand);
/* The above call will cause main_rand to be freed */
plan tests => 1;
# Create the $fipsmoduleconf file
-ok(run(app(['openssl', 'fipsinstall', '-pedantic',
+ok(run(app(['openssl', 'fipsinstall', '-pedantic', '-defer_tests',
'-module', $fipsmodule, '-provider_name', 'fips',
'-section_name', 'fips_sect', '-out', $fipsmoduleconf])),
"fips install");