From: Nick Mathewson Date: Thu, 4 Mar 2010 06:13:51 +0000 (-0500) Subject: Seed the RNG using sysctl() as well as /dev/urandom X-Git-Tag: release-2.0.5-beta~36^2~3 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=71fc3eb08b9acd359ba61b31059bf4220808a03b;p=libevent Seed the RNG using sysctl() as well as /dev/urandom William Ahern points out that if the user has chrooted, they might not have a working /dev/urandom. Linux and many of the BSDs, however, define a sysctl interface to their kernel random number generators. This patch takes a belt-and-suspenders approach and tries to do use the sysctl _and_ the /dev/urandom approach if both are present. When using the sysctl approach, it tries to bulletproof itself by checking to make sure that the buffers are actually set by the sysctl calls. --- diff --git a/arc4random.c b/arc4random.c index 28f0cdbf..a039711f 100644 --- a/arc4random.c +++ b/arc4random.c @@ -1,5 +1,6 @@ /* Portable arc4random.c based on arc4random.c from OpenBSD. * Portable version by Chris Davis, adapted for Libevent by Nick Mathewson + * Copyright (c) 2010 Chris Davis, Niels Provos, and Nick Mathewson * * Note that in Libevent, this file isn't compiled directly. Instead, * it's included from evutil_rand.c @@ -56,6 +57,7 @@ #include #include #include +#include #endif #include #include @@ -135,29 +137,20 @@ read_all(int fd, unsigned char *buf, size_t count) } #endif -/* This is adapted from Tor's crypto_seed_rng() */ +#ifdef WIN32 +#define TRY_SEED_WIN32 static int -arc4_seed(void) +arc4_seed_win32(void) { - unsigned char buf[ADD_ENTROPY]; - - /* local variables */ -#ifdef WIN32 + /* This is adapted from Tor's crypto_seed_rng() */ static int provider_set = 0; static HCRYPTPROV provider; -#else - static const char *filenames[] = { - "/dev/srandom", "/dev/urandom", "/dev/random", NULL - }; - int fd, i; - size_t n; -#endif + unsigned char buf[ADD_ENTROPY]; -#ifdef WIN32 if (!provider_set) { if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { - if ((unsigned long)GetLastError() != (unsigned long)NTE_BAD_KEYSET) + if (GetLastError() != (DWORD)NTE_BAD_KEYSET) return -1; } provider_set = 1; @@ -168,7 +161,100 @@ arc4_seed(void) memset(buf, 0, sizeof(buf)); arc4_seeded_ok = 1; return 0; -#else +} +#endif + +#if defined(_EVENT_HAVE_SYS_SYSCTL_H) +#if _EVENT_HAVE_DECL_CTL_KERN && _EVENT_HAVE_DECL_KERN_RANDOM && _EVENT_HAVE_DECL_RANDOM_UUID +#define TRY_SEED_SYSCTL_LINUX +static int +arc4_seed_sysctl_linux(void) +{ + /* Based on code by William Ahern, this function tries to use the + * RANDOM_UUID sysctl to get entropy from the kernel. This can work + * even if /dev/urandom is inaccessible for some reason (e.g., we're + * running in a chroot). */ + int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID }; + unsigned char buf[ADD_ENTROPY]; + size_t len, n; + int i, any_set; + + memset(buf, 0, sizeof(buf)); + + for (len = 0; len < sizeof(buf); len += n) { + n = sizeof(buf) - len; + + if (0 != sysctl(mib, 3, &buf[len], &n, NULL, 0)) + return -1; + } + /* make sure that the buffer actually got set. */ + for (i=any_set=0; i sizeof(buf)) + n = len - sizeof(buf); + if (sysctl(mib, 2, &buf[len], &n, NULL, 0) == -1) + return -1; + } + } + /* make sure that the buffer actually got set. */ + for (i=any_set=0; i]] + ) +fi + dnl - check if the macro WIN32 is defined on this compiler. dnl - (this is how we check for a windows version of GCC) AC_MSG_CHECKING(for WIN32)