summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-03-01 10:18:14 +0100
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2017-03-06 22:24:33 +0100
commit9735c552ab4496ec48518108db75eaa79479785f (patch)
tree4ea14736227478dc2abe1c8ac6742fb63e305860
parent995a82a08d4b303daee05ae816ba0fbc96d38249 (diff)
downloadgnutls-9735c552ab4496ec48518108db75eaa79479785f.tar.gz
nettle/rnd: use two random generators instead of 3
That combines the levels GNUTLS_RND_RANDOM and GNUTLS_RND_KEY, while at the same time makes sure that backtracking is impossible on the GNUTLS_RND_KEY level, by reinitializing the RNG after a call requesting data for the GNUTLS_RND_KEY level. Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r--lib/nettle/rnd.c45
1 files changed, 26 insertions, 19 deletions
diff --git a/lib/nettle/rnd.c b/lib/nettle/rnd.c
index fd0ad9e668..71390645ea 100644
--- a/lib/nettle/rnd.c
+++ b/lib/nettle/rnd.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010-2012 Free Software Foundation, Inc.
- * Copyright (C) 2000, 2001, 2008 Niels Möller
+ * Copyright (C) 2016-2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
@@ -33,12 +33,17 @@
#include <minmax.h>
#define PRNG_KEY_SIZE CHACHA_KEY_SIZE
-/* after this number of bytes PRNG will rekey */
+/* For a high level description see the documentation and
+ * the 'Random number generation' section of chapter
+ * 'Using GnuTLS as a cryptographic library'.
+ */
+
+/* after this number of bytes PRNG will rekey */
static const unsigned prng_reseed_limits[] = {
[GNUTLS_RND_NONCE] = 1024*1024, /* 1 MB */
[GNUTLS_RND_RANDOM] = 16*1024, /* 16 kb */
- [GNUTLS_RND_KEY] = 1024 /* 1 kb */
+ [GNUTLS_RND_KEY] = 16*1024 /* same as GNUTLS_RND_RANDOM */
};
struct prng_ctx_st {
@@ -50,7 +55,6 @@ struct prng_ctx_st {
struct generators_ctx_st {
struct prng_ctx_st nonce; /* GNUTLS_RND_NONCE */
struct prng_ctx_st normal; /* GNUTLS_RND_RANDOM */
- struct prng_ctx_st strong; /* GNUTLS_RND_KEY */
};
@@ -106,7 +110,7 @@ static int single_prng_init(struct prng_ctx_st *ctx,
static int wrap_nettle_rnd_init(void **_ctx)
{
int ret;
- uint8_t new_key[PRNG_KEY_SIZE*3];
+ uint8_t new_key[PRNG_KEY_SIZE*2];
struct generators_ctx_st *ctx;
ctx = calloc(1, sizeof(*ctx));
@@ -126,19 +130,13 @@ static int wrap_nettle_rnd_init(void **_ctx)
goto fail;
}
- /* initialize the normal RNG */
+ /* 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;
}
- ret = single_prng_init(&ctx->strong, new_key+2*PRNG_KEY_SIZE, PRNG_KEY_SIZE, 1);
- if (ret < 0) {
- gnutls_assert();
- goto fail;
- }
-
*_ctx = ctx;
return 0;
@@ -153,11 +151,10 @@ 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];
- if (level == GNUTLS_RND_RANDOM)
+ if (level == GNUTLS_RND_RANDOM || level == GNUTLS_RND_KEY)
prng_ctx = &ctx->normal;
- else if (level == GNUTLS_RND_KEY)
- prng_ctx = &ctx->strong;
else if (level == GNUTLS_RND_NONCE)
prng_ctx = &ctx->nonce;
else
@@ -173,8 +170,6 @@ wrap_nettle_rnd(void *_ctx, int level, void *data, size_t datasize)
}
if (reseed != 0 || prng_ctx->counter > prng_reseed_limits[level]) {
- uint8_t new_key[PRNG_KEY_SIZE];
-
if (level == GNUTLS_RND_NONCE) {
ret = wrap_nettle_rnd(_ctx, GNUTLS_RND_RANDOM, new_key, sizeof(new_key));
} else {
@@ -200,6 +195,20 @@ wrap_nettle_rnd(void *_ctx, int level, void *data, size_t datasize)
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:
@@ -214,11 +223,9 @@ static void wrap_nettle_rnd_refresh(void *_ctx)
/* force reseed */
ctx->nonce.counter = prng_reseed_limits[GNUTLS_RND_NONCE]+1;
ctx->normal.counter = prng_reseed_limits[GNUTLS_RND_RANDOM]+1;
- ctx->strong.counter = prng_reseed_limits[GNUTLS_RND_KEY]+1;
wrap_nettle_rnd(_ctx, GNUTLS_RND_NONCE, &tmp, 1);
wrap_nettle_rnd(_ctx, GNUTLS_RND_RANDOM, &tmp, 1);
- wrap_nettle_rnd(_ctx, GNUTLS_RND_KEY, &tmp, 1);
return;
}