X-Git-Url: https://www.bearssl.org/gitweb//home/git/?p=BearSSL;a=blobdiff_plain;f=src%2Frand%2Fsysrng.c;h=5a921145db73b91f4c454912ba89138240826b58;hp=3a10db9b84ed89431e8ee6b6dec20e43b034a704;hb=dda1f8a0c46e15b4a235163470ff700b2f13dcc5;hpb=af9c79a0710a45361f9ae4313f8bb5bf738c3b7a diff --git a/src/rand/sysrng.c b/src/rand/sysrng.c index 3a10db9..5a92114 100644 --- a/src/rand/sysrng.c +++ b/src/rand/sysrng.c @@ -25,6 +25,10 @@ #define BR_ENABLE_INTRINSICS 1 #include "inner.h" +#if BR_USE_GETENTROPY +#include +#endif + #if BR_USE_URANDOM #include #include @@ -38,6 +42,9 @@ #pragma comment(lib, "advapi32") #endif +/* + * Seeder that uses the RDRAND opcodes (on x86 CPU). + */ #if BR_RDRAND BR_TARGETS_X86_UP BR_TARGET("rdrnd") @@ -57,9 +64,24 @@ seeder_rdrand(const br_prng_class **ctx) * * Intel recommends trying at least 10 times in case of * failure. + * + * AMD bug: there are reports that some AMD processors + * have a bug that makes them fail silently after a + * suspend/resume cycle, in which case RDRAND will report + * a success but always return 0xFFFFFFFF. + * see: https://bugzilla.kernel.org/show_bug.cgi?id=85911 + * + * As a mitigation, if the 32-bit value is 0 or -1, then + * it is considered a failure and tried again. This should + * reliably detect the buggy case, at least. This also + * implies that the selected seed values can never be + * 0x00000000 or 0xFFFFFFFF, which is not a problem since + * we are generating a seed for a PRNG, and we overdo it + * a bit (we generate 32 bytes of randomness, and 256 bits + * of entropy are really overkill). */ for (j = 0; j < 10; j ++) { - if (_rdrand32_step(&x)) { + if (_rdrand32_step(&x) && x != 0 && x != (uint32_t)-1) { goto next_word; } } @@ -80,9 +102,11 @@ rdrand_supported(void) */ return br_cpuid(0, 0, 0x40000000, 0); } - #endif +/* + * Seeder that uses /dev/urandom (on Unix-like systems). + */ #if BR_USE_URANDOM static int seeder_urandom(const br_prng_class **ctx) @@ -116,6 +140,32 @@ seeder_urandom(const br_prng_class **ctx) } #endif +/* + * Seeder that uses getentropy() (backed by getrandom() on some systems, + * e.g. Linux). On failure, it will use the /dev/urandom seeder (if + * enabled). + */ +#if BR_USE_GETENTROPY +static int +seeder_getentropy(const br_prng_class **ctx) +{ + unsigned char tmp[32]; + + if (getentropy(tmp, sizeof tmp) == 0) { + (*ctx)->update(ctx, tmp, sizeof tmp); + return 1; + } +#if BR_USE_URANDOM + return seeder_urandom(ctx); +#else + return 0; +#endif +} +#endif + +/* + * Seeder that uses CryptGenRandom() (on Windows). + */ #if BR_USE_WIN32_RAND static int seeder_win32(const br_prng_class **ctx) @@ -139,7 +189,30 @@ seeder_win32(const br_prng_class **ctx) } #endif -/* see bearssl_rand.h.h */ +/* + * An aggregate seeder that uses RDRAND, and falls back to an OS-provided + * source if RDRAND fails. + */ +#if BR_RDRAND && (BR_USE_GETENTROPY || BR_USE_URANDOM || BR_USE_WIN32_RAND) +static int +seeder_rdrand_with_fallback(const br_prng_class **ctx) +{ + if (!seeder_rdrand(ctx)) { +#if BR_USE_GETENTROPY + return seeder_getentropy(ctx); +#elif BR_USE_URANDOM + return seeder_urandom(ctx); +#elif BR_USE_WIN32_RAND + return seeder_win32(ctx); +#else +#error "macro selection has gone wrong" +#endif + } + return 1; +} +#endif + +/* see bearssl_rand.h */ br_prng_seeder br_prng_seeder_system(const char **name) { @@ -148,10 +221,19 @@ br_prng_seeder_system(const char **name) if (name != NULL) { *name = "rdrand"; } +#if BR_USE_GETENTROPY || BR_USE_URANDOM || BR_USE_WIN32_RAND + return &seeder_rdrand_with_fallback; +#else return &seeder_rdrand; +#endif } #endif -#if BR_USE_URANDOM +#if BR_USE_GETENTROPY + if (name != NULL) { + *name = "getentropy"; + } + return &seeder_getentropy; +#elif BR_USE_URANDOM if (name != NULL) { *name = "urandom"; } @@ -161,9 +243,10 @@ br_prng_seeder_system(const char **name) *name = "win32"; } return &seeder_win32; -#endif +#else if (name != NULL) { *name = "none"; } return 0; +#endif }