diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-10-14 14:16:51 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2016-11-04 02:54:06 +0100 |
commit | e4c739fe0b9e568333bf43358fbc3db6b96fe1a1 (patch) | |
tree | 5846882d8a2ac908e9587a484274e1c4154e3811 | |
parent | fea6c3ca8f869752f4f79f724fbb8736e961fd88 (diff) | |
download | gnutls-e4c739fe0b9e568333bf43358fbc3db6b96fe1a1.tar.gz |
rng: split initialization in preinit and init
This makes gnutls to initialize its random generator on the
first call to gnutls_rnd(). That prevents blocking due to
getrandom() on a constructor; that change allows to use gnutls-linked
applications even in early boot in systems where getrandom() blocks
waiting for entropy.
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | lib/global.c | 2 | ||||
-rw-r--r-- | lib/locks.h | 4 | ||||
-rw-r--r-- | lib/nettle/rnd-fips.c | 4 | ||||
-rw-r--r-- | lib/nettle/rnd.c | 6 | ||||
-rw-r--r-- | lib/random.c | 85 | ||||
-rw-r--r-- | lib/random.h | 22 |
7 files changed, 83 insertions, 41 deletions
diff --git a/configure.ac b/configure.ac index 2e51075915..4336d334e5 100644 --- a/configure.ac +++ b/configure.ac @@ -189,6 +189,7 @@ AM_SUBST_NOTMAKE([DEFINE_IOVEC_T]) dnl Need netinet/tcp.h for TCP_FASTOPEN AC_CHECK_HEADERS([netinet/tcp.h]) +AC_CHECK_HEADERS([stdatomic.h]) AC_ARG_ENABLE(padlock, AS_HELP_STRING([--disable-padlock], [unconditionally disable padlock acceleration]), diff --git a/lib/global.c b/lib/global.c index 0b57f3d6d7..d31d5bcae9 100644 --- a/lib/global.c +++ b/lib/global.c @@ -303,7 +303,7 @@ static int _gnutls_global_init(unsigned constructor) } /* Initialize the random generator */ - ret = _gnutls_rnd_init(); + ret = _gnutls_rnd_preinit(); if (ret < 0) { gnutls_assert(); goto out; diff --git a/lib/locks.h b/lib/locks.h index 58077545e0..b1efbb52e8 100644 --- a/lib/locks.h +++ b/lib/locks.h @@ -27,6 +27,10 @@ #include "gnutls_int.h" #include <system.h> +#ifdef HAVE_STDATOMIC_H +# include <stdatomic.h> +#endif + extern mutex_init_func gnutls_mutex_init; extern mutex_deinit_func gnutls_mutex_deinit; extern mutex_lock_func gnutls_mutex_lock; diff --git a/lib/nettle/rnd-fips.c b/lib/nettle/rnd-fips.c index 59795a9529..08077014f1 100644 --- a/lib/nettle/rnd-fips.c +++ b/lib/nettle/rnd-fips.c @@ -172,10 +172,6 @@ static int _rngfips_init(void **_ctx) struct fips_ctx *ctx; int ret; - ret = _rnd_system_entropy_init(); - if (ret < 0) - return gnutls_assert_val(ret); - ctx = gnutls_calloc(1, sizeof(*ctx)); if (ctx == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); diff --git a/lib/nettle/rnd.c b/lib/nettle/rnd.c index 39b99e1916..c4fbc486f5 100644 --- a/lib/nettle/rnd.c +++ b/lib/nettle/rnd.c @@ -218,12 +218,6 @@ static int wrap_nettle_rnd_init(void **ctx) return ret; } - ret = _rnd_system_entropy_init(); - if (ret < 0) { - gnutls_assert(); - return ret; - } - /* initialize the main RNG */ yarrow256_init(&rnd_ctx.yctx, SOURCES, rnd_ctx.ysources); diff --git a/lib/random.c b/lib/random.c index d7f18f2ce7..977d7aa3ec 100644 --- a/lib/random.c +++ b/lib/random.c @@ -26,30 +26,80 @@ #include "gnutls_int.h" #include "errors.h" #include <random.h> +#include "locks.h" #include <fips.h> void *gnutls_rnd_ctx; +GNUTLS_STATIC_MUTEX(gnutls_rnd_init_mutex); -int _gnutls_rnd_init(void) +#ifdef HAVE_STDATOMIC_H +static atomic_uint rnd_initialized = 0; + +inline static int _gnutls_rnd_init(void) +{ + if (unlikely(!rnd_initialized)) { + if (_gnutls_rnd_ops.init == NULL) { + rnd_initialized = 1; + return 0; + } + + GNUTLS_STATIC_MUTEX_LOCK(gnutls_rnd_init_mutex); + if (!rnd_initialized) { + if (_gnutls_rnd_ops.init(&gnutls_rnd_ctx) < 0) { + gnutls_assert(); + GNUTLS_STATIC_MUTEX_UNLOCK(gnutls_rnd_init_mutex); + return GNUTLS_E_RANDOM_FAILED; + } + rnd_initialized = 1; + } + GNUTLS_STATIC_MUTEX_UNLOCK(gnutls_rnd_init_mutex); + } + return 0; +} +#else +static unsigned rnd_initialized = 0; + +inline static int _gnutls_rnd_init(void) +{ + GNUTLS_STATIC_MUTEX_LOCK(gnutls_rnd_init_mutex); + if (unlikely(!rnd_initialized)) { + if (_gnutls_rnd_ops.init == NULL) { + rnd_initialized = 1; + GNUTLS_STATIC_MUTEX_UNLOCK(gnutls_rnd_init_mutex); + return 0; + } + + if (_gnutls_rnd_ops.init(&gnutls_rnd_ctx) < 0) { + gnutls_assert(); + GNUTLS_STATIC_MUTEX_UNLOCK(gnutls_rnd_init_mutex); + return GNUTLS_E_RANDOM_FAILED; + } + rnd_initialized = 1; + } + GNUTLS_STATIC_MUTEX_UNLOCK(gnutls_rnd_init_mutex); + return 0; +} +#endif + +int _gnutls_rnd_preinit(void) { + int ret; + #ifdef ENABLE_FIPS140 /* The FIPS140 random generator is only enabled when we are compiled * with FIPS support, _and_ the system requires FIPS140. */ if (_gnutls_fips_mode_enabled() == 1) { - int ret; - ret = gnutls_crypto_rnd_register(100, &_gnutls_fips_rnd_ops); if (ret < 0) return ret; } #endif - if (_gnutls_rnd_ops.init != NULL) { - if (_gnutls_rnd_ops.init(&gnutls_rnd_ctx) < 0) { - gnutls_assert(); - return GNUTLS_E_RANDOM_FAILED; - } + ret = _rnd_system_entropy_init(); + if (ret < 0) { + gnutls_assert(); + return GNUTLS_E_RANDOM_FAILED; } return 0; @@ -57,9 +107,12 @@ int _gnutls_rnd_init(void) void _gnutls_rnd_deinit(void) { - if (_gnutls_rnd_ops.deinit != NULL) { + if (rnd_initialized && _gnutls_rnd_ops.deinit != NULL) { _gnutls_rnd_ops.deinit(gnutls_rnd_ctx); } + rnd_initialized = 0; + + _rnd_system_entropy_deinit(); return; } @@ -81,8 +134,17 @@ void _gnutls_rnd_deinit(void) **/ int gnutls_rnd(gnutls_rnd_level_t level, void *data, size_t len) { + int ret; FAIL_IF_LIB_ERROR; - return _gnutls_rnd(level, data, len); + + if (unlikely((ret=_gnutls_rnd_init()) < 0)) + return gnutls_assert_val(ret); + + if (likely(len > 0)) { + return _gnutls_rnd_ops.rnd(gnutls_rnd_ctx, level, data, + len); + } + return 0; } /** @@ -98,5 +160,6 @@ int gnutls_rnd(gnutls_rnd_level_t level, void *data, size_t len) **/ void gnutls_rnd_refresh(void) { - _gnutls_rnd_refresh(); + if (rnd_initialized && _gnutls_rnd_ops.rnd_refresh) + _gnutls_rnd_ops.rnd_refresh(gnutls_rnd_ctx); } diff --git a/lib/random.h b/lib/random.h index 1538ec8da6..2ef7bc4684 100644 --- a/lib/random.h +++ b/lib/random.h @@ -31,31 +31,15 @@ extern int crypto_rnd_prio; extern void *gnutls_rnd_ctx; extern gnutls_crypto_rnd_st _gnutls_rnd_ops; -inline static int -_gnutls_rnd(gnutls_rnd_level_t level, void *data, size_t len) -{ - if (len > 0) { - return _gnutls_rnd_ops.rnd(gnutls_rnd_ctx, level, data, - len); - } - return 0; -} - -inline static void _gnutls_rnd_refresh(void) -{ - _gnutls_rnd_ops.rnd_refresh(gnutls_rnd_ctx); -} +#define _gnutls_rnd gnutls_rnd +#define _gnutls_rnd_refresh gnutls_rnd_refresh void _gnutls_rnd_deinit(void); -int _gnutls_rnd_init(void); +int _gnutls_rnd_preinit(void); inline static int _gnutls_rnd_check(void) { return _rnd_system_entropy_check(); } -#ifndef _WIN32 -extern int _gnutls_urandom_fd; -#endif - #endif |