diff --git a/src/ssl.c b/src/ssl.c index 4fb9ebdb0..b37ad8e0b 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -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; diff --git a/tests/api.c b/tests/api.c index 37cdc2bd4..83273c911 100644 --- a/tests/api.c +++ b/tests/api.c @@ -307,6 +307,7 @@ #include #include #include + #include #ifdef OPENSSL_ALL #include #include @@ -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(); diff --git a/wolfssl/openssl/engine.h b/wolfssl/openssl/engine.h index e4a1ff193..ba147ff74 100644 --- a/wolfssl/openssl/engine.h +++ b/wolfssl/openssl/engine.h @@ -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() diff --git a/wolfssl/openssl/rand.h b/wolfssl/openssl/rand.h index 25d1419e2..11af818f6 100644 --- a/wolfssl/openssl/rand.h +++ b/wolfssl/openssl/rand.h @@ -24,4 +24,6 @@ #include #include +typedef WOLFSSL_RAND_METHOD RAND_METHOD; + #define RAND_set_rand_method wolfSSL_RAND_set_rand_method diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index a6697e8bc..4f813a279 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -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);