diff --git a/test/build.info b/test/build.info index 58d75be5d4..183c972602 100644 --- a/test/build.info +++ b/test/build.info @@ -47,7 +47,7 @@ IF[{- !$disabled{tests} -}] bio_callback_test bio_memleak_test bio_core_test param_build_test \ bioprinttest sslapitest dtlstest sslcorrupttest \ bio_enc_test pkey_meth_test pkey_meth_kdf_test evp_kdf_test uitest \ - cipherbytes_test \ + cipherbytes_test threadstest_fips \ asn1_encode_test asn1_decode_test asn1_string_table_test \ x509_time_test x509_dup_cert_test x509_check_cert_pkey_test \ recordlentest drbgtest rand_status_test sslbuffertest \ @@ -271,6 +271,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[threadstest]=../include ../apps/include DEPEND[threadstest]=../libcrypto libtestutil.a + SOURCE[threadstest_fips]=threadstest_fips.c + INCLUDE[threadstest_fips]=../include ../apps/include + DEPEND[threadstest_fips]=../libcrypto libtestutil.a + SOURCE[afalgtest]=afalgtest.c INCLUDE[afalgtest]=../include ../apps/include DEPEND[afalgtest]=../libcrypto libtestutil.a diff --git a/test/recipes/90-test_threads.t b/test/recipes/90-test_threads.t index a841a4b2f5..651fa805d5 100644 --- a/test/recipes/90-test_threads.t +++ b/test/recipes/90-test_threads.t @@ -23,7 +23,7 @@ my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0); my $config_path = abs_path(srctop_file("test", $no_fips ? "default.cnf" : "default-and-fips.cnf")); -plan tests => 1; +plan tests => 2; if ($no_fips) { ok(run(test(["threadstest", "-config", $config_path, data_dir()])), @@ -32,3 +32,25 @@ if ($no_fips) { ok(run(test(["threadstest", "-fips", "-config", $config_path, data_dir()])), "running test_threads with FIPS"); } + +# Merge the configuration files into one filtering the contents so the failure +# condition is reproducable. A working FIPS configuration without the install +# status is required. + +open CFGBASE, '<', $config_path; +open CFGINC, '<', bldtop_file('/providers/fipsmodule.cnf'); +open CFGOUT, '>', 'thread.cnf'; + +while () { + print CFGOUT unless m/^[.]include/; +} +close CFGBASE; +print CFGOUT "\n\n"; +while () { + print CFGOUT unless m/^install-status/; +} +close CFGINC; +close CFGOUT; + +$ENV{OPENSSL_CONF} = 'thread.cnf'; +ok(run(test(["threadstest_fips"])), "running test_threads_fips"); diff --git a/test/threadstest.c b/test/threadstest.c index 359b330024..4f05cbec54 100644 --- a/test/threadstest.c +++ b/test/threadstest.c @@ -20,77 +20,12 @@ #include #include #include "testutil.h" +#include "threadstest.h" static int do_fips = 0; static char *privkey; static char *config_file = NULL; -#if !defined(OPENSSL_THREADS) || defined(CRYPTO_TDEBUG) - -typedef unsigned int thread_t; - -static int run_thread(thread_t *t, void (*f)(void)) -{ - f(); - return 1; -} - -static int wait_for_thread(thread_t thread) -{ - return 1; -} - -#elif defined(OPENSSL_SYS_WINDOWS) - -typedef HANDLE thread_t; - -static DWORD WINAPI thread_run(LPVOID arg) -{ - void (*f)(void); - - *(void **) (&f) = arg; - - f(); - return 0; -} - -static int run_thread(thread_t *t, void (*f)(void)) -{ - *t = CreateThread(NULL, 0, thread_run, *(void **) &f, 0, NULL); - return *t != NULL; -} - -static int wait_for_thread(thread_t thread) -{ - return WaitForSingleObject(thread, INFINITE) == 0; -} - -#else - -typedef pthread_t thread_t; - -static void *thread_run(void *arg) -{ - void (*f)(void); - - *(void **) (&f) = arg; - - f(); - return NULL; -} - -static int run_thread(thread_t *t, void (*f)(void)) -{ - return pthread_create(t, NULL, thread_run, *(void **) &f) == 0; -} - -static int wait_for_thread(thread_t thread) -{ - return pthread_join(thread, NULL) == 0; -} - -#endif - static int test_lock(void) { CRYPTO_RWLOCK *lock = CRYPTO_THREAD_lock_new(); diff --git a/test/threadstest.h b/test/threadstest.h new file mode 100644 index 0000000000..8bdedd7052 --- /dev/null +++ b/test/threadstest.h @@ -0,0 +1,82 @@ +/* + * Copyright 2021 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 + */ + +#if defined(_WIN32) +# include +#endif + +#include +#include "testutil.h" + +#if !defined(OPENSSL_THREADS) || defined(CRYPTO_TDEBUG) + +typedef unsigned int thread_t; + +static int run_thread(thread_t *t, void (*f)(void)) +{ + f(); + return 1; +} + +static int wait_for_thread(thread_t thread) +{ + return 1; +} + +#elif defined(OPENSSL_SYS_WINDOWS) + +typedef HANDLE thread_t; + +static DWORD WINAPI thread_run(LPVOID arg) +{ + void (*f)(void); + + *(void **) (&f) = arg; + + f(); + return 0; +} + +static int run_thread(thread_t *t, void (*f)(void)) +{ + *t = CreateThread(NULL, 0, thread_run, *(void **) &f, 0, NULL); + return *t != NULL; +} + +static int wait_for_thread(thread_t thread) +{ + return WaitForSingleObject(thread, INFINITE) == 0; +} + +#else + +typedef pthread_t thread_t; + +static void *thread_run(void *arg) +{ + void (*f)(void); + + *(void **) (&f) = arg; + + f(); + return NULL; +} + +static int run_thread(thread_t *t, void (*f)(void)) +{ + return pthread_create(t, NULL, thread_run, *(void **) &f) == 0; +} + +static int wait_for_thread(thread_t thread) +{ + return pthread_join(thread, NULL) == 0; +} + +#endif + diff --git a/test/threadstest_fips.c b/test/threadstest_fips.c new file mode 100644 index 0000000000..b38221d4ed --- /dev/null +++ b/test/threadstest_fips.c @@ -0,0 +1,49 @@ +/* + * Copyright 2021 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 + */ + +#if defined(_WIN32) +# include +#endif + +#include "testutil.h" +#include "threadstest.h" + +static int success; + +static void thread_fips_rand_fetch(void) +{ + EVP_MD *md; + + if (!TEST_true(md = EVP_MD_fetch(NULL, "SHA2-256", NULL))) + success = 0; + EVP_MD_free(md); +} + +static int test_fips_rand_leak(void) +{ + thread_t thread; + + success = 1; + + if (!TEST_true(run_thread(&thread, thread_fips_rand_fetch))) + return 0; + if (!TEST_true(wait_for_thread(thread))) + return 0; + return TEST_true(success); +} + +int setup_tests(void) +{ + /* + * This test MUST be run first. Once the default library context is set + * up, this test will always pass. + */ + ADD_TEST(test_fips_rand_leak); + return 1; +}