|
|
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 |
|