[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [tor/master] Use NSS in crypto_rand.c
commit 60705a5719d929a5f3180bc4e6906f972855f84b
Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
Date: Fri Jul 13 14:35:51 2018 -0400
Use NSS in crypto_rand.c
This is comparatively straightforward too, except for a couple of
twists:
* For as long as we're building with two crypto libraries, we
want to seed _both_ their RNGs, and use _both_ their RNGs to
improve the output of crypto_strongest_rand()
* The NSS prng will sometimes refuse to generate huge outputs.
When it does, we stretch the output with SHAKE. We only need
this for the tests.
---
src/lib/crypt_ops/crypto_rand.c | 110 +++++++++++++++++++++++++++++++++++++---
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 fb9d0c2c6..980671474 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 f9276c25d..923f51ecc 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;
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits