diff --git a/lib/nettle/int/drbg-aes-self-test.c b/lib/nettle/int/drbg-aes-self-test.c
index 9c87453..eb62cf0 100644
--- a/lib/nettle/int/drbg-aes-self-test.c
+++ b/lib/nettle/int/drbg-aes-self-test.c
@@ -104,7 +104,8 @@ int drbg_aes_self_test(void)
struct drbg_aes_ctx test_ctx;
struct drbg_aes_ctx test_ctx2;
struct priv_st priv;
- int ret;
+ int ret, saved;
+ uint8_t *tmp;
unsigned char result[16];
memset(&priv, 0, sizeof(priv));
@@ -119,26 +120,32 @@ int drbg_aes_self_test(void)
return 0;
}
+ tmp = gnutls_malloc(MAX_DRBG_AES_GENERATE_SIZE+1);
+ if (tmp == NULL) {
+ gnutls_assert();
+ return 0;
+ }
+
for (i = 0; i < sizeof(tv) / sizeof(tv[0]); i++) {
/* Setup the key. */
ret =
drbg_aes_init(&test_ctx, DRBG_AES_SEED_SIZE, tv[i].entropy,
strlen(tv[i].pstring), (void *)tv[i].pstring);
if (ret == 0)
- return 0;
+ goto fail;
if (drbg_aes_is_seeded(&test_ctx) == 0)
- return 0;
+ goto fail;
/* Get and compare the first three results. */
for (j = 0; j < 3; j++) {
/* Compute the next value. */
if (drbg_aes_random(&test_ctx, 16, result) == 0)
- return 0;
+ goto fail;
/* Compare it to the known value. */
if (memcmp(result, tv[i].res[j], 16) != 0) {
- return 0;
+ goto fail;
}
}
@@ -146,20 +153,72 @@ int drbg_aes_self_test(void)
drbg_aes_reseed(&test_ctx, DRBG_AES_SEED_SIZE,
tv[i].entropy, 0, NULL);
if (ret == 0)
- return 0;
+ goto fail;
if (drbg_aes_random(&test_ctx, 16, result) == 0)
- return 0;
+ goto fail;
if (memcmp(result, tv[i].res[3], 16) != 0) {
- return 0;
+ goto fail;
}
/* test the error handling of drbg_aes_random() */
+ saved = test_ctx.reseed_counter;
test_ctx.reseed_counter = DRBG_AES_RESEED_TIME+1;
if (drbg_aes_random(&test_ctx, 16, result) != 0) {
gnutls_assert();
- return 0;
+ goto fail;
+ }
+ test_ctx.reseed_counter = saved;
+
+ ret = drbg_aes_random(&test_ctx, MAX_DRBG_AES_GENERATE_SIZE+1, tmp);
+ if (ret == 0) {
+ gnutls_assert();
+ goto fail;
+ }
+
+ /* test the low-level function */
+ ret = drbg_aes_generate(&test_ctx, MAX_DRBG_AES_GENERATE_SIZE+1, tmp, 0, NULL);
+ if (ret != 0) {
+ gnutls_assert();
+ goto fail;
+ }
+
+ /* Test of the reseed function for error handling */
+ ret =
+ drbg_aes_reseed(&test_ctx, DRBG_AES_SEED_SIZE*2,
+ (uint8_t*)tv, 0, NULL);
+ if (ret != 0)
+ goto fail;
+
+ ret =
+ drbg_aes_reseed(&test_ctx, DRBG_AES_SEED_SIZE,
+ tv[i].entropy, DRBG_AES_SEED_SIZE*2, (uint8_t*)tv);
+ if (ret != 0)
+ goto fail;
+
+ /* check whether reseed detection works */
+ if (i==0) {
+ ret =
+ drbg_aes_reseed(&test_ctx, DRBG_AES_SEED_SIZE,
+ tv[i].entropy, 0, NULL);
+ if (ret == 0)
+ goto fail;
+
+ saved = test_ctx.reseed_counter;
+ test_ctx.reseed_counter = DRBG_AES_RESEED_TIME-4;
+ for (j=0;j<5;j++) {
+ if (drbg_aes_random(&test_ctx, 1, result) == 0) {
+ gnutls_assert();
+ goto fail;
+ }
+ }
+ /* that should fail */
+ if (drbg_aes_random(&test_ctx, 1, result) != 0) {
+ gnutls_assert();
+ goto fail;
+ }
+ test_ctx.reseed_counter = saved;
}
/* test deinit, which is zeroize_key() */
@@ -167,9 +226,15 @@ int drbg_aes_self_test(void)
zeroize_key(&test_ctx, sizeof(test_ctx));
if (memcmp(&test_ctx, &test_ctx2, sizeof(test_ctx)) == 0) {
gnutls_assert();
- return 0;
+ goto fail;
}
+
+
}
+ free(tmp);
return 1;
+ fail:
+ free(tmp);
+ return 0;
}
diff --git a/lib/nettle/int/drbg-aes.c b/lib/nettle/int/drbg-aes.c
index 5ff2484..43df5e1 100644
--- a/lib/nettle/int/drbg-aes.c
+++ b/lib/nettle/int/drbg-aes.c
@@ -22,6 +22,7 @@
#include <config.h>
#include <drbg-aes.h>
+#include <gnutls_errors.h>
#include <nettle/memxor.h>
#include <nettle/aes.h>
#include <minmax.h>
@@ -67,7 +68,6 @@ drbg_aes_update(struct drbg_aes_ctx *ctx,
memcpy(ctx->v, &tmp[DRBG_AES_KEY_SIZE], AES_BLOCK_SIZE);
- ctx->reseed_counter = 1;
ctx->seeded = 1;
}
@@ -93,6 +93,27 @@ drbg_aes_reseed(struct drbg_aes_ctx *ctx,
memxor(tmp, entropy, entropy_size);
drbg_aes_update(ctx, tmp);
+ ctx->reseed_counter = 1;
+
+ return 1;
+}
+
+int drbg_aes_random(struct drbg_aes_ctx *ctx, unsigned length, uint8_t * dst)
+{
+ unsigned p_len;
+ int left = length;
+ uint8_t *p = dst;
+ int ret;
+
+ while(left > 0) {
+ p_len = MIN(MAX_DRBG_AES_GENERATE_SIZE, left);
+ ret = drbg_aes_generate(ctx, p_len, p, 0, 0);
+ if (ret == 0)
+ return ret;
+
+ p += p_len;
+ left -= p_len;
+ }
return 1;
}
@@ -106,11 +127,14 @@ int drbg_aes_generate(struct drbg_aes_ctx *ctx, unsigned length, uint8_t * dst,
unsigned left;
if (ctx->seeded == 0)
- return 0;
+ return gnutls_assert_val(0);
+
+ if (length > MAX_DRBG_AES_GENERATE_SIZE)
+ return gnutls_assert_val(0);
if (add_size > 0) {
if (add_size > DRBG_AES_SEED_SIZE)
- return 0;
+ return gnutls_assert_val(0);
memcpy(seed, add, add_size);
if (add_size != DRBG_AES_SEED_SIZE)
memset(&seed[add_size], 0, DRBG_AES_SEED_SIZE - add_size);
@@ -140,7 +164,7 @@ int drbg_aes_generate(struct drbg_aes_ctx *ctx, unsigned length, uint8_t * dst,
/* if detected loop */
if (memcmp(dst, ctx->prev_block, AES_BLOCK_SIZE) == 0) {
_gnutls_switch_lib_state(LIB_STATE_ERROR);
- return 0;
+ return gnutls_assert_val(0);
}
memcpy(ctx->prev_block, dst, AES_BLOCK_SIZE);
@@ -154,7 +178,7 @@ int drbg_aes_generate(struct drbg_aes_ctx *ctx, unsigned length, uint8_t * dst,
/* if detected loop */
if (memcmp(tmp, ctx->prev_block, AES_BLOCK_SIZE) == 0) {
_gnutls_switch_lib_state(LIB_STATE_ERROR);
- return 0;
+ return gnutls_assert_val(0);
}
memcpy(ctx->prev_block, tmp, AES_BLOCK_SIZE);
@@ -162,7 +186,7 @@ int drbg_aes_generate(struct drbg_aes_ctx *ctx, unsigned length, uint8_t * dst,
}
if (ctx->reseed_counter > DRBG_AES_RESEED_TIME)
- return 0;
+ return gnutls_assert_val(0);
ctx->reseed_counter++;
drbg_aes_update(ctx, seed);
diff --git a/lib/nettle/int/drbg-aes.h b/lib/nettle/int/drbg-aes.h
index eb89be6..72608de 100644
--- a/lib/nettle/int/drbg-aes.h
+++ b/lib/nettle/int/drbg-aes.h
@@ -55,10 +55,13 @@ struct drbg_aes_ctx {
unsigned reseed_counter;
};
+/* max_number_of_bits_per_request */
+#define MAX_DRBG_AES_GENERATE_SIZE 65536 /* 2^19 */
+
/* This DRBG should be reseeded if reseed_counter exceeds
* that number. Otherwise drbg_aes_random() will fail.
*/
-#define DRBG_AES_RESEED_TIME 65536
+#define DRBG_AES_RESEED_TIME 16777216
/* The entropy provided in these functions should be of
* size DRBG_AES_SEED_SIZE. Additional data and pers.
@@ -74,7 +77,10 @@ drbg_aes_reseed(struct drbg_aes_ctx *ctx,
unsigned entropy_size, const uint8_t *entropy,
unsigned add_size, const uint8_t* add);
-#define drbg_aes_random(ctx, l, dst) drbg_aes_generate(ctx, l, dst, 0, NULL)
+/* our wrapper for the low-level drbg_aes_generate */
+int
+drbg_aes_random(struct drbg_aes_ctx *ctx, unsigned length,
+ uint8_t * dst);
int
drbg_aes_generate(struct drbg_aes_ctx *ctx, unsigned length,
diff --git a/tests/rng-fork.c b/tests/rng-fork.c
index ba9178e..45a18b4 100644
--- a/tests/rng-fork.c
+++ b/tests/rng-fork.c
@@ -53,6 +53,7 @@ void doit(void)
unsigned char buf1[64];
unsigned char buf2[64];
pid_t pid;
+ unsigned char *tmp;
int ret;
FILE *fp;
unsigned i;
@@ -119,6 +120,20 @@ void doit(void)
exit(1);
}
}
+#define TMP_SIZE (65*1024)
+ tmp = malloc(TMP_SIZE);
+ if (tmp == NULL) {
+ fail("memory error\n");
+ exit(1);
+ }
+ for (i = 0; i <= 65539; i++) {
+ ret = gnutls_rnd(GNUTLS_RND_RANDOM, tmp, TMP_SIZE);
+ if (ret < 0) {
+ fail("Error iterating RNG-random more than %u times for %d data\n", i, TMP_SIZE);
+ exit(1);
+ }
+ }
+ free(tmp);
gnutls_global_deinit();
}