Beispiel #1
0
/* 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;
}
Beispiel #2
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;
}
Beispiel #3
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;
}
Beispiel #4
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;
}
Beispiel #5
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;
}
Beispiel #6
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;
}
Beispiel #7
0
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;
}
Beispiel #8
0
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;
}