diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index e63918860..fd2cbb3d4 100644 --- a/.github/workflows/os-check.yml +++ b/.github/workflows/os-check.yml @@ -48,6 +48,9 @@ jobs: '--enable-sniffer --enable-curve25519 --enable-curve448 --enable-enckeys CFLAGS=-DWOLFSSL_DH_EXTRA', '--enable-dtls --enable-dtls13 --enable-dtls-frag-ch --enable-dtls-mtu CPPFLAGS=-DWOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS', + '--enable-opensslall --enable-opensslextra CPPFLAGS=-DWC_RNG_SEED_CB', + '--enable-opensslall --enable-opensslextra + CPPFLAGS='-DWC_RNG_SEED_CB -DWOLFSSL_NO_GETPID'', ] name: make check if: github.repository_owner == 'wolfssl' diff --git a/CMakeLists.txt b/CMakeLists.txt index 688d9dc4e..a33712f03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,6 +124,7 @@ check_function_exists("memset" HAVE_MEMSET) check_function_exists("socket" HAVE_SOCKET) check_function_exists("strftime" HAVE_STRFTIME) check_function_exists("__atomic_fetch_add" HAVE_C___ATOMIC) +check_function_exists("getpid" HAVE_GETPID) include(CheckSymbolExists) check_symbol_exists(isascii "ctype.h" HAVE_ISASCII) diff --git a/configure.ac b/configure.ac index e0b6d769c..7da6c7647 100644 --- a/configure.ac +++ b/configure.ac @@ -129,8 +129,8 @@ AC_CHECK_HEADER(assert.h, [AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSL_HAVE_ASSERT_H"],[ # check if functions of interest are linkable, but also check if # they're declared by the expected headers, and if not, supersede the # unusable positive from AC_CHECK_FUNCS(). -AC_CHECK_FUNCS([gethostbyname getaddrinfo gettimeofday gmtime_r gmtime_s inet_ntoa memset socket strftime atexit isascii]) -AC_CHECK_DECLS([gethostbyname, getaddrinfo, gettimeofday, gmtime_r, gmtime_s, inet_ntoa, memset, socket, strftime, atexit, isascii], [], [ +AC_CHECK_FUNCS([gethostbyname getaddrinfo gettimeofday gmtime_r gmtime_s inet_ntoa memset socket strftime atexit isascii getpid]) +AC_CHECK_DECLS([gethostbyname, getaddrinfo, gettimeofday, gmtime_r, gmtime_s, inet_ntoa, memset, socket, strftime, atexit, isascii, getpid], [], [ if test "$(eval echo \$"$(eval 'echo ac_cv_func_${as_decl_name}')")" = "yes" then AC_MSG_NOTICE([ note: earlier check for $(eval 'echo ${as_decl_name}') superseded.]) diff --git a/src/ssl.c b/src/ssl.c index bb1d1176c..80589ad5c 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -25500,6 +25500,13 @@ static int wolfSSL_RAND_InitMutex(void) #ifdef OPENSSL_EXTRA +#if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) && \ + defined(HAVE_FIPS) && FIPS_VERSION3_LT(6,0,0) +/* In older FIPS bundles add check for reseed here since it does not exist in + * the older random.c certified files. */ +static pid_t currentRandPid = 0; +#endif + /* Checks if the global RNG has been created. If not then one is created. * * Returns WOLFSSL_SUCCESS when no error is encountered. @@ -25512,6 +25519,10 @@ int wolfSSL_RAND_Init(void) if (initGlobalRNG == 0) { ret = wc_InitRng(&globalRNG); if (ret == 0) { + #if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) && \ + defined(HAVE_FIPS) && FIPS_VERSION3_LT(6,0,0) + currentRandPid = getpid(); + #endif initGlobalRNG = 1; ret = WOLFSSL_SUCCESS; } @@ -25946,8 +25957,8 @@ int wolfSSL_RAND_pseudo_bytes(unsigned char* buf, int num) return ret; } -/* returns WOLFSSL_SUCCESS if the bytes generated are valid otherwise - * WOLFSSL_FAILURE */ +/* returns WOLFSSL_SUCCESS (1) if the bytes generated are valid otherwise 0 + * on failure */ int wolfSSL_RAND_bytes(unsigned char* buf, int num) { int ret = 0; @@ -25989,6 +26000,26 @@ int wolfSSL_RAND_bytes(unsigned char* buf, int num) * have the lock. */ if (initGlobalRNG) { + #if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) && \ + defined(HAVE_FIPS) && FIPS_VERSION3_LT(6,0,0) + pid_t p; + + p = getpid(); + if (p != currentRandPid) { + wc_UnLockMutex(&globalRNGMutex); + if (wolfSSL_RAND_poll() != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Issue with check pid and reseed"); + ret = WOLFSSL_FAILURE; + } + + /* reclaim lock after wolfSSL_RAND_poll */ + if (wc_LockMutex(&globalRNGMutex) != 0) { + WOLFSSL_MSG("Bad Lock Mutex rng"); + return ret; + } + currentRandPid = p; + } + #endif rng = &globalRNG; used_global = 1; } @@ -26065,6 +26096,11 @@ int wolfSSL_RAND_poll(void) } else { #ifdef HAVE_HASHDRBG + if (wc_LockMutex(&globalRNGMutex) != 0) { + WOLFSSL_MSG("Bad Lock Mutex rng"); + return ret; + } + ret = wc_RNG_DRBG_Reseed(&globalRNG, entropy, entropy_sz); if (ret != 0) { WOLFSSL_MSG("Error reseeding DRBG"); @@ -26073,6 +26109,7 @@ int wolfSSL_RAND_poll(void) else { ret = WOLFSSL_SUCCESS; } + wc_UnLockMutex(&globalRNGMutex); #else WOLFSSL_MSG("RAND_poll called with HAVE_HASHDRBG not set"); ret = WOLFSSL_FAILURE; diff --git a/tests/api.c b/tests/api.c index 26667ce1c..fb813f98d 100644 --- a/tests/api.c +++ b/tests/api.c @@ -33158,6 +33158,12 @@ static int test_wolfSSL_RAND_bytes(void) const int size4 = RNG_MAX_BLOCK_LEN * 4; /* in bytes */ int max_bufsize; byte *my_buf = NULL; +#if defined(HAVE_GETPID) + byte seed[16] = {0}; + byte randbuf[8] = {0}; + int pipefds[2] = {0}; + pid_t pid = 0; +#endif /* sanity check */ ExpectIntEQ(RAND_bytes(NULL, 16), 0); @@ -33177,6 +33183,46 @@ static int test_wolfSSL_RAND_bytes(void) ExpectIntEQ(RAND_bytes(my_buf, size3), 1); ExpectIntEQ(RAND_bytes(my_buf, size4), 1); +#if defined(OPENSSL_EXTRA) && defined(HAVE_GETPID) + XMEMSET(seed, 0, sizeof(seed)); + RAND_cleanup(); + + /* No global methods set. */ + ExpectIntEQ(RAND_seed(seed, sizeof(seed)), 1); + + ExpectIntEQ(pipe(pipefds), 0); + pid = fork(); + ExpectIntGE(pid, 0); + if (pid == 0) { + ssize_t n_written = 0; + + /* Child process. */ + close(pipefds[0]); + RAND_bytes(randbuf, sizeof(randbuf)); + n_written = write(pipefds[1], randbuf, sizeof(randbuf)); + close(pipefds[1]); + exit(n_written == sizeof(randbuf) ? 0 : 1); + } + else { + /* Parent process. */ + word64 childrand64 = 0; + int waitstatus = 0; + + close(pipefds[1]); + ExpectIntEQ(RAND_bytes(randbuf, sizeof(randbuf)), 1); + ExpectIntEQ(read(pipefds[0], &childrand64, sizeof(childrand64)), + sizeof(childrand64)); + #ifdef WOLFSSL_NO_GETPID + ExpectBufEQ(randbuf, &childrand64, sizeof(randbuf)); + #else + ExpectBufNE(randbuf, &childrand64, sizeof(randbuf)); + #endif + close(pipefds[0]); + waitpid(pid, &waitstatus, 0); + } + RAND_cleanup(); +#endif + XFREE(my_buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif return EXPECT_RESULT(); @@ -33209,50 +33255,60 @@ static int test_wolfSSL_RAND(void) } +#if defined(WC_RNG_SEED_CB) && defined(OPENSSL_EXTRA) +static int wc_DummyGenerateSeed(OS_Seed* os, byte* output, word32 sz) +{ + word32 i; + for (i = 0; i < sz; i++ ) + output[i] = (byte)i; + + (void)os; + + return 0; +} +#endif /* WC_RNG_SEED_CB */ + + static int test_wolfSSL_RAND_poll(void) { EXPECT_DECLS; -#if defined(OPENSSL_EXTRA) && defined(__linux__) - byte seed[16] = {0}; - byte randbuf[8] = {0}; - int pipefds[2] = {0}; - pid_t pid = 0; +#if defined(OPENSSL_EXTRA) + byte seed[16]; + byte rand1[16]; +#ifdef WC_RNG_SEED_CB + byte rand2[16]; +#endif XMEMSET(seed, 0, sizeof(seed)); - - /* No global methods set. */ ExpectIntEQ(RAND_seed(seed, sizeof(seed)), 1); + ExpectIntEQ(RAND_poll(), 1); + ExpectIntEQ(RAND_bytes(rand1, 16), 1); + RAND_cleanup(); - ExpectIntEQ(pipe(pipefds), 0); - pid = fork(); - ExpectIntGE(pid, 0); - if (pid == 0) - { - ssize_t n_written = 0; +#ifdef WC_RNG_SEED_CB + /* Test with custom seed and poll */ + wc_SetSeed_Cb(wc_DummyGenerateSeed); - /* Child process. */ - close(pipefds[0]); - RAND_poll(); - RAND_bytes(randbuf, sizeof(randbuf)); - n_written = write(pipefds[1], randbuf, sizeof(randbuf)); - close(pipefds[1]); - exit(n_written == sizeof(randbuf) ? 0 : 1); - } - else - { - /* Parent process. */ - word64 childrand64 = 0; - int waitstatus = 0; + ExpectIntEQ(RAND_seed(seed, sizeof(seed)), 1); + ExpectIntEQ(RAND_bytes(rand1, 16), 1); + RAND_cleanup(); - close(pipefds[1]); - ExpectIntEQ(RAND_poll(), 1); - ExpectIntEQ(RAND_bytes(randbuf, sizeof(randbuf)), 1); - ExpectIntEQ(read(pipefds[0], &childrand64, sizeof(childrand64)), sizeof(childrand64)); - ExpectBufNE(randbuf, &childrand64, sizeof(randbuf)); - close(pipefds[0]); - waitpid(pid, &waitstatus, 0); - } + /* test that the same value is generated twice with dummy seed function */ + ExpectIntEQ(RAND_seed(seed, sizeof(seed)), 1); + ExpectIntEQ(RAND_bytes(rand2, 16), 1); + ExpectIntEQ(XMEMCMP(rand1, rand2, 16), 0); + RAND_cleanup(); + + /* test that doing a poll is reseeding RNG */ + ExpectIntEQ(RAND_seed(seed, sizeof(seed)), 1); + ExpectIntEQ(RAND_poll(), 1); + ExpectIntEQ(RAND_bytes(rand2, 16), 1); + ExpectIntNE(XMEMCMP(rand1, rand2, 16), 0); + + /* reset the seed function used */ + wc_SetSeed_Cb(wc_GenerateSeed); +#endif RAND_cleanup(); ExpectIntEQ(RAND_egd(NULL), -1); diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index 311d5a71c..3bc5f2d76 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -1640,6 +1640,9 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, #else rng->heap = heap; #endif +#if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) + rng->pid = getpid(); +#endif #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) rng->devId = devId; #if defined(WOLF_CRYPTO_CB) @@ -1895,6 +1898,63 @@ int wc_InitRngNonce_ex(WC_RNG* rng, byte* nonce, word32 nonceSz, return _InitRng(rng, nonce, nonceSz, heap, devId); } +#ifdef HAVE_HASHDRBG +static int PollAndReSeed(WC_RNG* rng) +{ + int ret = DRBG_NEED_RESEED; + int devId = INVALID_DEVID; +#if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) + devId = rng->devId; +#endif + if (wc_RNG_HealthTestLocal(1, rng->heap, devId) == 0) { + #ifndef WOLFSSL_SMALL_STACK + byte newSeed[SEED_SZ + SEED_BLOCK_SZ]; + ret = DRBG_SUCCESS; + #else + byte* newSeed = (byte*)XMALLOC(SEED_SZ + SEED_BLOCK_SZ, rng->heap, + DYNAMIC_TYPE_SEED); + ret = (newSeed == NULL) ? MEMORY_E : DRBG_SUCCESS; + #endif + if (ret == DRBG_SUCCESS) { + #ifdef WC_RNG_SEED_CB + if (seedCb == NULL) { + ret = DRBG_NO_SEED_CB; + } + else { + ret = seedCb(&rng->seed, newSeed, SEED_SZ + SEED_BLOCK_SZ); + if (ret != 0) { + ret = DRBG_FAILURE; + } + } + #else + ret = wc_GenerateSeed(&rng->seed, newSeed, + SEED_SZ + SEED_BLOCK_SZ); + #endif + if (ret != 0) + ret = DRBG_FAILURE; + } + if (ret == DRBG_SUCCESS) + ret = wc_RNG_TestSeed(newSeed, SEED_SZ + SEED_BLOCK_SZ); + + if (ret == DRBG_SUCCESS) + ret = Hash_DRBG_Reseed((DRBG_internal *)rng->drbg, + newSeed + SEED_BLOCK_SZ, SEED_SZ); + #ifdef WOLFSSL_SMALL_STACK + if (newSeed != NULL) { + ForceZero(newSeed, SEED_SZ + SEED_BLOCK_SZ); + } + XFREE(newSeed, rng->heap, DYNAMIC_TYPE_SEED); + #else + ForceZero(newSeed, sizeof(newSeed)); + #endif + } + else { + ret = DRBG_CONT_FAILURE; + } + + return ret; +} +#endif /* place a generated block in output */ WOLFSSL_ABI @@ -1954,60 +2014,22 @@ int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz) if (rng->status != DRBG_OK) return RNG_FAILURE_E; +#if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) + if (rng->pid != getpid()) { + rng->pid = getpid(); + ret = PollAndReSeed(rng); + if (ret != DRBG_SUCCESS) { + rng->status = DRBG_FAILED; + return RNG_FAILURE_E; + } + } +#endif + ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, sz); if (ret == DRBG_NEED_RESEED) { - int devId = INVALID_DEVID; - #if defined(WOLFSSL_ASYNC_CRYPT) || defined(WOLF_CRYPTO_CB) - devId = rng->devId; - #endif - if (wc_RNG_HealthTestLocal(1, rng->heap, devId) == 0) { - #ifndef WOLFSSL_SMALL_STACK - byte newSeed[SEED_SZ + SEED_BLOCK_SZ]; - ret = DRBG_SUCCESS; - #else - byte* newSeed = (byte*)XMALLOC(SEED_SZ + SEED_BLOCK_SZ, rng->heap, - DYNAMIC_TYPE_SEED); - ret = (newSeed == NULL) ? MEMORY_E : DRBG_SUCCESS; - #endif - if (ret == DRBG_SUCCESS) { - #ifdef WC_RNG_SEED_CB - if (seedCb == NULL) { - ret = DRBG_NO_SEED_CB; - } - else { - ret = seedCb(&rng->seed, newSeed, SEED_SZ + SEED_BLOCK_SZ); - if (ret != 0) { - ret = DRBG_FAILURE; - } - } - #else - ret = wc_GenerateSeed(&rng->seed, newSeed, - SEED_SZ + SEED_BLOCK_SZ); - #endif - if (ret != 0) - ret = DRBG_FAILURE; - } - if (ret == DRBG_SUCCESS) - ret = wc_RNG_TestSeed(newSeed, SEED_SZ + SEED_BLOCK_SZ); - - if (ret == DRBG_SUCCESS) - ret = Hash_DRBG_Reseed((DRBG_internal *)rng->drbg, - newSeed + SEED_BLOCK_SZ, SEED_SZ); - if (ret == DRBG_SUCCESS) - ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, sz); - - #ifdef WOLFSSL_SMALL_STACK - if (newSeed != NULL) { - ForceZero(newSeed, SEED_SZ + SEED_BLOCK_SZ); - } - XFREE(newSeed, rng->heap, DYNAMIC_TYPE_SEED); - #else - ForceZero(newSeed, sizeof(newSeed)); - #endif - } - else { - ret = DRBG_CONT_FAILURE; - } + ret = PollAndReSeed(rng); + if (ret == DRBG_SUCCESS) + ret = Hash_DRBG_Generate((DRBG_internal *)rng->drbg, output, sz); } if (ret == DRBG_SUCCESS) { diff --git a/wolfssl/wolfcrypt/random.h b/wolfssl/wolfcrypt/random.h index 5abd6c011..a566956f1 100644 --- a/wolfssl/wolfcrypt/random.h +++ b/wolfssl/wolfcrypt/random.h @@ -189,6 +189,9 @@ struct WC_RNG { #endif byte status; #endif +#if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) + pid_t pid; +#endif #ifdef WOLFSSL_ASYNC_CRYPT WC_ASYNC_DEV asyncDev; #endif