diff options
Diffstat (limited to 'crypto/random-platform.c')
| -rw-r--r-- | crypto/random-platform.c | 104 |
1 files changed, 62 insertions, 42 deletions
diff --git a/crypto/random-platform.c b/crypto/random-platform.c index 7541b4cae7..66624106fe 100644 --- a/crypto/random-platform.c +++ b/crypto/random-platform.c @@ -27,68 +27,88 @@ #include <wincrypt.h> static HCRYPTPROV hCryptProv; #else -static int fd; /* a file handle to either /dev/urandom or /dev/random */ +# ifdef CONFIG_GETRANDOM +# include <sys/random.h> +# endif +/* This is -1 for getrandom(), or a file handle for /dev/{u,}random. */ +static int fd; #endif int qcrypto_random_init(Error **errp) { -#ifndef _WIN32 - /* TBD perhaps also add support for BSD getentropy / Linux - * getrandom syscalls directly */ - fd = open("/dev/urandom", O_RDONLY); - if (fd == -1 && errno == ENOENT) { - fd = open("/dev/random", O_RDONLY); - } - - if (fd < 0) { - error_setg(errp, "No /dev/urandom or /dev/random found"); - return -1; - } -#else +#ifdef _WIN32 if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT | CRYPT_VERIFYCONTEXT)) { error_setg_win32(errp, GetLastError(), "Unable to create cryptographic provider"); return -1; } +#else +# ifdef CONFIG_GETRANDOM + if (getrandom(NULL, 0, 0) == 0) { + /* Use getrandom() */ + fd = -1; + return 0; + } + /* Fall through to /dev/urandom case. */ +# endif + fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); + if (fd == -1 && errno == ENOENT) { + fd = open("/dev/random", O_RDONLY | O_CLOEXEC); + } + if (fd < 0) { + error_setg_errno(errp, errno, "No /dev/urandom or /dev/random"); + return -1; + } #endif - return 0; } -int qcrypto_random_bytes(uint8_t *buf G_GNUC_UNUSED, - size_t buflen G_GNUC_UNUSED, +int qcrypto_random_bytes(void *buf, + size_t buflen, Error **errp) { -#ifndef _WIN32 - int ret = -1; - int got; - - while (buflen > 0) { - got = read(fd, buf, buflen); - if (got < 0) { - error_setg_errno(errp, errno, - "Unable to read random bytes"); - goto cleanup; - } else if (!got) { - error_setg(errp, - "Unexpected EOF reading random bytes"); - goto cleanup; - } - buflen -= got; - buf += got; - } - - ret = 0; - cleanup: - return ret; -#else +#ifdef _WIN32 if (!CryptGenRandom(hCryptProv, buflen, buf)) { error_setg_win32(errp, GetLastError(), "Unable to read random bytes"); return -1; } - - return 0; +#else +# ifdef CONFIG_GETRANDOM + if (likely(fd < 0)) { + while (1) { + ssize_t got = getrandom(buf, buflen, 0); + if (likely(got == buflen)) { + return 0; + } + if (got >= 0) { + buflen -= got; + buf += got; + } else if (errno != EINTR) { + error_setg_errno(errp, errno, "getrandom"); + return -1; + } + } + } + /* Fall through to /dev/urandom case. */ +# endif + while (1) { + ssize_t got = read(fd, buf, buflen); + if (likely(got == buflen)) { + return 0; + } + if (got > 0) { + buflen -= got; + buf += got; + } else if (got == 0) { + error_setg(errp, "Unexpected EOF reading random bytes"); + return -1; + } else if (errno != EINTR) { + error_setg_errno(errp, errno, "Unable to read random bytes"); + return -1; + } + } #endif + return 0; } |