use OpenSSL::Test::Simple;
+use OpenSSL::Test qw/:DEFAULT srctop_file srctop_dir bldtop_dir bldtop_file/;
+use OpenSSL::Test::Utils;
+use Cwd qw(abs_path);
-simple_test("test_threads", "threadstest");
+BEGIN {
+setup("test_threads");
+}
+
+use lib srctop_dir('Configurations');
+use lib bldtop_dir('.');
+use platform;
+
+my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0);
+
+
+plan tests => 1 + ($no_fips ? 0 : 1);
+
+if (!$no_fips) {
+ my $infile = bldtop_file('providers', platform->dso('fips'));
+ ok(run(app(['openssl', 'fipsinstall',
+ '-out', bldtop_file('providers', 'fipsmodule.cnf'),
+ '-module', $infile])),
+ "fipsinstall");
+}
+
+if ($no_fips) {
+ $ENV{OPENSSL_CONF} = abs_path(srctop_file("test", "default.cnf"));
+ ok(run(test(["threadstest"])), "running test_threads");
+} else {
+ $ENV{OPENSSL_CONF} = abs_path(srctop_file("test", "default-and-fips.cnf"));
+ ok(run(test(["threadstest", "-fips"])), "running test_threads");
+}
# include <windows.h>
#endif
+#include <string.h>
#include <openssl/crypto.h>
+#include <openssl/evp.h>
+#include <openssl/aes.h>
+#include <openssl/rsa.h>
#include "testutil.h"
+static int do_fips = 0;
+
#if !defined(OPENSSL_THREADS) || defined(CRYPTO_TDEBUG)
typedef unsigned int thread_t;
testresult = 1;
err:
-
CRYPTO_THREAD_lock_free(lock);
return testresult;
}
+static OSSL_LIB_CTX *multi_libctx = NULL;
+static int multi_success;
+
+static void thread_multi_worker(void)
+{
+ EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
+ EVP_MD *md = EVP_MD_fetch(multi_libctx, "SHA2-256", NULL);
+ EVP_CIPHER_CTX *cipherctx = EVP_CIPHER_CTX_new();
+ EVP_CIPHER *ciph = EVP_CIPHER_fetch(multi_libctx, "AES-128-CBC", NULL);
+ const char *message = "Hello World";
+ size_t messlen = strlen(message);
+ /* Should be big enough for encryption output too */
+ unsigned char out[EVP_MAX_MD_SIZE];
+ const unsigned char key[AES_BLOCK_SIZE] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f
+ };
+ const unsigned char iv[AES_BLOCK_SIZE] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f
+ };
+ unsigned int mdoutl;
+ int ciphoutl;
+ EVP_PKEY_CTX *pctx = NULL;
+ EVP_PKEY *pkey = NULL;
+ int testresult = 0;
+ int i, isfips;
+
+ isfips = OSSL_PROVIDER_available(multi_libctx, "fips");
+
+ if (!TEST_ptr(mdctx)
+ || !TEST_ptr(md)
+ || !TEST_ptr(cipherctx)
+ || !TEST_ptr(ciph))
+ goto err;
+
+ /* Do some work */
+ for (i = 0; i < 5; i++) {
+ if (!TEST_true(EVP_DigestInit_ex(mdctx, md, NULL))
+ || !TEST_true(EVP_DigestUpdate(mdctx, message, messlen))
+ || !TEST_true(EVP_DigestFinal(mdctx, out, &mdoutl)))
+ goto err;
+ }
+ for (i = 0; i < 5; i++) {
+ if (!TEST_true(EVP_EncryptInit_ex(cipherctx, ciph, NULL, key, iv))
+ || !TEST_true(EVP_EncryptUpdate(cipherctx, out, &ciphoutl,
+ (unsigned char *)message,
+ messlen))
+ || !TEST_true(EVP_EncryptFinal(cipherctx, out, &ciphoutl)))
+ goto err;
+ }
+
+ pctx = EVP_PKEY_CTX_new_from_name(multi_libctx, "RSA", NULL);
+ if (!TEST_ptr(pctx)
+ || !TEST_int_gt(EVP_PKEY_keygen_init(pctx), 0)
+ /*
+ * We want the test to run quickly - not securely. Therefore we
+ * use an insecure bit length where we can (512). In the FIPS
+ * module though we must use a longer length.
+ */
+ || !TEST_int_gt(EVP_PKEY_CTX_set_rsa_keygen_bits(pctx,
+ isfips ? 2048 : 512),
+ 0)
+ || !TEST_int_gt(EVP_PKEY_keygen(pctx, &pkey), 0))
+ goto err;
+
+ testresult = 1;
+ err:
+ EVP_MD_CTX_free(mdctx);
+ EVP_MD_free(md);
+ EVP_CIPHER_CTX_free(cipherctx);
+ EVP_CIPHER_free(ciph);
+ EVP_PKEY_CTX_free(pctx);
+ EVP_PKEY_free(pkey);
+ if (!testresult)
+ multi_success = 0;
+}
+
+/*
+ * Do work in multiple worker threads at the same time.
+ * Test 0: Use the default provider
+ * Test 1: Use the fips provider
+ */
+static int test_multi(int idx)
+{
+ thread_t thread1, thread2;
+ int testresult = 0;
+ OSSL_PROVIDER *prov = NULL;
+
+ if (idx == 1 && !do_fips)
+ return TEST_skip("FIPS not supported");
+
+ multi_success = 1;
+ multi_libctx = OSSL_LIB_CTX_new();
+ if (!TEST_ptr(multi_libctx))
+ goto err;
+ prov = OSSL_PROVIDER_load(multi_libctx, (idx == 0) ? "default" : "fips");
+ if (!TEST_ptr(prov))
+ goto err;
+
+ if (!TEST_true(run_thread(&thread1, thread_multi_worker))
+ || !TEST_true(run_thread(&thread2, thread_multi_worker)))
+ goto err;
+
+ thread_multi_worker();
+
+ if (!TEST_true(wait_for_thread(thread1))
+ || !TEST_true(wait_for_thread(thread2))
+ || !TEST_true(multi_success))
+ goto err;
+
+ testresult = 1;
+
+ err:
+ OSSL_PROVIDER_unload(prov);
+ OSSL_LIB_CTX_free(multi_libctx);
+ return testresult;
+}
+
+typedef enum OPTION_choice {
+ OPT_ERR = -1,
+ OPT_EOF = 0,
+ OPT_FIPS,
+ OPT_TEST_ENUM
+} OPTION_CHOICE;
+
+const OPTIONS *test_get_options(void)
+{
+ static const OPTIONS options[] = {
+ OPT_TEST_OPTIONS_DEFAULT_USAGE,
+ { "fips", OPT_FIPS, '-', "Test the FIPS provider" },
+ { NULL }
+ };
+ return options;
+}
+
int setup_tests(void)
{
+ OPTION_CHOICE o;
+
+ while ((o = opt_next()) != OPT_EOF) {
+ switch (o) {
+ case OPT_FIPS:
+ do_fips = 1;
+ break;
+ case OPT_TEST_CASES:
+ break;
+ default:
+ return 0;
+ }
+ }
+
ADD_TEST(test_lock);
ADD_TEST(test_once);
ADD_TEST(test_thread_local);
ADD_TEST(test_atomic);
+ ADD_ALL_TESTS(test_multi, 2);
return 1;
}