From 033dc8974de052c1f1ab5d735ec2ee921127e352 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Thu, 28 Feb 2019 23:37:24 +0100 Subject: tools: genkey: account for short reads of /dev/urandom Apparently Haiku has a misbehaving /dev/urandom. While we're at it, simplify the function signature to completely succeed or completely fail and make sure the caller checks the result. Reported-by: Alexander von Gluck IV Nitpicked-by: Aaron Jones --- contrib/examples/embeddable-wg-library/wireguard.c | 17 ++++++---- src/tools/genkey.c | 36 ++++++++++++++-------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/contrib/examples/embeddable-wg-library/wireguard.c b/contrib/examples/embeddable-wg-library/wireguard.c index 51da8ec..54b8700 100644 --- a/contrib/examples/embeddable-wg-library/wireguard.c +++ b/contrib/examples/embeddable-wg-library/wireguard.c @@ -1751,16 +1751,21 @@ void wg_generate_private_key(wg_key private_key) void wg_generate_preshared_key(wg_key preshared_key) { ssize_t ret; + size_t i; int fd; - -#if defined(__NR_getrandom) - ret = syscall(__NR_getrandom, preshared_key, sizeof(wg_key), 0); - if (ret == sizeof(wg_key)) +#if defined(__OpenBSD__) || (defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12) || (defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))) + if (!getentropy(preshared_key, sizeof(wg_key))) + return; +#endif +#if defined(__NR_getrandom) && defined(__linux__) + if (syscall(__NR_getrandom, preshared_key, sizeof(wg_key), 0) == sizeof(wg_key)) return; #endif fd = open("/dev/urandom", O_RDONLY); assert(fd >= 0); - ret = read(fd, preshared_key, sizeof(wg_key)); + for (i = 0; i < sizeof(wg_key); i += ret) { + ret = read(fd, preshared_key + i, sizeof(wg_key) - i); + assert(ret > 0); + } close(fd); - assert(ret == sizeof(wg_key)); } diff --git a/src/tools/genkey.c b/src/tools/genkey.c index 645f614..21d2f7a 100644 --- a/src/tools/genkey.c +++ b/src/tools/genkey.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -27,29 +28,40 @@ #include "encoding.h" #include "subcommands.h" -static inline ssize_t get_random_bytes(uint8_t *out, size_t len) +static inline bool __attribute__((__warn_unused_result__)) get_random_bytes(uint8_t *out, size_t len) { - ssize_t ret; + ssize_t ret = 0; + size_t i; int fd; + if (len > 256) { + errno = EOVERFLOW; + return false; + } + #if defined(__OpenBSD__) || (defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12) || (defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))) - ret = getentropy(out, len); - if (!ret) - return len; + if (!getentropy(out, len)) + return true; #endif #if defined(__NR_getrandom) && defined(__linux__) - ret = syscall(__NR_getrandom, out, len, 0); - if (ret >= 0) - return ret; + if (syscall(__NR_getrandom, out, len, 0) == (ssize_t)len) + return true; #endif fd = open("/dev/urandom", O_RDONLY); if (fd < 0) - return fd; - ret = read(fd, out, len); + return false; + for (errno = 0, i = 0; i < len; i += ret, ret = 0) { + ret = read(fd, out + i, len - i); + if (ret <= 0) { + ret = errno ? -errno : -EIO; + break; + } + } close(fd); - return ret; + errno = -ret; + return i == len; } int genkey_main(int argc, char *argv[]) @@ -66,7 +78,7 @@ int genkey_main(int argc, char *argv[]) if (!fstat(STDOUT_FILENO, &stat) && S_ISREG(stat.st_mode) && stat.st_mode & S_IRWXO) fputs("Warning: writing to world accessible file.\nConsider setting the umask to 077 and trying again.\n", stderr); - if (get_random_bytes(key, WG_KEY_LEN) != WG_KEY_LEN) { + if (!get_random_bytes(key, WG_KEY_LEN)) { perror("getrandom"); return 1; } -- cgit v1.2.3-59-g8ed1b