random: split initialization in preinit and init

This makes gnutls not to initialize its random generator
before any randomness is really necessary. This allows to use
gnutls even in early boot in systems that have system calls which
may block waiting for entropy.
parent 2347c783
Pipeline #4608433 passed with stage
in 70 minutes 26 seconds
......@@ -73,7 +73,8 @@ typedef struct {
} gnutls_crypto_digest_st;
typedef struct gnutls_crypto_rnd {
int (*init) (void **ctx);
int (*preinit) (void **ctx); /* called as early as possible */
int (*init) (void **ctx); /* called prior to first usage of randomness */
int (*check) (void **ctx);
int (*rnd) (void *ctx, int level, void *data, size_t datasize);
void (*rnd_refresh) (void *ctx);
......
......@@ -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;
......
......@@ -164,6 +164,11 @@ static int _rngfips_ctx_reinit(struct fips_ctx *fctx)
return 0;
}
static int _rngfips_preinit(void **ctx)
{
return _rnd_system_entropy_init();
}
/* Initialize this random subsystem. */
static int _rngfips_init(void **_ctx)
{
......@@ -172,10 +177,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);
......@@ -260,6 +261,7 @@ static int selftest_kat(void)
gnutls_crypto_rnd_st _gnutls_fips_rnd_ops = {
.init = _rngfips_init,
.preinit = _rngfips_preinit,
.check = _rndfips_check,
.deinit = _rngfips_deinit,
.rnd = _rngfips_rnd,
......
......@@ -198,6 +198,11 @@ static int nonce_rng_init(struct nonce_ctx_st *ctx,
/* API functions */
static int wrap_nettle_rnd_preinit(void **ctx)
{
return _rnd_system_entropy_init();
}
static int wrap_nettle_rnd_init(void **ctx)
{
int ret;
......@@ -218,12 +223,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);
......@@ -372,6 +371,7 @@ static void wrap_nettle_rnd_refresh(void *_ctx)
int crypto_rnd_prio = INT_MAX;
gnutls_crypto_rnd_st _gnutls_rnd_ops = {
.preinit = wrap_nettle_rnd_preinit,
.init = wrap_nettle_rnd_init,
.check = wrap_nettle_rnd_check,
.deinit = wrap_nettle_rnd_deinit,
......
......@@ -26,11 +26,30 @@
#include "gnutls_int.h"
#include "errors.h"
#include <random.h>
#include "locks.h"
#include <fips.h>
void *gnutls_rnd_ctx;
int _gnutls_rnd_init(void)
GNUTLS_STATIC_MUTEX(gnutls_rnd_init_mutex);
static int rnd_initialized = 0;
inline static int _gnutls_rnd_init(void)
{
GNUTLS_STATIC_MUTEX_LOCK(gnutls_rnd_init_mutex);
if (unlikely(!rnd_initialized && _gnutls_rnd_ops.init != NULL)) {
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;
}
int _gnutls_rnd_preinit(void)
{
#ifdef ENABLE_FIPS140
/* The FIPS140 random generator is only enabled when we are compiled
......@@ -45,8 +64,8 @@ int _gnutls_rnd_init(void)
}
#endif
if (_gnutls_rnd_ops.init != NULL) {
if (_gnutls_rnd_ops.init(&gnutls_rnd_ctx) < 0) {
if (_gnutls_rnd_ops.preinit != NULL) {
if (_gnutls_rnd_ops.preinit(&gnutls_rnd_ctx) < 0) {
gnutls_assert();
return GNUTLS_E_RANDOM_FAILED;
}
......@@ -57,9 +76,10 @@ 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;
return;
}
......@@ -81,8 +101,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 +127,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_ctx);
}
......@@ -30,23 +30,11 @@ 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)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment