static void wrap_nettle_rnd_refresh(void *_ctx) { struct generators_ctx_st *ctx = _ctx; char tmp; /* force reseed */ ctx->nonce.counter = prng_reseed_limits[GNUTLS_RND_NONCE]+1; ctx->normal.counter = prng_reseed_limits[GNUTLS_RND_RANDOM]+1; wrap_nettle_rnd(_ctx, GNUTLS_RND_NONCE, &tmp, 1); wrap_nettle_rnd(_ctx, GNUTLS_RND_RANDOM, &tmp, 1); return; }
static void wrap_nettle_rnd_refresh(void *_ctx) { uint8_t nonce_key[NONCE_KEY_SIZE]; /* this call refreshes the random context */ wrap_nettle_rnd(&rnd_ctx, GNUTLS_RND_RANDOM, nonce_key, sizeof(nonce_key)); RND_LOCK(&nonce_ctx); nonce_rng_init(&nonce_ctx, nonce_key, sizeof(nonce_key), 0); RND_UNLOCK(&nonce_ctx); return; }
static int wrap_nettle_rnd(void *_ctx, int level, void *data, size_t datasize) { struct generators_ctx_st *ctx = _ctx; struct prng_ctx_st *prng_ctx; int ret, reseed = 0; uint8_t new_key[PRNG_KEY_SIZE]; time_t now; if (level == GNUTLS_RND_RANDOM || level == GNUTLS_RND_KEY) prng_ctx = &ctx->normal; else if (level == GNUTLS_RND_NONCE) prng_ctx = &ctx->nonce; else return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED); /* Two reasons for this memset(): * 1. avoid getting filled with valgrind warnings * 2. avoid a cipher/PRNG failure to expose stack data */ memset(data, 0, datasize); now = gnutls_time(0); /* We re-seed based on time in addition to output data. That is, * to prevent a temporal state compromise to become permanent for low * traffic sites */ if (unlikely(_gnutls_detect_fork(prng_ctx->forkid))) { reseed = 1; } else { if (now > prng_ctx->last_reseed + prng_reseed_time[level]) reseed = 1; } if (reseed != 0 || prng_ctx->counter > prng_reseed_limits[level]) { if (level == GNUTLS_RND_NONCE) { ret = wrap_nettle_rnd(_ctx, GNUTLS_RND_RANDOM, new_key, sizeof(new_key)); } else { /* we also use the system entropy to reduce the impact * of a temporal state compromise for these two levels. */ ret = _rnd_get_system_entropy(new_key, sizeof(new_key)); } if (ret < 0) { gnutls_assert(); goto cleanup; } ret = single_prng_init(prng_ctx, new_key, sizeof(new_key), 0); if (ret < 0) { gnutls_assert(); goto cleanup; } prng_ctx->last_reseed = now; prng_ctx->forkid = _gnutls_get_forkid(); } chacha_crypt(&prng_ctx->ctx, datasize, data, data); prng_ctx->counter += datasize; if (level == GNUTLS_RND_KEY) { /* prevent backtracking */ ret = wrap_nettle_rnd(_ctx, GNUTLS_RND_RANDOM, new_key, sizeof(new_key)); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = single_prng_init(prng_ctx, new_key, sizeof(new_key), 0); if (ret < 0) { gnutls_assert(); goto cleanup; } } ret = 0; cleanup: return ret; }