From 3a3b4faa10bd4d0dfae0b8d62352dd48b190a43e Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Tue, 1 Feb 2022 12:39:01 +0100 Subject: [PATCH] use `getrandom()` on recent linux distros Instead of using the internal DRBG-based RNG, use the `getrandom()` system call where available. Keep the existing version as fall-back for other systems that don't provide that system call. ... and for cases where auto-detection fails or the user simply wants to use the internal RNG a new configure-switch is provided. Signed-off-by: Steffen Jaeckel --- configure.ac | 8 +++++++ src/rand.c | 59 +++++++++++++++++++++++++++++++++++++++++++++-- tests/test_rand.c | 18 +++++++++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 76494d3..2922460 100644 --- a/configure.ac +++ b/configure.ac @@ -41,6 +41,8 @@ AC_ARG_ENABLE([tls], [AS_HELP_STRING([--disable-tls], [disable TLS support])]) AC_ARG_ENABLE([cares], [AS_HELP_STRING([--enable-cares], [use c-ares for DNS resolution])]) +AC_ARG_ENABLE([getrandom], + [AS_HELP_STRING([--disable-getrandom], [disable usage of the getrandom() system call])]) AC_ARG_ENABLE([fuzzing], [AS_HELP_STRING([--enable-fuzzing], [turn on fuzzing test])], @@ -96,6 +98,12 @@ elif test "x$enable_tls" != xno; then )]) fi +AC_CHECK_FUNCS([getrandom], [], [enable_getrandom=no]) +if test "$enable_getrandom" = "no"; then + AC_DEFINE(DONT_USE_GETRANDOM) + AC_MSG_NOTICE([libstrophe will not use the getrandom() system call]) +fi + with_parser="" if test "x$with_libxml2" != xyes; then PKG_CHECK_MODULES([expat], [expat >= 2.0.0], diff --git a/src/rand.c b/src/rand.c index 6c96fff..4f56a43 100644 --- a/src/rand.c +++ b/src/rand.c @@ -23,13 +23,23 @@ #include /* memeset */ #include /* clock, time */ +#if !defined(DONT_USE_GETRANDOM) && defined(__linux__) && \ + defined(__GLIBC_PREREQ) +#if __GLIBC_PREREQ(2, 25) +#define USE_GETRANDOM +#include +#include +#endif +#endif + #include "common.h" /* xmpp_alloc, xmpp_free */ #include "ostypes.h" /* uint8_t, uint32_t, size_t */ -#include "sha1.h" -#include "snprintf.h" /* xmpp_snprintf */ #include "rand.h" /* xmpp_rand_t */ +#ifndef USE_GETRANDOM +#include "sha1.h" + #define outlen SHA1_DIGEST_SIZE #define seedlen (440 / 8) #define reseed_interval 0x7fffffff @@ -285,6 +295,51 @@ void xmpp_rand_bytes(xmpp_rand_t *rand, unsigned char *output, size_t len) } } +#else + +static int _read_getrandom(void *p, size_t n) +{ + unsigned char *q = (unsigned char *)p; + while (n > 0u) { + ssize_t ret = getrandom(q, n, 0); + if (ret < 0) { + if (errno == EINTR) { + continue; + } + return 1; + } + q += ret; + n -= (size_t)ret; + } + return 0; +} + +struct _xmpp_rand_t { + char nothing; +}; + +static xmpp_rand_t _xmpp_rand; + +xmpp_rand_t *xmpp_rand_new(xmpp_ctx_t *ctx) +{ + UNUSED(ctx); + return &_xmpp_rand; +} + +void xmpp_rand_free(xmpp_ctx_t *ctx, xmpp_rand_t *rand) +{ + UNUSED(ctx); + assert(rand == &_xmpp_rand); +} + +void xmpp_rand_bytes(xmpp_rand_t *rand, unsigned char *output, size_t len) +{ + assert(rand == &_xmpp_rand); + assert(_read_getrandom(output, len) == 0); +} + +#endif + int xmpp_rand(xmpp_rand_t *rand) { int result; diff --git a/tests/test_rand.c b/tests/test_rand.c index 19c47fb..6d97791 100644 --- a/tests/test_rand.c +++ b/tests/test_rand.c @@ -20,6 +20,8 @@ /* include rand.c to access private structures and functions */ #include "rand.c" +#ifndef USE_GETRANDOM + /* stubs to build test without whole libstrophe */ void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size) { @@ -160,3 +162,19 @@ int main() return 0; } + +#else + +int main() +{ + uint8_t output[1024]; + xmpp_rand_t *rand = xmpp_rand_new(NULL); + + assert(rand != NULL); + /* this would assert if it failed */ + xmpp_rand_bytes(rand, output, sizeof(output)); + + return 0; +} + +#endif