test: add test case to reliably reproduce RAND leak during POST

The FIPS provider leaks a RAND if the POST is run at initialisation time.
This test case reliably reproduces this event.

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/15278)
This commit is contained in:
Pauli 2021-05-14 15:41:14 +10:00
parent b6f0f050fd
commit 235776b2c7
5 changed files with 160 additions and 68 deletions

View File

@ -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

View File

@ -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 (<CFGBASE>) {
print CFGOUT unless m/^[.]include/;
}
close CFGBASE;
print CFGOUT "\n\n";
while (<CFGINC>) {
print CFGOUT unless m/^install-status/;
}
close CFGINC;
close CFGOUT;
$ENV{OPENSSL_CONF} = 'thread.cnf';
ok(run(test(["threadstest_fips"])), "running test_threads_fips");

View File

@ -20,77 +20,12 @@
#include <openssl/aes.h>
#include <openssl/rsa.h>
#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();

82
test/threadstest.h Normal file
View File

@ -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 <windows.h>
#endif
#include <string.h>
#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

49
test/threadstest_fips.c Normal file
View File

@ -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 <windows.h>
#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;
}