diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/crypt_ops/crypto_rand.c | 110 | ||||
-rw-r--r-- | src/test/test-timers.c | 5 |
2 files changed, 107 insertions, 8 deletions
diff --git a/src/lib/crypt_ops/crypto_rand.c b/src/lib/crypt_ops/crypto_rand.c index fb9d0c2c6c..9806714747 100644 --- a/src/lib/crypt_ops/crypto_rand.c +++ b/src/lib/crypt_ops/crypto_rand.c @@ -35,9 +35,22 @@ #include "lib/testsupport/testsupport.h" #include "lib/fs/files.h" +#ifdef ENABLE_NSS +#include "lib/crypt_ops/crypto_nss_mgt.h" +#include "lib/crypt_ops/crypto_digest.h" +#endif + +#ifdef ENABLE_OPENSSL DISABLE_GCC_WARNING(redundant-decls) #include <openssl/rand.h> ENABLE_GCC_WARNING(redundant-decls) +#endif + +#ifdef ENABLE_NSS +#include <pk11pub.h> +#include <secerr.h> +#include <prerror.h> +#endif #if __GNUC__ && GCC_VERSION >= 402 #if GCC_VERSION >= 406 @@ -324,14 +337,21 @@ crypto_strongest_rand(uint8_t *out, size_t out_len) { #define DLEN SHA512_DIGEST_LENGTH /* We're going to hash DLEN bytes from the system RNG together with some - * bytes from the openssl PRNG, in order to yield DLEN bytes. + * bytes from the PRNGs from our crypto librar(y/ies), in order to yield + * DLEN bytes. */ - uint8_t inp[DLEN*2]; + uint8_t inp[DLEN*3]; uint8_t tmp[DLEN]; tor_assert(out); while (out_len) { - crypto_rand((char*) inp, DLEN); - if (crypto_strongest_rand_raw(inp+DLEN, DLEN) < 0) { + memset(inp, 0, sizeof(inp)); +#ifdef ENABLE_OPENSSL + RAND_bytes(inp, DLEN); +#endif +#ifdef ENABLE_NSS + PK11_GenerateRandom(inp+DLEN, DLEN); +#endif + if (crypto_strongest_rand_raw(inp+DLEN*2, DLEN) < 0) { // LCOV_EXCL_START log_err(LD_CRYPTO, "Failed to load strong entropy when generating an " "important key. Exiting."); @@ -354,12 +374,13 @@ crypto_strongest_rand(uint8_t *out, size_t out_len) #undef DLEN } +#ifdef ENABLE_OPENSSL /** * Seed OpenSSL's random number generator with bytes from the operating * system. Return 0 on success, -1 on failure. **/ -int -crypto_seed_rng(void) +static int +crypto_seed_openssl_rng(void) { int rand_poll_ok = 0, load_entropy_ok = 0; uint8_t buf[ADD_ENTROPY]; @@ -383,6 +404,52 @@ crypto_seed_rng(void) else return -1; } +#endif + +#ifdef ENABLE_NSS +/** + * Seed OpenSSL's random number generator with bytes from the operating + * system. Return 0 on success, -1 on failure. + **/ +static int +crypto_seed_nss_rng(void) +{ + uint8_t buf[ADD_ENTROPY]; + + int load_entropy_ok = !crypto_strongest_rand_raw(buf, sizeof(buf)); + if (load_entropy_ok) { + if (PK11_RandomUpdate(buf, sizeof(buf)) != SECSuccess) { + load_entropy_ok = 0; + } + } + + memwipe(buf, 0, sizeof(buf)); + + return load_entropy_ok ? 0 : -1; +} +#endif + +/** + * Seed the RNG for any and all crypto libraries that we're using with bytes + * from the operating system. Return 0 on success, -1 on failure. + */ +int +crypto_seed_rng(void) +{ + int seeded = 0; +#ifdef ENABLE_NSS + if (crypto_seed_nss_rng() < 0) + return -1; + ++seeded; +#endif +#ifdef ENABLE_OPENSSL + if (crypto_seed_openssl_rng() < 0) + return -1; + ++seeded; +#endif + tor_assert(seeded); + return 0; +} /** * Write <b>n</b> bytes of strong random data to <b>to</b>. Supports mocking @@ -407,17 +474,44 @@ crypto_rand, (char *to, size_t n)) void crypto_rand_unmocked(char *to, size_t n) { - int r; if (n == 0) return; tor_assert(n < INT_MAX); tor_assert(to); - r = RAND_bytes((unsigned char*)to, (int)n); + +#ifdef ENABLE_NSS + SECStatus s = PK11_GenerateRandom((unsigned char*)to, (int)n); + if (s != SECSuccess) { + /* NSS rather sensibly might refuse to generate huge amounts of random + * data at once. Unfortunately, our unit test do this in a couple of + * places. To solve this issue, we use our XOF to stretch a shorter + * output when a longer one is needed. + * + * Yes, this is secure. */ + + /* This is longer than it needs to be; 1600 bits == 200 bytes is the + * state-size of SHA3. */ +#define BUFLEN 512 + tor_assert(PR_GetError() == SEC_ERROR_INVALID_ARGS && n > BUFLEN); + unsigned char buf[BUFLEN]; + s = PK11_GenerateRandom(buf, BUFLEN); + tor_assert(s == SECSuccess); + crypto_xof_t *xof = crypto_xof_new(); + crypto_xof_add_bytes(xof, buf, BUFLEN); + crypto_xof_squeeze_bytes(xof, (unsigned char *)to, n); + crypto_xof_free(xof); + memwipe(buf, 0, BUFLEN); + +#undef BUFLEN + } +#else + int r = RAND_bytes((unsigned char*)to, (int)n); /* We consider a PRNG failure non-survivable. Let's assert so that we get a * stack trace about where it happened. */ tor_assert(r >= 0); +#endif } /** diff --git a/src/test/test-timers.c b/src/test/test-timers.c index f9276c25d6..923f51ecce 100644 --- a/src/test/test-timers.c +++ b/src/test/test-timers.c @@ -9,6 +9,7 @@ #include "lib/evloop/compat_libevent.h" #include "lib/evloop/timers.h" +#include "lib/crypt_ops/crypto_init.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/log/util_bug.h" #include "lib/time/compat_time.h" @@ -62,6 +63,10 @@ main(int argc, char **argv) memset(&cfg, 0, sizeof(cfg)); tor_libevent_initialize(&cfg); timers_initialize(); + init_logging(1); + + if (crypto_global_init(0, NULL, NULL) < 0) + return 1; int i; int ret; |