Add wolfSSL_RAND_set_rand_method() and support for RAND_ callbacks.

This commit is contained in:
Kareem Abuobeid
2021-03-17 14:29:24 -07:00
committed by David Garske
parent e668b9b5d6
commit 1477af9a22
5 changed files with 340 additions and 29 deletions

205
src/ssl.c
View File

@ -153,6 +153,10 @@
#ifdef OPENSSL_EXTRA
/* Global pointer to constant BN on */
static WOLFSSL_BIGNUM* bn_one = NULL;
static const WOLFSSL_RAND_METHOD* rand_methods = NULL;
static int initRandMethMutex = 0;
static wolfSSL_Mutex rand_methods_mutex;
#endif
#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC)
@ -4953,6 +4957,14 @@ int wolfSSL_Init(void)
#endif
#ifdef OPENSSL_EXTRA
if (wc_InitMutex(&rand_methods_mutex) != 0) {
WOLFSSL_MSG("Bad Init Mutex rand methods");
return BAD_MUTEX_E;
}
else {
initRandMethMutex = 1;
}
if (wolfSSL_RAND_seed(NULL, 0) != WOLFSSL_SUCCESS) {
WOLFSSL_MSG("wolfSSL_RAND_Seed failed");
return WC_INIT_E;
@ -13219,6 +13231,18 @@ int wolfSSL_Cleanup(void)
#ifdef OPENSSL_EXTRA
wolfSSL_RAND_Cleanup();
if (wc_LockMutex(&rand_methods_mutex) != 0) {
WOLFSSL_MSG("Bad Lock Mutex rand methods");
return BAD_MUTEX_E;
}
rand_methods = NULL;
wc_UnLockMutex(&rand_methods_mutex);
if (wc_FreeMutex(&rand_methods_mutex) != 0)
ret = BAD_MUTEX_E;
else
initRandMethMutex = 0;
#endif
if (wolfCrypt_Cleanup() != 0) {
@ -17807,24 +17831,131 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
#endif
}
/* If a valid struct is provided with function pointers, will override
RAND_seed, bytes, cleanup, add, pseudo_bytes and status. If a NULL
pointer is passed in, it will cancel any previous function overrides.
Returns WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE on failure. */
int wolfSSL_RAND_set_rand_method(const WOLFSSL_RAND_METHOD *methods)
{
int ret = WOLFSSL_FAILURE;
if (initRandMethMutex == 0) {
if (wc_InitMutex(&rand_methods_mutex) != 0) {
WOLFSSL_MSG("Bad Init Mutex rand methods");
ret = BAD_MUTEX_E;
}
else {
initRandMethMutex = 1;
}
}
if (initRandMethMutex != 0) {
if (wc_LockMutex(&rand_methods_mutex) != 0) {
WOLFSSL_MSG("Lock rand methods mutex failed");
ret = BAD_MUTEX_E;
}
else {
rand_methods = methods;
wc_UnLockMutex(&rand_methods_mutex);
ret = WOLFSSL_SUCCESS;
}
}
return ret;
}
/* Sets func_ptr to a pointer to the given function func if it was set
by RAND_set_rand_method, or NULL if either it was not set,
or there was an error retreiving it.
Returns WOLFSSL_SUCCESS on success, otherwise returns an error code. */
static int GetRandFunction(RandFunction func, void** func_ptr)
{
int ret = WOLFSSL_FAILURE;
if (func_ptr == NULL) {
return WOLFSSL_FAILURE;
}
*func_ptr = NULL;
if (initRandMethMutex == 0) {
if (wc_InitMutex(&rand_methods_mutex) != 0) {
WOLFSSL_MSG("Bad Init Mutex rand methods");
ret = BAD_MUTEX_E;
}
else {
initRandMethMutex = 1;
}
}
if (initRandMethMutex != 0) {
if (wc_LockMutex(&rand_methods_mutex) != 0) {
WOLFSSL_MSG("Lock rand methods mutex failed");
ret = BAD_MUTEX_E;
}
else {
if (rand_methods != NULL && rand_methods->status != NULL) {
if (func == RAND_SEED) {
*func_ptr = rand_methods->seed;
}
else if (func == RAND_BYTES) {
*func_ptr = rand_methods->bytes;
}
else if (func == RAND_CLEANUP) {
*func_ptr = rand_methods->cleanup;
}
else if (func == RAND_ADD) {
*func_ptr = rand_methods->add;
}
else if (func == RAND_PSEUDORAND) {
*func_ptr = rand_methods->pseudorand;
}
else if (func == RAND_STATUS) {
*func_ptr = rand_methods->status;
}
}
wc_UnLockMutex(&rand_methods_mutex);
ret = WOLFSSL_SUCCESS;
}
}
return ret;
}
int wolfSSL_RAND_status(void)
{
return WOLFSSL_SUCCESS; /* wolfCrypt provides enough seed internally */
RandStatusMethod* randFunc = NULL;
if (GetRandFunction(RAND_STATUS, (void**)&randFunc)
!= WOLFSSL_SUCCESS) {
return WOLFSSL_FAILURE;
}
else if (randFunc != NULL) {
return randFunc();
}
return WOLFSSL_SUCCESS; /* wolfCrypt provides enough seed internally */
}
#ifndef NO_WOLFSSL_STUB
void wolfSSL_RAND_add(const void* add, int len, double entropy)
{
(void)add;
(void)len;
(void)entropy;
WOLFSSL_STUB("RAND_add");
RandAddMethod* randFunc = NULL;
if (GetRandFunction(RAND_ADD, (void**)&randFunc)
!= WOLFSSL_SUCCESS) {
return;
}
else if (randFunc != NULL) {
randFunc(add, len, entropy);
}
/* wolfSSL seeds/adds internally, use explicit RNG if you want
to take control */
return;
}
#endif
#ifndef NO_DES3
/* 0 on ok */
@ -31512,11 +31643,17 @@ static int wolfSSL_RAND_Init(void)
/* WOLFSSL_SUCCESS on ok */
int wolfSSL_RAND_seed(const void* seed, int len)
{
RandSeedMethod* randFunc = NULL;
WOLFSSL_MSG("wolfSSL_RAND_seed");
(void)seed;
(void)len;
if (GetRandFunction(RAND_SEED, (void**)&randFunc)
!= WOLFSSL_SUCCESS) {
return WOLFSSL_FAILURE;
}
else if (randFunc != NULL) {
return randFunc(seed, len);
}
return wolfSSL_RAND_Init();
}
@ -31821,22 +31958,40 @@ int wolfSSL_RAND_egd(const char* nm)
void wolfSSL_RAND_Cleanup(void)
{
RandCleanupMethod* randFunc = NULL;
WOLFSSL_ENTER("wolfSSL_RAND_Cleanup()");
if (GetRandFunction(RAND_CLEANUP, (void**)&randFunc)
== WOLFSSL_SUCCESS && randFunc != NULL) {
randFunc();
}
if (wc_LockMutex(&globalRNGMutex) != 0) {
WOLFSSL_MSG("Bad Lock Mutex rng");
return;
}
if (initGlobalRNG != 0) {
else if (initGlobalRNG != 0) {
wc_FreeRng(&globalRNG);
initGlobalRNG = 0;
}
wc_UnLockMutex(&globalRNGMutex);
return;
}
int wolfSSL_RAND_pseudo_bytes(unsigned char* buf, int num)
{
RandPseudorandMethod* randFunc = NULL;
if (GetRandFunction(RAND_PSEUDORAND, (void**)&randFunc)
!= WOLFSSL_SUCCESS) {
return WOLFSSL_FAILURE;
}
else if (randFunc != NULL) {
return randFunc(buf, num);
}
return wolfSSL_RAND_bytes(buf, num);
}
@ -31854,9 +32009,18 @@ int wolfSSL_RAND_bytes(unsigned char* buf, int num)
#endif
int used_global = 0;
int blockCount = 0;
RandBytesMethod* randFunc = NULL;
WOLFSSL_ENTER("wolfSSL_RAND_bytes");
if (GetRandFunction(RAND_BYTES, (void**)&randFunc)
!= WOLFSSL_SUCCESS) {
return WOLFSSL_FAILURE;
}
else if (randFunc != NULL) {
return randFunc(buf, num);
}
#ifdef WOLFSSL_SMALL_STACK
tmpRNG = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL, DYNAMIC_TYPE_RNG);
if (tmpRNG == NULL)
@ -31879,7 +32043,7 @@ int wolfSSL_RAND_bytes(unsigned char* buf, int num)
if (rng) {
/* handles size grater than RNG_MAX_BLOCK_LEN */
blockCount = num / RNG_MAX_BLOCK_LEN;
while(blockCount--) {
if((ret = wc_RNG_GenerateBlock(rng, buf, RNG_MAX_BLOCK_LEN) != 0)){
WOLFSSL_MSG("Bad wc_RNG_GenerateBlock");
@ -31888,10 +32052,10 @@ int wolfSSL_RAND_bytes(unsigned char* buf, int num)
num -= RNG_MAX_BLOCK_LEN;
buf += RNG_MAX_BLOCK_LEN;
}
if (ret == 0 && num)
ret = wc_RNG_GenerateBlock(rng, buf, num);
if (ret != 0)
WOLFSSL_MSG("Bad wc_RNG_GenerateBlock");
else
@ -45760,19 +45924,6 @@ int wolfSSL_FIPS_mode_set(int r)
}
#endif
#ifndef NO_WOLFSSL_STUB
int wolfSSL_RAND_set_rand_method(const void *meth)
{
(void) meth;
WOLFSSL_ENTER("wolfSSL_RAND_set_rand_method");
WOLFSSL_STUB("RAND_set_rand_method");
/* if implemented RAND_bytes and RAND_pseudo_bytes need updated
* those two functions will call the respective functions from meth */
return SSL_FAILURE;
}
#endif
int wolfSSL_CIPHER_get_bits(const WOLFSSL_CIPHER *c, int *alg_bits)
{
int ret = WOLFSSL_FAILURE;

View File

@ -307,6 +307,7 @@
#include <wolfssl/openssl/crypto.h>
#include <wolfssl/openssl/hmac.h>
#include <wolfssl/openssl/objects.h>
#include <wolfssl/openssl/rand.h>
#ifdef OPENSSL_ALL
#include <wolfssl/openssl/txt_db.h>
#include <wolfssl/openssl/lhash.h>
@ -30380,6 +30381,125 @@ static void test_wolfSSL_BUF(void)
#endif /* OPENSSL_EXTRA */
}
#if defined(OPENSSL_EXTRA)
static int stub_rand_seed(const void *buf, int num)
{
(void)buf;
(void)num;
return 123;
}
static int stub_rand_bytes(unsigned char *buf, int num)
{
(void)buf;
(void)num;
return 456;
}
static byte* was_stub_rand_cleanup_called(void)
{
static byte was_called = 0;
return &was_called;
}
static void stub_rand_cleanup(void)
{
byte* was_called = was_stub_rand_cleanup_called();
*was_called = 1;
return;
}
static byte* was_stub_rand_add_called(void)
{
static byte was_called = 0;
return &was_called;
}
static int stub_rand_add(const void *buf, int num, double entropy)
{
byte* was_called = was_stub_rand_add_called();
(void)buf;
(void)num;
(void)entropy;
*was_called = 1;
return 0;
}
static int stub_rand_pseudo_bytes(unsigned char *buf, int num)
{
(void)buf;
(void)num;
return 9876;
}
static int stub_rand_status(void)
{
return 5432;
}
#endif
static void test_wolfSSL_RAND_set_rand_method(void)
{
#if defined(OPENSSL_EXTRA)
WOLFSSL_RAND_METHOD rand_methods = {NULL, NULL, NULL, NULL, NULL, NULL};
unsigned char* buf = NULL;
int num = 0;
double entropy = 0;
byte* was_cleanup_called = was_stub_rand_cleanup_called();
byte* was_add_called = was_stub_rand_add_called();
printf(testingFmt, "wolfSSL_RAND_set_rand_method()");
AssertIntNE(wolfSSL_RAND_status(), 5432);
AssertIntEQ(*was_cleanup_called, 0);
wolfSSL_RAND_Cleanup();
AssertIntEQ(*was_cleanup_called, 0);
rand_methods.seed = &stub_rand_seed;
rand_methods.bytes = &stub_rand_bytes;
rand_methods.cleanup = &stub_rand_cleanup;
rand_methods.add = &stub_rand_add;
rand_methods.pseudorand = &stub_rand_pseudo_bytes;
rand_methods.status = &stub_rand_status;
AssertIntEQ(wolfSSL_RAND_set_rand_method(&rand_methods), SSL_SUCCESS);
AssertIntEQ(wolfSSL_RAND_seed(buf, num), 123);
AssertIntEQ(wolfSSL_RAND_bytes(buf, num), 456);
AssertIntEQ(wolfSSL_RAND_pseudo_bytes(buf, num), 9876);
AssertIntEQ(wolfSSL_RAND_status(), 5432);
AssertIntEQ(*was_add_called, 0);
/* The function pointer for RAND_add returns int, but RAND_add itself returns void. */
wolfSSL_RAND_add(buf, num, entropy);
AssertIntEQ(*was_add_called, 1);
was_add_called = 0;
AssertIntEQ(*was_cleanup_called, 0);
wolfSSL_RAND_Cleanup();
AssertIntEQ(*was_cleanup_called, 1);
*was_cleanup_called = 0;
AssertIntEQ(wolfSSL_RAND_set_rand_method(NULL), SSL_SUCCESS);
AssertIntNE(wolfSSL_RAND_status(), 5432);
AssertIntEQ(*was_cleanup_called, 0);
wolfSSL_RAND_Cleanup();
AssertIntEQ(*was_cleanup_called, 0);
printf(resultFmt, passed);
#endif
}
static void test_wolfSSL_RAND_bytes(void)
{
#if defined(OPENSSL_EXTRA)
@ -41500,6 +41620,7 @@ void ApiTest(void)
test_wolfSSL_CTX_set_srp_password();
test_wolfSSL_CTX_set_ecdh_auto();
test_wolfSSL_THREADID_hash();
test_wolfSSL_RAND_set_rand_method();
test_wolfSSL_RAND_bytes();
test_wolfSSL_pseudo_rand();
test_wolfSSL_PKCS8_Compat();

View File

@ -4,5 +4,7 @@
#undef HAVE_OPENSSL_ENGINE_H
#define ENGINE_load_builtin_engines() /*ENGINE_load_builtin_engines not needed*/
/* ENGINE_load_builtin_engines not needed, as all builtin engines are already
loaded into memory and used on startup. */
#define ENGINE_load_builtin_engines()

View File

@ -24,4 +24,6 @@
#include <wolfssl/openssl/ssl.h>
#include <wolfssl/wolfcrypt/random.h>
typedef WOLFSSL_RAND_METHOD RAND_METHOD;
#define RAND_set_rand_method wolfSSL_RAND_set_rand_method

View File

@ -639,6 +639,41 @@ struct WOLFSSL_X509_STORE_CTX {
typedef char* WOLFSSL_STRING;
/* seed = Data to mix into the random generator.
len = Number of bytes to mix from seed. */
typedef int RandSeedMethod(const void* seed, int len);
/* buf = Buffer to store random bytes in.
len = Number of bytes to store in buf. */
typedef int RandBytesMethod(unsigned char* buf, int len);
typedef void RandCleanupMethod(void);
/* add = Data to mix into the random generator.
len = Number of bytes to mix from add.
entropy = Estimate of randomness contained in seed.
Should be between 0 and len. */
typedef int RandAddMethod(const void* add, int len, double entropy);
/* buf = Buffer to store pseudorandom bytes in.
len = Number of bytes to store in buf. */
typedef int RandPseudorandMethod(unsigned char *buf, int len);
typedef int RandStatusMethod(void);
typedef struct WOLFSSL_RAND_METHOD {
RandSeedMethod* seed;
RandBytesMethod* bytes;
RandCleanupMethod* cleanup;
RandAddMethod* add;
RandPseudorandMethod* pseudorand;
RandStatusMethod* status;
} WOLFSSL_RAND_METHOD;
typedef enum RandFunction {
RAND_SEED,
RAND_BYTES,
RAND_CLEANUP,
RAND_ADD,
RAND_PSEUDORAND,
RAND_STATUS
} RandFunction;
/* Valid Alert types from page 16/17
* Add alert string to the function wolfSSL_alert_type_string_long in src/ssl.c
*/
@ -3769,7 +3804,7 @@ WOLFSSL_API int wolfSSL_FIPS_mode(void);
WOLFSSL_API int wolfSSL_FIPS_mode_set(int r);
WOLFSSL_API int wolfSSL_RAND_set_rand_method(const void *meth);
WOLFSSL_API int wolfSSL_RAND_set_rand_method(const WOLFSSL_RAND_METHOD *methods);
WOLFSSL_API int wolfSSL_CIPHER_get_bits(const WOLFSSL_CIPHER *c, int *alg_bits);