diff options
author | Matt Johnston <matt@ucc.asn.au> | 2020-05-28 22:50:41 +0800 |
---|---|---|
committer | Matt Johnston <matt@ucc.asn.au> | 2020-05-28 22:50:41 +0800 |
commit | 89e98a2f8382bcaab0e7ba04cb4050c9d62898a4 (patch) | |
tree | d0e2d836a78fc8ad73850bcca665914efbea15df | |
parent | 5027bc4db18a50aebd70bf4ae41f7702469c01ba (diff) |
Use Linux getrandom() to ensure random device is initialised
Remove old code warning about random device being not ready,
/dev/random isn't used by default anyway.
-rw-r--r-- | configure.ac | 5 | ||||
-rw-r--r-- | dbrandom.c | 144 | ||||
-rw-r--r-- | includes.h | 4 |
3 files changed, 97 insertions, 56 deletions
diff --git a/configure.ac b/configure.ac index bcb6e4a..848c261 100644 --- a/configure.ac +++ b/configure.ac @@ -370,7 +370,8 @@ AC_CHECK_HEADERS([netinet/in.h netinet/tcp.h \ crypt.h \ pty.h libutil.h libgen.h inttypes.h stropts.h utmp.h \ utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h \ - pam/pam_appl.h netinet/in_systm.h sys/uio.h linux/pkt_sched.h]) + pam/pam_appl.h netinet/in_systm.h sys/uio.h linux/pkt_sched.h \ + sys/random.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -526,7 +527,7 @@ AC_CHECK_FUNCS(clock_gettime) AC_CHECK_HEADERS([mach/mach_time.h]) AC_CHECK_FUNCS(mach_absolute_time) -AC_CHECK_FUNCS(explicit_bzero memset_s) +AC_CHECK_FUNCS(explicit_bzero memset_s getrandom) AC_ARG_ENABLE(bundled-libtom, [ --enable-bundled-libtom Force using bundled libtomcrypt/libtommath even if a system version exists. @@ -49,24 +49,19 @@ static int donerandinit = 0; * */ -/* Pass len=0 to hash an entire file */ +/* Pass wantlen=0 to hash an entire file */ static int process_file(hash_state *hs, const char *filename, - unsigned int len, int prngd) -{ - static int already_blocked = 0; + unsigned int wantlen, int prngd) { int readfd; unsigned int readcount; int ret = DROPBEAR_FAILURE; + if (prngd) { #if DROPBEAR_USE_PRNGD - if (prngd) - { readfd = connect_unix(filename); - } - else #endif - { + } else { readfd = open(filename, O_RDONLY); } @@ -75,58 +70,31 @@ process_file(hash_state *hs, const char *filename, } readcount = 0; - while (len == 0 || readcount < len) - { + while (wantlen == 0 || readcount < wantlen) { int readlen, wantread; unsigned char readbuf[4096]; - if (!already_blocked && !prngd) - { - int res; - struct timeval timeout; - fd_set read_fds; - - timeout.tv_sec = 2; - timeout.tv_usec = 0; - - DROPBEAR_FD_ZERO(&read_fds); - FD_SET(readfd, &read_fds); - res = select(readfd + 1, &read_fds, NULL, NULL, &timeout); - if (res == 0) - { - dropbear_log(LOG_WARNING, "Warning: Reading the randomness source '%s' seems to have blocked.\nYou may need to find a better entropy source.", filename); - already_blocked = 1; - } - } - - if (len == 0) - { + if (wantlen == 0) { wantread = sizeof(readbuf); - } - else - { - wantread = MIN(sizeof(readbuf), len-readcount); + } else { + wantread = MIN(sizeof(readbuf), wantlen-readcount); } #if DROPBEAR_USE_PRNGD - if (prngd) - { + if (prngd) { char egdcmd[2]; egdcmd[0] = 0x02; /* blocking read */ egdcmd[1] = (unsigned char)wantread; - if (write(readfd, egdcmd, 2) < 0) - { + if (write(readfd, egdcmd, 2) < 0) { dropbear_exit("Can't send command to egd"); } } #endif - readlen = read(readfd, readbuf, wantread); if (readlen <= 0) { if (readlen < 0 && errno == EINTR) { continue; } - if (readlen == 0 && len == 0) - { + if (readlen == 0 && wantlen == 0) { /* whole file was read as requested */ break; } @@ -193,6 +161,63 @@ void fuzz_seed(void) { } #endif + +#ifdef HAVE_GETRANDOM +/* Reads entropy seed with getrandom(). + * May block if the kernel isn't ready. + * Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ +static int process_getrandom(hash_state *hs) { + char buf[INIT_SEED_SIZE]; + ssize_t ret; + + /* First try non-blocking so that we can warn about waiting */ + ret = getrandom(buf, sizeof(buf), GRND_NONBLOCK); + if (ret == -1) { + if (errno == ENOSYS) { + /* Old kernel */ + return DROPBEAR_FAILURE; + } + /* Other errors fall through to blocking getrandom() */ + TRACE(("first getrandom() failed: %d %s", errno, strerror(errno))) + if (errno == EAGAIN) { + dropbear_log(LOG_WARNING, "Waiting for kernel randomness to be initialised..."); + } + } + + /* Wait blocking if needed. Loop in case we get EINTR */ + while (ret != sizeof(buf)) { + ret = getrandom(buf, sizeof(buf), 0); + + if (ret == sizeof(buf)) { + /* Success */ + break; + } + if (ret == -1 && errno == EINTR) { + /* Try again. */ + continue; + } + if (ret >= 0) { + TRACE(("Short read %zd from getrandom() shouldn't happen", ret)) + /* Try again? */ + continue; + } + + /* Unexpected problem, fall back to /dev/urandom */ + TRACE(("2nd getrandom() failed: %d %s", errno, strerror(errno))) + break; + } + + if (ret == sizeof(buf)) { + /* Success, stir in the entropy */ + sha1_process(hs, (void*)buf, sizeof(buf)); + return DROPBEAR_SUCCESS; + } + + return DROPBEAR_FAILURE; + +} +#endif /* HAVE_GETRANDOM */ + /* Initialise the prng from /dev/urandom or prngd. This function can * be called multiple times */ void seedrandom() { @@ -202,6 +227,7 @@ void seedrandom() { pid_t pid; struct timeval tv; clock_t clockval; + int urandom_seeded = 0; #if DROPBEAR_FUZZ if (fuzz.fuzzing) { @@ -215,20 +241,30 @@ void seedrandom() { /* existing state */ sha1_process(&hs, (void*)hashpool, sizeof(hashpool)); -#if DROPBEAR_USE_PRNGD - if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1) - != DROPBEAR_SUCCESS) { - dropbear_exit("Failure reading random device %s", - DROPBEAR_PRNGD_SOCKET); +#ifdef HAVE_GETRANDOM + if (process_getrandom(&hs) == DROPBEAR_SUCCESS) { + urandom_seeded = 1; } +#endif + + if (!urandom_seeded) { +#if DROPBEAR_USE_PRNGD + if (process_file(&hs, DROPBEAR_PRNGD_SOCKET, INIT_SEED_SIZE, 1) + != DROPBEAR_SUCCESS) { + dropbear_exit("Failure reading random device %s", + DROPBEAR_PRNGD_SOCKET); + urandom_seeded = 1; + } #else - /* non-blocking random source (probably /dev/urandom) */ - if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0) - != DROPBEAR_SUCCESS) { - dropbear_exit("Failure reading random device %s", - DROPBEAR_URANDOM_DEV); - } + /* non-blocking random source (probably /dev/urandom) */ + if (process_file(&hs, DROPBEAR_URANDOM_DEV, INIT_SEED_SIZE, 0) + != DROPBEAR_SUCCESS) { + dropbear_exit("Failure reading random device %s", + DROPBEAR_URANDOM_DEV); + urandom_seeded = 1; + } #endif + } /* urandom_seeded */ /* A few other sources to fall back on. * Add more here for other platforms */ @@ -124,6 +124,10 @@ #include <sys/uio.h> #endif +#ifdef HAVE_SYS_RANDOM_H +#include <sys/random.h> +#endif + #ifdef BUNDLED_LIBTOM #include "libtomcrypt/src/headers/tomcrypt.h" #include "libtommath/tommath.h" |