/* Initializes the nonce level random generator. * * the @nonce_key must be provided. * * @init must be non zero on first initialization, and * zero on any subsequent reinitializations. */ static int nonce_rng_init(struct nonce_ctx_st *ctx, uint8_t nonce_key[NONCE_KEY_SIZE], unsigned nonce_key_size, unsigned init) { uint8_t iv[8]; int ret; if (init == 0) { /* use the previous key to generate IV as well */ memset(iv, 0, sizeof(iv)); /* to prevent valgrind from whinning */ salsa20r12_crypt(&ctx->ctx, sizeof(iv), iv, iv); /* Add key continuity by XORing the new key with data generated * from the old key */ salsa20r12_crypt(&ctx->ctx, nonce_key_size, nonce_key, nonce_key); } else { ctx->forkid = _gnutls_get_forkid(); /* when initializing read the IV from the system randomness source */ ret = _rnd_get_system_entropy(iv, sizeof(iv)); if (ret < 0) return gnutls_assert_val(ret); } salsa20_set_key(&ctx->ctx, nonce_key_size, nonce_key); salsa20_set_iv(&ctx->ctx, iv); zeroize_key(nonce_key, nonce_key_size); ctx->counter = 0; return 0; }
static int do_device_source(struct rnd_ctx_st *ctx, int init, struct event_st *event) { unsigned int read_size = DEVICE_READ_SIZE; int ret; if (init) { memcpy(&ctx->device_last_read, &event->now, sizeof(ctx->device_last_read)); read_size = DEVICE_READ_SIZE_MAX; /* initially read more data */ } if ((init || (timespec_sub_sec(&event->now, &ctx->device_last_read) > DEVICE_READ_INTERVAL))) { /* More than 20 minutes since we last read the device */ uint8_t buf[DEVICE_READ_SIZE_MAX]; ret = _rnd_get_system_entropy(buf, read_size); if (ret < 0) return gnutls_assert_val(ret); memcpy(&ctx->device_last_read, &event->now, sizeof(ctx->device_last_read)); return yarrow256_update(&ctx->yctx, RANDOM_SOURCE_DEVICE, read_size * 8 / 2 /* we trust the RNG */ , read_size, buf); } return 0; }
static int wrap_nettle_rnd_init(void **ctx) { int ret; struct event_st event; uint8_t nonce_key[NONCE_KEY_SIZE]; memset(&rnd_ctx, 0, sizeof(rnd_ctx)); ret = gnutls_mutex_init(&nonce_ctx.mutex); if (ret < 0) { gnutls_assert(); return ret; } ret = gnutls_mutex_init(&rnd_ctx.mutex); if (ret < 0) { gnutls_assert(); return ret; } /* initialize the main RNG */ yarrow256_init(&rnd_ctx.yctx, SOURCES, rnd_ctx.ysources); _rnd_get_event(&event); rnd_ctx.forkid = _gnutls_get_forkid(); ret = do_device_source(&rnd_ctx, 1, &event); if (ret < 0) { gnutls_assert(); return ret; } ret = do_trivia_source(&rnd_ctx, 1, &event); if (ret < 0) { gnutls_assert(); return ret; } yarrow256_slow_reseed(&rnd_ctx.yctx); /* initialize the nonce RNG */ ret = _rnd_get_system_entropy(nonce_key, sizeof(nonce_key)); if (ret < 0) return gnutls_assert_val(ret); ret = nonce_rng_init(&nonce_ctx, nonce_key, sizeof(nonce_key), 1); if (ret < 0) return gnutls_assert_val(ret); return 0; }
/* Reseed a generator. */ static int drbg_reseed(struct drbg_aes_ctx *ctx) { uint8_t buffer[DRBG_AES_SEED_SIZE]; int ret; /* The other two generators are seeded from /dev/random. */ ret = _rnd_get_system_entropy(buffer, sizeof(buffer)); if (ret < 0) return gnutls_assert_val(ret); drbg_aes_reseed(ctx, sizeof(buffer), buffer, 0, NULL); return 0; }
static int drbg_init(struct drbg_aes_ctx *ctx) { uint8_t buffer[DRBG_AES_SEED_SIZE]; int ret; /* Get a key from the standard RNG or from the entropy source. */ ret = _rnd_get_system_entropy(buffer, sizeof(buffer)); if (ret < 0) return gnutls_assert_val(ret); ret = drbg_aes_init(ctx, sizeof(buffer), buffer, PSTRING_SIZE, (void*)PSTRING); if (ret == 0) return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED); zeroize_key(buffer, sizeof(buffer)); return 0; }
static int wrap_nettle_rnd_nonce(void *_ctx, void *data, size_t datasize) { int ret, reseed = 0; uint8_t nonce_key[NONCE_KEY_SIZE]; /* we don't really need memset here, but otherwise we * get filled with valgrind warnings */ memset(data, 0, datasize); RND_LOCK(&nonce_ctx); if (_gnutls_detect_fork(nonce_ctx.forkid)) { reseed = 1; } if (reseed != 0 || nonce_ctx.counter > NONCE_RESEED_BYTES) { /* reseed nonce */ ret = _rnd_get_system_entropy(nonce_key, sizeof(nonce_key)); if (ret < 0) { gnutls_assert(); goto cleanup; } ret = nonce_rng_init(&nonce_ctx, nonce_key, sizeof(nonce_key), 0); if (ret < 0) { gnutls_assert(); goto cleanup; } nonce_ctx.forkid = _gnutls_get_forkid(); } salsa20r12_crypt(&nonce_ctx.ctx, datasize, data, data); nonce_ctx.counter += datasize; ret = 0; cleanup: RND_UNLOCK(&nonce_ctx); return ret; }
static int wrap_nettle_rnd_init(void **_ctx) { int ret; uint8_t new_key[PRNG_KEY_SIZE*2]; struct generators_ctx_st *ctx; ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); /* initialize the nonce RNG */ ret = _rnd_get_system_entropy(new_key, sizeof(new_key)); if (ret < 0) { gnutls_assert(); goto fail; } ret = single_prng_init(&ctx->nonce, new_key, PRNG_KEY_SIZE, 1); if (ret < 0) { gnutls_assert(); goto fail; } /* initialize the random/key RNG */ ret = single_prng_init(&ctx->normal, new_key+PRNG_KEY_SIZE, PRNG_KEY_SIZE, 1); if (ret < 0) { gnutls_assert(); goto fail; } *_ctx = ctx; return 0; fail: gnutls_free(ctx); return ret; }
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; }