Add a test for performing work in multiple concurrent threads

We test both the default provider and the fips provider

Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/13660)
This commit is contained in:
Matt Caswell 2020-12-10 15:39:58 +00:00
parent f6b72c7d75
commit ae95a40e8d
2 changed files with 188 additions and 2 deletions

View File

@ -8,5 +8,35 @@
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");
}

View File

@ -11,9 +11,15 @@
# 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;
@ -254,16 +260,166 @@ static int test_atomic(void)
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;
}