diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index d366e6cc1..f1c66de08 100644 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -68,6 +68,9 @@ This library contains implementation for the random number generator. #include +#ifdef WC_RNG_BANK_SUPPORT + #include +#endif #include #ifndef WC_NO_RNG /* if not FIPS and RNG is disabled then do not compile */ @@ -369,6 +372,12 @@ static int Hash_df(DRBG_internal* drbg, byte* out, word32 outSz, byte type, XFREE(digest, drbg->heap, DYNAMIC_TYPE_DIGEST); #endif +#ifdef WC_VERBOSE_RNG + if (ret != 0) + WOLFSSL_DEBUG_PRINTF("ERROR: %s failed with err = %d", __FUNCTION__, + ret); +#endif + return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE; } @@ -406,6 +415,13 @@ static int Hash_DRBG_Reseed(DRBG_internal* drbg, const byte* seed, word32 seedSz #ifndef WOLFSSL_SMALL_STACK_CACHE WC_FREE_VAR_EX(newV, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER); #endif + + #ifdef WC_VERBOSE_RNG + if (ret != 0) + WOLFSSL_DEBUG_PRINTF("ERROR: Hash_DRBG_Reseed failed with err %d.", + ret); + #endif + return ret; } @@ -525,6 +541,19 @@ static int Hash_gen(DRBG_internal* drbg, byte* out, word32 outSz, const byte* V) WC_FREE_VAR_EX(data, drbg->heap, DYNAMIC_TYPE_TMP_BUFFER); #endif + #ifdef WC_VERBOSE_RNG + if ((ret != DRBG_SUCCESS) && (ret != DRBG_FAILURE)) { + /* Note, if we're just going to return DRBG_FAILURE to the caller, then + * there's no point printing it out here because (1) the lower-level + * code that was remapped to DRBG_FAILURE already got printed before the + * remapping, so a DRBG_FAILURE message would just be spamming the log, + * and (2) the caller will actually see the DRBG_FAILURE code, and is + * free to (and probably will) log it itself. + */ + WOLFSSL_DEBUG_PRINTF("ERROR: Hash_gen failed with err %d.", ret); + } + #endif + return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE; } @@ -635,6 +664,14 @@ static int Hash_DRBG_Generate(DRBG_internal* drbg, byte* out, word32 outSz) #endif } + #ifdef WC_VERBOSE_RNG + if ((ret != DRBG_SUCCESS) && (ret != DRBG_FAILURE)) { + /* see note above regarding log spam reduction */ + WOLFSSL_DEBUG_PRINTF("ERROR: Hash_DRBG_Generate failed with err %d.", + ret); + } + #endif + return (ret == 0) ? DRBG_SUCCESS : DRBG_FAILURE; } @@ -721,7 +758,6 @@ int wc_RNG_TestSeed(const byte* seed, word32 seedSz) if (ConstantCompare(seed + seedIdx, seed + seedIdx + scratchSz, (int)scratchSz) == 0) { - ret = DRBG_CONT_FAILURE; } seedIdx += SEED_BLOCK_SZ; @@ -922,6 +958,11 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, else { ret = seedCb(&rng->seed, seed, seedSz); if (ret != 0) { +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "ERROR: seedCb in _InitRng() failed with err = %d", + ret); +#endif ret = DRBG_FAILURE; } } @@ -931,6 +972,10 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, if (ret != 0) { #if defined(DEBUG_WOLFSSL) WOLFSSL_MSG_EX("Seed generation failed... %d", ret); + #elif defined(WC_VERBOSE_RNG) + WOLFSSL_DEBUG_PRINTF( + "ERROR: wc_GenerateSeed() in _InitRng() failed with err %d", + ret); #endif ret = DRBG_FAILURE; rng->status = DRBG_FAILED; @@ -942,7 +987,14 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, if (ret != 0) { WOLFSSL_MSG_EX("wc_RNG_TestSeed failed... %d", ret); } + #elif defined(WC_VERBOSE_RNG) + if (ret != DRBG_SUCCESS) { + WOLFSSL_DEBUG_PRINTF( + "ERROR: wc_RNG_TestSeed() in _InitRng() returned err %d.", + ret); + } #endif + if (ret == DRBG_SUCCESS) ret = Hash_DRBG_Instantiate((DRBG_internal *)rng->drbg, seed + SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ, @@ -1112,19 +1164,35 @@ static int PollAndReSeed(WC_RNG* rng) else { ret = seedCb(&rng->seed, newSeed, SEED_SZ + SEED_BLOCK_SZ); if (ret != 0) { + #ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF("ERROR: seedCb() in PollAndReSeed() " + "failed with err %d", ret); + #endif ret = DRBG_FAILURE; } } #else ret = wc_GenerateSeed(&rng->seed, newSeed, SEED_SZ + SEED_BLOCK_SZ); - #endif - if (ret != 0) + if (ret != 0) { + #ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "ERROR: wc_GenerateSeed() in PollAndReSeed() failed with " + "err %d", ret); + #endif ret = DRBG_FAILURE; + } + #endif } - if (ret == DRBG_SUCCESS) + if (ret == DRBG_SUCCESS) { ret = wc_RNG_TestSeed(newSeed, SEED_SZ + SEED_BLOCK_SZ); - + #ifdef WC_VERBOSE_RNG + if (ret != DRBG_SUCCESS) + WOLFSSL_DEBUG_PRINTF( + "ERROR: wc_RNG_TestSeed() in PollAndReSeed() returned " + "err %d.", ret); + #endif + } if (ret == DRBG_SUCCESS) ret = Hash_DRBG_Reseed((DRBG_internal *)rng->drbg, newSeed + SEED_BLOCK_SZ, SEED_SZ); @@ -1146,8 +1214,12 @@ static int PollAndReSeed(WC_RNG* rng) #endif /* place a generated block in output */ +#ifdef WC_RNG_BANK_SUPPORT +static int wc_local_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz) +#else WOLFSSL_ABI int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz) +#endif { int ret; @@ -1194,6 +1266,11 @@ int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz) #ifdef CUSTOM_RAND_GENERATE_BLOCK XMEMSET(output, 0, sz); ret = (int)CUSTOM_RAND_GENERATE_BLOCK(output, sz); + #ifdef WC_VERBOSE_RNG + if (ret != 0) + WOLFSSL_DEBUG_PRINTF( + "ERROR: CUSTOM_RAND_GENERATE_BLOCK failed with err %d.", ret); + #endif #else #ifdef HAVE_HASHDRBG @@ -1243,6 +1320,42 @@ int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz) return ret; } +#ifdef WC_RNG_BANK_SUPPORT +WOLFSSL_ABI +int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz) +{ + if (rng == NULL) + return BAD_FUNC_ARG; + + if (rng->status == WC_DRBG_BANKREF) { + int ret; + struct wc_rng_bank_inst *bank_inst = NULL; + + ret = wc_local_rng_bank_checkout_for_bankref(rng->bankref, &bank_inst); + if (ret != 0) + return ret; + if (bank_inst == NULL) + return BAD_STATE_E; + ret = wc_local_RNG_GenerateBlock(WC_RNG_BANK_INST_TO_RNG(bank_inst), + output, sz); + { + int checkin_ret = wc_rng_bank_checkin(rng->bankref, &bank_inst); + if (checkin_ret != 0) { +#ifdef WC_VERBOSE_RNG + WOLFSSL_DEBUG_PRINTF( + "ERROR: wc_RNG_GenerateBlock() wc_rng_bank_checkin() " + "failed with err %d.", checkin_ret); +#endif + if (ret == 0) + ret = checkin_ret; + } + } + return ret; + } + else + return wc_local_RNG_GenerateBlock(rng, output, sz); +} +#endif int wc_RNG_GenerateByte(WC_RNG* rng, byte* b) { @@ -1257,6 +1370,11 @@ int wc_FreeRng(WC_RNG* rng) if (rng == NULL) return BAD_FUNC_ARG; +#ifdef WC_RNG_BANK_SUPPORT + if (rng->status == WC_DRBG_BANKREF) + return wc_BankRef_Release(rng); +#endif /* WC_RNG_BANK_SUPPORT */ + #if defined(WOLFSSL_ASYNC_CRYPT) wolfAsync_DevCtxFree(&rng->asyncDev, WOLFSSL_ASYNC_MARKER_RNG); #endif @@ -2994,32 +3112,10 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) #elif defined(WOLFSSL_LINUXKM) - /* When registering the kernel default DRBG with a native/intrinsic entropy - * source, fallback to get_random_bytes() isn't allowed because we replace - * it with our DRBG. - */ + #ifndef LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT + #include + #endif - #if defined(HAVE_ENTROPY_MEMUSE) && \ - defined(LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT) - - int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) - { - (void)os; - return wc_Entropy_Get(MAX_ENTROPY_BITS, output, sz); - } - - #elif (defined(HAVE_INTEL_RDSEED) || defined(HAVE_AMD_RDSEED)) && \ - defined(LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT) - - int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) - { - (void)os; - return wc_GenerateSeed_IntelRD(NULL, output, sz); - } - - #else /* !((HAVE_ENTROPY_MEMUSE || HAVE_*_RDSEED) && LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT) */ - - #include int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) { (void)os; @@ -3027,11 +3123,9 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) #ifdef HAVE_ENTROPY_MEMUSE ret = wc_Entropy_Get(MAX_ENTROPY_BITS, output, sz); - if (ret == 0) { + if (ret == 0) return 0; - } #ifdef ENTROPY_MEMUSE_FORCE_FAILURE - /* Don't fallback to /dev/urandom. */ return ret; #endif #endif @@ -3039,23 +3133,30 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) #if defined(HAVE_INTEL_RDSEED) || defined(HAVE_AMD_RDSEED) if (IS_INTEL_RDSEED(intel_flags)) { ret = wc_GenerateSeed_IntelRD(NULL, output, sz); - #ifndef FORCE_FAILURE_RDSEED if (ret == 0) - #endif - { - return ret; - } + return 0; + #ifdef FORCE_FAILURE_RDSEED + return ret; + #endif } #endif /* HAVE_INTEL_RDSEED || HAVE_AMD_RDSEED */ + #ifdef LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT + #if !defined(HAVE_ENTROPY_MEMUSE) && \ + !defined(HAVE_INTEL_RDSEED) && \ + !defined(HAVE_AMD_RDSEED) + #error LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT requires an intrinsic entropy source. + #else + return ret; + #endif + #else (void)ret; get_random_bytes(output, sz); return 0; + #endif } - #endif /* !(HAVE_*_RDSEED && LINUXKM_LKCAPI_REGISTER_HASH_DRBG_DEFAULT) */ - #elif defined(WOLFSSL_BSDKM) #include int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) diff --git a/wolfssl/wolfcrypt/random.h b/wolfssl/wolfcrypt/random.h index 29ad26d3e..834db3ee8 100644 --- a/wolfssl/wolfcrypt/random.h +++ b/wolfssl/wolfcrypt/random.h @@ -243,12 +243,6 @@ struct OS_Seed { #define RNG_HEALTH_TEST_CHECK_SIZE (WC_SHA256_DIGEST_SIZE * 4) -/* RNG health states */ -#define WC_DRBG_NOT_INIT 0 -#define WC_DRBG_OK 1 -#define WC_DRBG_FAILED 2 -#define WC_DRBG_CONT_FAILED 3 - struct DRBG_internal { #ifdef WORD64_AVAILABLE word64 reseedCtr; @@ -267,26 +261,57 @@ struct DRBG_internal { byte digest_scratch[WC_SHA256_DIGEST_SIZE]; #endif }; +#endif /* HAVE_HASHDRBG */ + +/* RNG health states */ +#define WC_DRBG_NOT_INIT 0 +#define WC_DRBG_OK 1 +#define WC_DRBG_FAILED 2 +#define WC_DRBG_CONT_FAILED 3 +#ifdef WC_RNG_BANK_SUPPORT + #define WC_DRBG_BANKREF 4 /* Marks the WC_RNG as a ref to a wc_rng_bank, + * with no usable DRBG of its own. + */ #endif /* RNG context */ struct WC_RNG { struct OS_Seed seed; void* heap; -#ifdef HAVE_HASHDRBG - /* Hash-based Deterministic Random Bit Generator */ - struct DRBG* drbg; -#if defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY) - struct DRBG_internal drbg_data; -#endif -#ifdef WOLFSSL_SMALL_STACK_CACHE - /* Scratch buffer slots -- everything is preallocated by _InitRng(). */ - struct DRBG_internal *drbg_scratch; - byte *health_check_scratch; - byte *newSeed_buf; -#endif byte status; -#endif /* HAVE_HASHDRBG */ + +#ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES + union { +#endif + + #ifdef WC_RNG_BANK_SUPPORT + struct wc_rng_bank *bankref; + #endif + + #ifdef HAVE_HASHDRBG + #ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES + struct { + #endif + /* Hash-based Deterministic Random Bit Generator */ + struct DRBG* drbg; + #if defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_STATIC_MEMORY) + struct DRBG_internal drbg_data; + #endif + #ifdef WOLFSSL_SMALL_STACK_CACHE + /* Scratch buffers -- all preallocated by _InitRng(). */ + struct DRBG_internal *drbg_scratch; + byte *health_check_scratch; + byte *newSeed_buf; + #endif + #ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES + }; + #endif + #endif /* HAVE_HASHDRBG */ + +#ifdef HAVE_ANONYMOUS_INLINE_AGGREGATES + }; +#endif + #if defined(HAVE_GETPID) && !defined(WOLFSSL_NO_GETPID) pid_t pid; #endif