Blame SOURCES/gnutls-3.6.8-fips-rng-continuous.patch

8dd812
From c7a419e7868fd9342c1799a04d21c2ff6292c405 Mon Sep 17 00:00:00 2001
8dd812
From: Daiki Ueno <dueno@redhat.com>
8dd812
Date: Fri, 21 Jun 2019 15:49:26 +0200
8dd812
Subject: [PATCH] nettle/rnd-fips: add FIPS 140-2 continuous RNG test
8dd812
8dd812
This adds a continuous random number generator test as defined in FIPS
8dd812
140-2 4.9.2, by iteratively fetching fixed sized block from the system
8dd812
and comparing consecutive blocks.
8dd812
8dd812
Signed-off-by: Daiki Ueno <dueno@redhat.com>
8dd812
---
8dd812
 lib/nettle/rnd-fips.c | 102 +++++++++++++++++++++++++++++++++---------
8dd812
 1 file changed, 81 insertions(+), 21 deletions(-)
8dd812
8dd812
diff --git a/lib/nettle/rnd-fips.c b/lib/nettle/rnd-fips.c
8dd812
index ee68cf68d..ccb92d25a 100644
8dd812
--- a/lib/nettle/rnd-fips.c
8dd812
+++ b/lib/nettle/rnd-fips.c
8dd812
@@ -27,12 +27,13 @@
8dd812
 
8dd812
 #include "gnutls_int.h"
8dd812
 #include "errors.h"
8dd812
-#include <nettle/aes.h>
8dd812
-#include <nettle/memxor.h>
8dd812
-#include <locks.h>
8dd812
+#include <nettle/sha2.h>
8dd812
 #include <atfork.h>
8dd812
 #include <rnd-common.h>
8dd812
 
8dd812
+/* The block size is chosen arbitrarily */
8dd812
+#define ENTROPY_BLOCK_SIZE SHA256_DIGEST_SIZE
8dd812
+
8dd812
 /* This provides a random generator for gnutls. It uses
8dd812
  * two instances of the DRBG-AES-CTR generator, one for
8dd812
  * nonce level and another for the other levels of randomness.
8dd812
@@ -41,11 +42,13 @@ struct fips_ctx {
8dd812
 	struct drbg_aes_ctx nonce_context;
8dd812
 	struct drbg_aes_ctx normal_context;
8dd812
 	unsigned int forkid;
8dd812
+	uint8_t entropy_hash[SHA256_DIGEST_SIZE];
8dd812
 };
8dd812
 
8dd812
 static int _rngfips_ctx_reinit(struct fips_ctx *fctx);
8dd812
 static int _rngfips_ctx_init(struct fips_ctx *fctx);
8dd812
-static int drbg_reseed(struct drbg_aes_ctx *ctx);
8dd812
+static int drbg_reseed(struct fips_ctx *fctx, struct drbg_aes_ctx *ctx);
8dd812
+static int get_entropy(struct fips_ctx *fctx, uint8_t *buffer, size_t length);
8dd812
 
8dd812
 static int get_random(struct drbg_aes_ctx *ctx, struct fips_ctx *fctx,
8dd812
 		      void *buffer, size_t length)
8dd812
@@ -59,7 +62,7 @@ static int get_random(struct drbg_aes_ctx *ctx, struct fips_ctx *fctx,
8dd812
 	}
8dd812
 
8dd812
 	if (ctx->reseed_counter > DRBG_AES_RESEED_TIME) {
8dd812
-		ret = drbg_reseed(ctx);
8dd812
+		ret = drbg_reseed(fctx, ctx);
8dd812
 		if (ret < 0)
8dd812
 			return gnutls_assert_val(ret);
8dd812
 	}
8dd812
@@ -71,54 +74,111 @@ static int get_random(struct drbg_aes_ctx *ctx, struct fips_ctx *fctx,
8dd812
 	return 0;
8dd812
 }
8dd812
 
8dd812
+static int get_entropy(struct fips_ctx *fctx, uint8_t *buffer, size_t length)
8dd812
+{
8dd812
+	int ret;
8dd812
+	uint8_t block[ENTROPY_BLOCK_SIZE];
8dd812
+	uint8_t hash[SHA256_DIGEST_SIZE];
8dd812
+	struct sha256_ctx ctx;
8dd812
+	size_t total = 0;
8dd812
+
8dd812
+	/* For FIPS 140-2 4.9.2 continuous random number generator
8dd812
+	 * test, iteratively fetch fixed sized block from the system
8dd812
+	 * RNG and compare consecutive blocks.
8dd812
+	 *
8dd812
+	 * Note that we store the hash of the entropy block rather
8dd812
+	 * than the block itself for backward secrecy.
8dd812
+	 */
8dd812
+	while (total < length) {
8dd812
+		ret = _rnd_get_system_entropy(block, ENTROPY_BLOCK_SIZE);
8dd812
+		if (ret < 0)
8dd812
+			return gnutls_assert_val(ret);
8dd812
+
8dd812
+		sha256_init(&ctx;;
8dd812
+		sha256_update(&ctx, sizeof(block), block);
8dd812
+		sha256_digest(&ctx, sizeof(hash), hash);
8dd812
+
8dd812
+		if (memcmp(hash, fctx->entropy_hash, sizeof(hash)) == 0) {
8dd812
+			_gnutls_switch_lib_state(LIB_STATE_ERROR);
8dd812
+			return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
8dd812
+		}
8dd812
+		memcpy(fctx->entropy_hash, hash, sizeof(hash));
8dd812
+
8dd812
+		memcpy(buffer, block, MIN(length - total, sizeof(block)));
8dd812
+		total += sizeof(block);
8dd812
+		buffer += sizeof(block);
8dd812
+	}
8dd812
+	zeroize_key(block, sizeof(block));
8dd812
+
8dd812
+	return 0;
8dd812
+}
8dd812
+
8dd812
 #define PSTRING "gnutls-rng"
