diff --git a/IDE/WIN10/user_settings.h b/IDE/WIN10/user_settings.h index 15476f9e2..4b106cf1c 100644 --- a/IDE/WIN10/user_settings.h +++ b/IDE/WIN10/user_settings.h @@ -42,6 +42,9 @@ #define WOLFSSL_VALIDATE_ECC_IMPORT #define WOLFSSL_VALIDATE_FFC_IMPORT #define HAVE_FFDHE_Q + #define WOLFSSL_AESNI + #define HAVE_INTEL_RDSEED + #define FORCE_FAILURE_RDSEED #endif /* FIPS v2 */ #else /* Enables blinding mode, to prevent timing attacks */ diff --git a/fips-check.sh b/fips-check.sh index a88f583d2..901053ea5 100755 --- a/fips-check.sh +++ b/fips-check.sh @@ -161,6 +161,8 @@ linuxv2) CRYPT_VERSION=$LINUXV2_CRYPT_VERSION CRYPT_INC_PATH=wolfssl/wolfcrypt CRYPT_SRC_PATH=wolfcrypt/src +# Replace the WC_MODS list for now. Do not want to copy over random.c yet. + WC_MODS=( aes des3 sha sha256 sha512 rsa hmac ) WC_MODS+=( cmac dh ecc ) FIPS_SRCS+=( wolfcrypt_first.c wolfcrypt_last.c ) FIPS_INCS=( fips.h ) diff --git a/wolfcrypt/src/random.c b/wolfcrypt/src/random.c index cf2f598be..db1a6edac 100755 --- a/wolfcrypt/src/random.c +++ b/wolfcrypt/src/random.c @@ -89,13 +89,12 @@ int wc_RNG_GenerateByte(WC_RNG* rng, byte* b) return FreeRng_fips(rng); } - int wc_RNG_HealthTest(int reseed, - const byte* entropyA, word32 entropyASz, - const byte* entropyB, word32 entropyBSz, - byte* output, word32 outputSz) + int wc_RNG_HealthTest(int reseed, const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, + byte* output, word32 outputSz) { - return RNG_HealthTest_fips(reseed, entropyA, entropyASz, - entropyB, entropyBSz, output, outputSz); + return RNG_HealthTest_fips(reseed, seedA, seedASz, + seedB, seedBSz, output, outputSz); } #endif /* HAVE_HASHDRBG */ @@ -177,9 +176,68 @@ int wc_RNG_GenerateByte(WC_RNG* rng, byte* b) #define OUTPUT_BLOCK_LEN (WC_SHA256_DIGEST_SIZE) #define MAX_REQUEST_LEN (0x10000) #define RESEED_INTERVAL WC_RESEED_INTERVAL -#define SECURITY_STRENGTH (2048) -#define ENTROPY_SZ (SECURITY_STRENGTH/8) -#define MAX_ENTROPY_SZ (ENTROPY_SZ + ENTROPY_SZ/2) + + +/* For FIPS builds, the user should not be adjusting the values. */ +#if defined(HAVE_FIPS) && \ + defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2) + #if defined(RNG_SECURITY_STRENGTH) \ + || defined(ENTROPY_SCALE_FACTOR) \ + || defined(SEED_BLOCK_SZ) + + #error "Do not change the RNG parameters for FIPS builds." + #endif +#endif + + +/* The security strength for the RNG is the target number of bits of + * entropy you are looking for in a seed. */ +#ifndef RNG_SECURITY_STRENGTH + #if defined(HAVE_FIPS) && \ + defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2) + /* SHA-256 requires a minimum of 256-bits of entropy. The goal + * of 1024 will provide 4 times that. */ + #define RNG_SECURITY_STRENGTH (1024) + #else + /* If not using FIPS or using old FIPS, set the number down a bit. + * More is better, but more is also slower. */ + #define RNG_SECURITY_STRENGTH (256) + #endif +#endif + +#ifndef ENTROPY_SCALE_FACTOR + /* The entropy scale factor should be the whole number inverse of the + * minimum bits of entropy per bit of NDRNG output. */ + #if defined(HAVE_INTEL_RDSEED) || defined(HAVE_INTEL_RDRAND) + /* The value of 2 applies to Intel's RDSEED which provides about + * 0.5 bits minimum of entropy per bit. */ + #define ENTROPY_SCALE_FACTOR 2 + #else + /* Setting the default to 1. */ + #define ENTROPY_SCALE_FACTOR 1 + #endif +#endif + +#ifndef SEED_BLOCK_SZ + /* The seed block size, is the size of the output of the underlying NDRNG. + * This value is used for testing the output of the NDRNG. */ + #if defined(HAVE_INTEL_RDSEED) || defined(HAVE_INTEL_RDRAND) + /* RDSEED outputs in blocks of 64-bits. */ + #define SEED_BLOCK_SZ sizeof(word64) + #else + /* Setting the default to 4. */ + #define SEED_BLOCK_SZ 4 + #endif +#endif + +#define SEED_SZ (RNG_SECURITY_STRENGTH*ENTROPY_SCALE_FACTOR/8) + +/* The maximum seed size will be the seed size plus a seed block for the + * test, and an additional half of the seed size. This additional half + * is in case the user does not supply a nonce. A nonce will be obtained + * from the NDRNG. */ +#define MAX_SEED_SZ (SEED_SZ + SEED_SZ/2 + SEED_BLOCK_SZ) + /* Internal return codes */ #define DRBG_SUCCESS 0 @@ -310,19 +368,19 @@ static int Hash_df(DRBG* drbg, byte* out, word32 outSz, byte type, } /* Returns: DRBG_SUCCESS or DRBG_FAILURE */ -static int Hash_DRBG_Reseed(DRBG* drbg, const byte* entropy, word32 entropySz) +static int Hash_DRBG_Reseed(DRBG* drbg, const byte* seed, word32 seedSz) { - byte seed[DRBG_SEED_LEN]; + byte newV[DRBG_SEED_LEN]; - XMEMSET(seed, 0, DRBG_SEED_LEN); + XMEMSET(newV, 0, DRBG_SEED_LEN); - if (Hash_df(drbg, seed, sizeof(seed), drbgReseed, drbg->V, sizeof(drbg->V), - entropy, entropySz) != DRBG_SUCCESS) { + if (Hash_df(drbg, newV, sizeof(newV), drbgReseed, + drbg->V, sizeof(drbg->V), seed, seedSz) != DRBG_SUCCESS) { return DRBG_FAILURE; } - XMEMCPY(drbg->V, seed, sizeof(drbg->V)); - ForceZero(seed, sizeof(seed)); + XMEMCPY(drbg->V, newV, sizeof(drbg->V)); + ForceZero(newV, sizeof(newV)); if (Hash_df(drbg, drbg->C, sizeof(drbg->C), drbgInitC, drbg->V, sizeof(drbg->V), NULL, 0) != DRBG_SUCCESS) { @@ -336,13 +394,13 @@ static int Hash_DRBG_Reseed(DRBG* drbg, const byte* entropy, word32 entropySz) } /* Returns: DRBG_SUCCESS and DRBG_FAILURE or BAD_FUNC_ARG on fail */ -int wc_RNG_DRBG_Reseed(WC_RNG* rng, const byte* entropy, word32 entropySz) +int wc_RNG_DRBG_Reseed(WC_RNG* rng, const byte* seed, word32 seedSz) { - if (rng == NULL || entropy == NULL) { + if (rng == NULL || seed == NULL) { return BAD_FUNC_ARG; } - return Hash_DRBG_Reseed(rng->drbg, entropy, entropySz); + return Hash_DRBG_Reseed(rng->drbg, seed, seedSz); } static WC_INLINE void array_add_one(byte* data, word32 dataSz) @@ -572,6 +630,29 @@ static int Hash_DRBG_Uninstantiate(DRBG* drbg) return (compareSum == 0) ? DRBG_SUCCESS : DRBG_FAILURE; } + + +int wc_RNG_TestSeed(const byte* seed, word32 seedSz) +{ + int ret = DRBG_SUCCESS; + + /* Check the seed for duplicate words. */ + word32 seedIdx = 0; + word32 scratchSz = min(SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ); + + while (seedIdx < seedSz - SEED_BLOCK_SZ) { + if (ConstantCompare(seed + seedIdx, + seed + seedIdx + scratchSz, + scratchSz) == 0) { + + ret = DRBG_CONT_FAILURE; + } + seedIdx += SEED_BLOCK_SZ; + scratchSz = min(SEED_BLOCK_SZ, (seedSz - seedIdx)); + } + + return ret; +} #endif /* HAVE_HASHDRBG */ /* End NIST DRBG Code */ @@ -581,7 +662,7 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, { int ret = RNG_FAILURE_E; #ifdef HAVE_HASHDRBG - word32 entropySz = ENTROPY_SZ; + word32 seedSz = SEED_SZ + SEED_BLOCK_SZ; #endif (void)nonce; @@ -634,10 +715,10 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, #else #ifdef HAVE_HASHDRBG if (nonceSz == 0) - entropySz = MAX_ENTROPY_SZ; + seedSz = MAX_SEED_SZ; if (wc_RNG_HealthTestLocal(0) == 0) { - DECLARE_VAR(entropy, byte, MAX_ENTROPY_SZ, rng->heap); + DECLARE_VAR(seed, byte, MAX_SEED_SZ, rng->heap); rng->drbg = (struct DRBG*)XMALLOC(sizeof(DRBG), rng->heap, @@ -645,16 +726,24 @@ static int _InitRng(WC_RNG* rng, byte* nonce, word32 nonceSz, if (rng->drbg == NULL) { ret = MEMORY_E; } - else if (wc_GenerateSeed(&rng->seed, entropy, entropySz) == 0 && - Hash_DRBG_Instantiate(rng->drbg, entropy, entropySz, - nonce, nonceSz, rng->heap, devId) == DRBG_SUCCESS) { - ret = Hash_DRBG_Generate(rng->drbg, NULL, 0); - } - else - ret = DRBG_FAILURE; + else { + ret = wc_GenerateSeed(&rng->seed, seed, seedSz); + if (ret != 0) + ret = DRBG_FAILURE; + else + ret = wc_RNG_TestSeed(seed, seedSz); - ForceZero(entropy, entropySz); - FREE_VAR(entropy, rng->heap); + if (ret == DRBG_SUCCESS) + ret = Hash_DRBG_Instantiate(rng->drbg, + seed + SEED_BLOCK_SZ, seedSz - SEED_BLOCK_SZ, + nonce, nonceSz, rng->heap, devId); + + if (ret == DRBG_SUCCESS) + ret = Hash_DRBG_Generate(rng->drbg, NULL, 0); + } + + ForceZero(seed, seedSz); + FREE_VAR(seed, rng->heap); } else ret = DRBG_CONT_FAILURE; @@ -747,20 +836,24 @@ int wc_RNG_GenerateBlock(WC_RNG* rng, byte* output, word32 sz) ret = Hash_DRBG_Generate(rng->drbg, output, sz); if (ret == DRBG_NEED_RESEED) { if (wc_RNG_HealthTestLocal(1) == 0) { - byte entropy[ENTROPY_SZ]; + byte newSeed[SEED_SZ + SEED_BLOCK_SZ]; - if (wc_GenerateSeed(&rng->seed, entropy, ENTROPY_SZ) == 0 && - Hash_DRBG_Reseed(rng->drbg, entropy, ENTROPY_SZ) - == DRBG_SUCCESS) { - - ret = Hash_DRBG_Generate(rng->drbg, NULL, 0); - if (ret == DRBG_SUCCESS) - ret = Hash_DRBG_Generate(rng->drbg, output, sz); - } - else + ret = wc_GenerateSeed(&rng->seed, newSeed, + SEED_SZ + SEED_BLOCK_SZ); + if (ret != 0) ret = DRBG_FAILURE; + else + ret = wc_RNG_TestSeed(newSeed, SEED_SZ + SEED_BLOCK_SZ); - ForceZero(entropy, ENTROPY_SZ); + if (ret == DRBG_SUCCESS) + ret = Hash_DRBG_Reseed(rng->drbg, newSeed + SEED_BLOCK_SZ, + SEED_SZ); + if (ret == DRBG_SUCCESS) + ret = Hash_DRBG_Generate(rng->drbg, NULL, 0); + if (ret == DRBG_SUCCESS) + ret = Hash_DRBG_Generate(rng->drbg, output, sz); + + ForceZero(newSeed, sizeof(newSeed)); } else ret = DRBG_CONT_FAILURE; @@ -822,21 +915,20 @@ int wc_FreeRng(WC_RNG* rng) } #ifdef HAVE_HASHDRBG -int wc_RNG_HealthTest(int reseed, const byte* entropyA, word32 entropyASz, - const byte* entropyB, word32 entropyBSz, +int wc_RNG_HealthTest(int reseed, const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, byte* output, word32 outputSz) { return wc_RNG_HealthTest_ex(reseed, NULL, 0, - entropyA, entropyASz, - entropyB, entropyBSz, + seedA, seedASz, seedB, seedBSz, output, outputSz, NULL, INVALID_DEVID); } int wc_RNG_HealthTest_ex(int reseed, const byte* nonce, word32 nonceSz, - const byte* entropyA, word32 entropyASz, - const byte* entropyB, word32 entropyBSz, + const byte* seedA, word32 seedASz, + const byte* seedB, word32 seedBSz, byte* output, word32 outputSz, void* heap, int devId) { @@ -846,11 +938,11 @@ int wc_RNG_HealthTest_ex(int reseed, const byte* nonce, word32 nonceSz, DRBG drbg_var; #endif - if (entropyA == NULL || output == NULL) { + if (seedA == NULL || output == NULL) { return BAD_FUNC_ARG; } - if (reseed != 0 && entropyB == NULL) { + if (reseed != 0 && seedB == NULL) { return BAD_FUNC_ARG; } @@ -867,13 +959,13 @@ int wc_RNG_HealthTest_ex(int reseed, const byte* nonce, word32 nonceSz, drbg = &drbg_var; #endif - if (Hash_DRBG_Instantiate(drbg, entropyA, entropyASz, nonce, nonceSz, + if (Hash_DRBG_Instantiate(drbg, seedA, seedASz, nonce, nonceSz, heap, devId) != 0) { goto exit_rng_ht; } if (reseed) { - if (Hash_DRBG_Reseed(drbg, entropyB, entropyBSz) != 0) { + if (Hash_DRBG_Reseed(drbg, seedB, seedBSz) != 0) { goto exit_rng_ht; } } @@ -904,14 +996,14 @@ exit_rng_ht: } -const byte entropyA[] = { +const byte seedA[] = { 0x63, 0x36, 0x33, 0x77, 0xe4, 0x1e, 0x86, 0x46, 0x8d, 0xeb, 0x0a, 0xb4, 0xa8, 0xed, 0x68, 0x3f, 0x6a, 0x13, 0x4e, 0x47, 0xe0, 0x14, 0xc7, 0x00, 0x45, 0x4e, 0x81, 0xe9, 0x53, 0x58, 0xa5, 0x69, 0x80, 0x8a, 0xa3, 0x8f, 0x2a, 0x72, 0xa6, 0x23, 0x59, 0x91, 0x5a, 0x9f, 0x8a, 0x04, 0xca, 0x68 }; -const byte reseedEntropyA[] = { +const byte reseedSeedA[] = { 0xe6, 0x2b, 0x8a, 0x8e, 0xe8, 0xf1, 0x41, 0xb6, 0x98, 0x05, 0x66, 0xe3, 0xbf, 0xe3, 0xc0, 0x49, 0x03, 0xda, 0xd4, 0xac, 0x2c, 0xdf, 0x9f, 0x22, 0x80, 0x01, 0x0a, 0x67, 0x39, 0xbc, 0x83, 0xd3 @@ -931,7 +1023,7 @@ const byte outputA[] = { 0xa1, 0x80, 0x18, 0x3a, 0x07, 0xdf, 0xae, 0x17 }; -const byte entropyB[] = { +const byte seedB[] = { 0xa6, 0x5a, 0xd0, 0xf3, 0x45, 0xdb, 0x4e, 0x0e, 0xff, 0xe8, 0x75, 0xc3, 0xa2, 0xe7, 0x1f, 0x42, 0xc7, 0x12, 0x9d, 0x62, 0x0f, 0xf5, 0xc1, 0x19, 0xa9, 0xef, 0x55, 0xf0, 0x51, 0x85, 0xe0, 0xfb, /* nonce next */ @@ -972,8 +1064,8 @@ static int wc_RNG_HealthTestLocal(int reseed) #endif if (reseed) { - ret = wc_RNG_HealthTest(1, entropyA, sizeof(entropyA), - reseedEntropyA, sizeof(reseedEntropyA), + ret = wc_RNG_HealthTest(1, seedA, sizeof(seedA), + reseedSeedA, sizeof(reseedSeedA), check, RNG_HEALTH_TEST_CHECK_SIZE); if (ret == 0) { if (ConstantCompare(check, outputA, @@ -982,7 +1074,7 @@ static int wc_RNG_HealthTestLocal(int reseed) } } else { - ret = wc_RNG_HealthTest(0, entropyB, sizeof(entropyB), + ret = wc_RNG_HealthTest(0, seedB, sizeof(seedB), NULL, 0, check, RNG_HEALTH_TEST_CHECK_SIZE); if (ret == 0) { @@ -992,13 +1084,13 @@ static int wc_RNG_HealthTestLocal(int reseed) } /* The previous test cases use a large seed instead of a seed and nonce. - * entropyB is actually from a test case with a seed and nonce, and + * seedB is actually from a test case with a seed and nonce, and * just concatenates them. The pivot point between seed and nonce is * byte 32, feed them into the health test separately. */ if (ret == 0) { ret = wc_RNG_HealthTest_ex(0, - entropyB + 32, sizeof(entropyB) - 32, - entropyB, 32, + seedB + 32, sizeof(seedB) - 32, + seedB, 32, NULL, 0, check, RNG_HEALTH_TEST_CHECK_SIZE, NULL, INVALID_DEVID); @@ -1350,6 +1442,19 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) { + #ifdef HAVE_INTEL_RDSEED + if (IS_INTEL_RDSEED(intel_flags)) { + if (!wc_GenerateSeed_IntelRD(NULL, output, sz)) { + /* success, we're done */ + return 0; + } + #ifdef FORCE_FAILURE_RDSEED + /* don't fall back to CryptoAPI */ + return READ_RAN_E; + #endif + } + #endif /* HAVE_INTEL_RDSEED */ + if(!CryptAcquireContext(&os->handle, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) return WINCRYPT_E; diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 51fa46e50..0995b7663 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -8276,6 +8276,36 @@ int random_test(void) if ((ret = random_rng_test()) != 0) return ret; + /* Test the seed check function. */ +#if !(defined(HAVE_FIPS) || defined(HAVE_SELFTEST)) || \ + (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2)) + { + word32 i, outputSz; + + /* Repeat the same byte over and over. Should fail. */ + outputSz = sizeof(output); + XMEMSET(output, 1, outputSz); + ret = wc_RNG_TestSeed(output, outputSz); + if (ret == 0) + return -6404; + + /* Every byte of the entropy scratch is different, + * entropy is a single byte that shouldn't match. */ + outputSz = (sizeof(word32) * 2) + 1; + for (i = 0; i < outputSz; i++) + output[i] = (byte)i; + ret = wc_RNG_TestSeed(output, outputSz); + if (ret != 0) + return -6405; + + outputSz = sizeof(output); + for (i = 0; i < outputSz; i++) + output[i] = (byte)i; + ret = wc_RNG_TestSeed(output, outputSz); + if (ret != 0) + return -6406; + } +#endif return 0; } diff --git a/wolfssl/wolfcrypt/random.h b/wolfssl/wolfcrypt/random.h index b95d410d6..03c638e4c 100644 --- a/wolfssl/wolfcrypt/random.h +++ b/wolfssl/wolfcrypt/random.h @@ -205,6 +205,7 @@ WOLFSSL_API int wc_FreeRng(WC_RNG*); #ifdef HAVE_HASHDRBG WOLFSSL_LOCAL int wc_RNG_DRBG_Reseed(WC_RNG* rng, const byte* entropy, word32 entropySz); + WOLFSSL_API int wc_RNG_TestSeed(const byte* seed, word32 seedSz); WOLFSSL_API int wc_RNG_HealthTest(int reseed, const byte* entropyA, word32 entropyASz, const byte* entropyB, word32 entropyBSz,