diff --git a/SOURCES/gnutls-3.3.8-fips-reseed.patch b/SOURCES/gnutls-3.3.8-fips-reseed.patch new file mode 100644 index 0000000..438edda --- /dev/null +++ b/SOURCES/gnutls-3.3.8-fips-reseed.patch @@ -0,0 +1,301 @@ +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(); + } diff --git a/SPECS/gnutls.spec b/SPECS/gnutls.spec index 8dd3b37..c612bb4 100644 --- a/SPECS/gnutls.spec +++ b/SPECS/gnutls.spec @@ -3,7 +3,7 @@ Summary: A TLS protocol implementation Name: gnutls Version: 3.3.8 -Release: 12%{?dist} +Release: 12%{?dist}.1 # The libraries are LGPLv2.1+, utilities are GPLv3+ License: GPLv3+ and LGPLv2+ Group: System Environment/Libraries @@ -57,6 +57,7 @@ Patch21: gnutls-3.3.8-fips-rnd-regr.patch Patch22: gnutls-3.3.8-urandom-fd-fips.patch Patch23: gnutls-3.3.8-rnd-reregister.patch Patch24: gnutls-3.3.8-handshake-reset3.patch +Patch25: gnutls-3.3.8-fips-reseed.patch # Wildcard bundling exception https://fedorahosted.org/fpc/ticket/174 Provides: bundled(gnulib) = 20130424 @@ -181,6 +182,7 @@ This package contains Guile bindings for the library. %patch22 -p1 -b .init-fd-fips %patch23 -p1 -b .reregister %patch24 -p1 -b .handshake-reset3 +%patch25 -p1 -b .fips-reseed sed 's/gnutls_srp.c//g' -i lib/Makefile.in sed 's/gnutls_srp.lo//g' -i lib/Makefile.in rm -f lib/minitasn1/*.c lib/minitasn1/*.h @@ -326,6 +328,10 @@ fi %endif %changelog +* Fri Jun 5 2015 Nikos Mavrogiannopoulos 3.3.8-12.1 +- Corrected reseed and respect of max_number_of_bits_per_request in + FIPS140-2 mode. Also enhanced the initial tests. (#1228199) + * Mon Jan 5 2015 Nikos Mavrogiannopoulos 3.3.8-12 - corrected fix of handshake buffer resets (#1153106)