8dd812
 #define PSTRING_SIZE (sizeof(PSTRING)-1)
8dd812
-static int drbg_init(struct drbg_aes_ctx *ctx)
8dd812
+static int drbg_init(struct fips_ctx *fctx, struct drbg_aes_ctx *ctx)
8dd812
 {
8dd812
 	uint8_t buffer[DRBG_AES_SEED_SIZE];
8dd812
 	int ret;
8dd812
 
8dd812
-	/* Get a key from the standard RNG or from the entropy source.  */
8dd812
-	ret = _rnd_get_system_entropy(buffer, sizeof(buffer));
8dd812
+	ret = get_entropy(fctx, buffer, sizeof(buffer));
8dd812
 	if (ret < 0)
8dd812
 		return gnutls_assert_val(ret);
8dd812
 
8dd812
-	ret = drbg_aes_init(ctx, sizeof(buffer), buffer, PSTRING_SIZE, (void*)PSTRING);
8dd812
+	ret = drbg_aes_init(ctx, sizeof(buffer), buffer,
8dd812
+			    PSTRING_SIZE, (void*)PSTRING);
8dd812
+	zeroize_key(buffer, sizeof(buffer));
8dd812
 	if (ret == 0)
8dd812
 		return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
8dd812
 
8dd812
-	zeroize_key(buffer, sizeof(buffer));
8dd812
-
8dd812
-	return 0;
8dd812
+	return GNUTLS_E_SUCCESS;
8dd812
 }
8dd812
 
8dd812
 /* Reseed a generator. */
8dd812
-static int drbg_reseed(struct drbg_aes_ctx *ctx)
8dd812
+static int drbg_reseed(struct fips_ctx *fctx, struct drbg_aes_ctx *ctx)
8dd812
 {
8dd812
 	uint8_t buffer[DRBG_AES_SEED_SIZE];
8dd812
 	int ret;
8dd812
 
8dd812
-	/* The other two generators are seeded from /dev/random.  */
8dd812
-	ret = _rnd_get_system_entropy(buffer, sizeof(buffer));
8dd812
+	ret = get_entropy(fctx, buffer, sizeof(buffer));
8dd812
 	if (ret < 0)
8dd812
 		return gnutls_assert_val(ret);
8dd812
 
8dd812
-	drbg_aes_reseed(ctx, sizeof(buffer), buffer, 0, NULL);
8dd812
+	ret = drbg_aes_reseed(ctx, sizeof(buffer), buffer, 0, NULL);
8dd812
+	zeroize_key(buffer, sizeof(buffer));
8dd812
+	if (ret == 0)
8dd812
+		return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
8dd812
 
8dd812
-	return 0;
8dd812
+	return GNUTLS_E_SUCCESS;
8dd812
 }
8dd812
 
8dd812
 static int _rngfips_ctx_init(struct fips_ctx *fctx)
8dd812
 {
8dd812
+	uint8_t block[ENTROPY_BLOCK_SIZE];
8dd812
+	struct sha256_ctx ctx;
8dd812
 	int ret;
8dd812
 
8dd812
+	/* For FIPS 140-2 4.9.2 continuous random number generator
8dd812
+	 * test, get the initial entropy from the system RNG and keep
8dd812
+	 * it for comparison.
8dd812
+	 *
8dd812
+	 * Note that we store the hash of the entropy block rather
8dd812
+	 * than the block itself for backward secrecy.
8dd812
+	 */
8dd812
+	ret = _rnd_get_system_entropy(block, sizeof(block));
8dd812
+	if (ret < 0)
8dd812
+		return gnutls_assert_val(ret);
8dd812
+	sha256_init(&ctx;;
8dd812
+	sha256_update(&ctx, sizeof(block), block);
8dd812
+	zeroize_key(block, sizeof(block));
8dd812
+	sha256_digest(&ctx, sizeof(fctx->entropy_hash), fctx->entropy_hash);
8dd812
+
8dd812
 	/* normal */
8dd812
-	ret = drbg_init(&fctx->normal_context);
8dd812
+	ret = drbg_init(fctx, &fctx->normal_context);
8dd812
 	if (ret < 0)
8dd812
 		return gnutls_assert_val(ret);
8dd812
 
8dd812
 	/* nonce */
8dd812
-	ret = drbg_init(&fctx->nonce_context);
8dd812
+	ret = drbg_init(fctx, &fctx->nonce_context);
8dd812
 	if (ret < 0)
8dd812
 		return gnutls_assert_val(ret);
8dd812
 
8dd812
@@ -132,12 +192,12 @@ static int _rngfips_ctx_reinit(struct fips_ctx *fctx)
8dd812
 	int ret;
8dd812
 
8dd812
 	/* normal */
8dd812
-	ret = drbg_reseed(&fctx->normal_context);
8dd812
+	ret = drbg_reseed(fctx, &fctx->normal_context);
8dd812
 	if (ret < 0)
8dd812
 		return gnutls_assert_val(ret);
8dd812
 
8dd812
 	/* nonce */
8dd812
-	ret = drbg_reseed(&fctx->nonce_context);
8dd812
+	ret = drbg_reseed(fctx, &fctx->nonce_context);
8dd812
 	if (ret < 0)
8dd812
 		return gnutls_assert_val(ret);
8dd812
 
8dd812
-- 
8dd812
2.21.0
8dd812