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 #include +#include #include #include #include @@ -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(); }