Torsten Duwe 22291c
From cfd04a840941a4aa59174ad14f04a37b53eeb16a Mon Sep 17 00:00:00 2001
Torsten Duwe 22291c
From: Stephan Mueller <smueller@chronox.de>
Torsten Duwe 22291c
Date: Fri, 3 May 2019 21:54:46 +0200
Torsten Duwe 22291c
Subject: [PATCH v5] crypto: DRBG - add FIPS 140-2 CTRNG for noise source
Torsten Duwe 22291c
Patch-mainline: Never, handled differently
Torsten Duwe 22291c
References: bsc#1155334
Torsten Duwe 22291c
Torsten Duwe 22291c
FIPS 140-2 section 4.9.2 requires a continuous self test of the noise
Torsten Duwe 22291c
source. Up to kernel 4.8 drivers/char/random.c provided this continuous
Torsten Duwe 22291c
self test. Afterwards it was moved to a location that is inconsistent
Torsten Duwe 22291c
with the FIPS 140-2 requirements. The relevant patch was
Torsten Duwe 22291c
e192be9d9a30555aae2ca1dc3aad37cba484cd4a .
Torsten Duwe 22291c
Torsten Duwe 22291c
Thus, the FIPS 140-2 CTRNG is added to the DRBG when it obtains the
Torsten Duwe 22291c
seed. This patch resurrects the function drbg_fips_continous_test that
Torsten Duwe 22291c
existed some time ago and applies it to the noise sources. The patch
Torsten Duwe 22291c
that removed the drbg_fips_continous_test was
Torsten Duwe 22291c
b3614763059b82c26bdd02ffcb1c016c1132aad0 .
Torsten Duwe 22291c
Torsten Duwe 22291c
The Jitter RNG implements its own FIPS 140-2 self test and thus does not
Torsten Duwe 22291c
need to be subjected to the test in the DRBG.
Torsten Duwe 22291c
Torsten Duwe 22291c
The patch contains a tiny fix to ensure proper zeroization in case of an
Torsten Duwe 22291c
error during the Jitter RNG data gathering.
Torsten Duwe 22291c
Torsten Duwe 22291c
Signed-off-by: Stephan Mueller <smueller@chronox.de>
Torsten Duwe 22291c
Acked-by: Torsten Duwe <duwe@suse.de>
Torsten Duwe 22291c
---
Torsten Duwe 22291c
 crypto/drbg.c         | 84 +++++++++++++++++++++++++++++++++++++++++--
Torsten Duwe 22291c
 include/crypto/drbg.h |  2 ++
Torsten Duwe 22291c
 2 files changed, 83 insertions(+), 3 deletions(-)
Torsten Duwe 22291c
Torsten Duwe 22291c
diff --git a/crypto/drbg.c b/crypto/drbg.c
Torsten Duwe 22291c
index 2a5b16bb000c..8328d7d9b42e 100644
Torsten Duwe 22291c
--- a/crypto/drbg.c
Torsten Duwe 22291c
+++ b/crypto/drbg.c
Torsten Duwe 22291c
@@ -219,6 +219,57 @@ static inline unsigned short drbg_sec_strength(drbg_flag_t flags)
Torsten Duwe 22291c
 	}
Torsten Duwe 22291c
 }
Torsten Duwe 22291c
 
Torsten Duwe 22291c
+/*
Torsten Duwe 22291c
+ * FIPS 140-2 continuous self test for the noise source
Torsten Duwe 22291c
+ * The test is performed on the noise source input data. Thus, the function
Torsten Duwe 22291c
+ * implicitly knows the size of the buffer to be equal to the security
Torsten Duwe 22291c
+ * strength.
Torsten Duwe 22291c
+ *
Torsten Duwe 22291c
+ * Note, this function disregards the nonce trailing the entropy data during
Torsten Duwe 22291c
+ * initial seeding.
Torsten Duwe 22291c
+ *
Torsten Duwe 22291c
+ * drbg->drbg_mutex must have been taken.
Torsten Duwe 22291c
+ *
Torsten Duwe 22291c
+ * @drbg DRBG handle
Torsten Duwe 22291c
+ * @entropy buffer of seed data to be checked
Torsten Duwe 22291c
+ *
Torsten Duwe 22291c
+ * return:
Torsten Duwe 22291c
+ *	0 on success
Torsten Duwe 22291c
+ *	-EAGAIN on when the CTRNG is not yet primed
Torsten Duwe 22291c
+ *	< 0 on error
Torsten Duwe 22291c
+ */
Torsten Duwe 22291c
+static int drbg_fips_continuous_test(struct drbg_state *drbg,
Torsten Duwe 22291c
+				     const unsigned char *entropy)
Torsten Duwe 22291c
+{
Torsten Duwe 22291c
+	if (IS_ENABLED(CONFIG_CRYPTO_FIPS)) {
Torsten Duwe 22291c
+		unsigned short entropylen = drbg_sec_strength(drbg->core->flags);
Torsten Duwe 22291c
+		int ret = 0;
Torsten Duwe 22291c
+
Torsten Duwe 22291c
+		/* skip test if we test the overall system */
Torsten Duwe 22291c
+		if (list_empty(&drbg->test_data.list))
Torsten Duwe 22291c
+			return 0;
Torsten Duwe 22291c
+		/* only perform test in FIPS mode */
Torsten Duwe 22291c
+		if (!fips_enabled)
Torsten Duwe 22291c
+			return 0;
Torsten Duwe 22291c
+
Torsten Duwe 22291c
+		if (!drbg->fips_primed) {
Torsten Duwe 22291c
+			/* Priming of FIPS test */
Torsten Duwe 22291c
+			memcpy(drbg->prev, entropy, entropylen);
Torsten Duwe 22291c
+			drbg->fips_primed = true;
Torsten Duwe 22291c
+			/* priming: another round is needed */
Torsten Duwe 22291c
+			return -EAGAIN;
Torsten Duwe 22291c
+		}
Torsten Duwe 22291c
+		ret = memcmp(drbg->prev, entropy, entropylen);
Torsten Duwe 22291c
+		if (!ret)
Torsten Duwe 22291c
+			panic("DRBG continuous self test failed\n");
Torsten Duwe 22291c
+		memcpy(drbg->prev, entropy, entropylen);
Torsten Duwe 22291c
+		/* the test shall pass when the two values are not equal */
Torsten Duwe 22291c
+		return (ret != 0) ? 0 : -EFAULT;
Torsten Duwe 22291c
+	} else {
Torsten Duwe 22291c
+		return 0;
Torsten Duwe 22291c
+	}
Torsten Duwe 22291c
+}
Torsten Duwe 22291c
+
Torsten Duwe 22291c
 /*
Torsten Duwe 22291c
  * Convert an integer into a byte representation of this integer.
Torsten Duwe 22291c
  * The byte representation is big-endian
Torsten Duwe 22291c
@@ -1006,16 +1057,23 @@ static void drbg_async_seed(struct work_struct *work)
Torsten Duwe 22291c
 					       seed_work);
Torsten Duwe 22291c
 	unsigned int entropylen = drbg_sec_strength(drbg->core->flags);
Torsten Duwe 22291c
 	unsigned char entropy[32];
Torsten Duwe 22291c
+	int ret;
Torsten Duwe 22291c
 
Torsten Duwe 22291c
 	BUG_ON(!entropylen);
Torsten Duwe 22291c
 	BUG_ON(entropylen > sizeof(entropy));
Torsten Duwe 22291c
-	get_random_bytes(entropy, entropylen);
Torsten Duwe 22291c
 
Torsten Duwe 22291c
 	drbg_string_fill(&data, entropy, entropylen);
Torsten Duwe 22291c
 	list_add_tail(&data.list, &seedlist);
Torsten Duwe 22291c
 
Torsten Duwe 22291c
 	mutex_lock(&drbg->drbg_mutex);
Torsten Duwe 22291c
 
Torsten Duwe 22291c
+	do {
Torsten Duwe 22291c
+		get_random_bytes(entropy, entropylen);
Torsten Duwe 22291c
+		ret = drbg_fips_continuous_test(drbg, entropy);
Torsten Duwe 22291c
+		if (ret && ret != -EAGAIN)
Torsten Duwe 22291c
+			goto unlock;
Torsten Duwe 22291c
+	} while (ret);
Torsten Duwe 22291c
+
Torsten Duwe 22291c
 	/* If nonblocking pool is initialized, deactivate Jitter RNG */
Torsten Duwe 22291c
 	crypto_free_rng(drbg->jent);
Torsten Duwe 22291c
 	drbg->jent = NULL;
Torsten Duwe 22291c
@@ -1030,6 +1088,7 @@ static void drbg_async_seed(struct work_struct *work)
Torsten Duwe 22291c
 	if (drbg->seeded)
Torsten Duwe 22291c
 		drbg->reseed_threshold = drbg_max_requests(drbg);
Torsten Duwe 22291c
 
Torsten Duwe 22291c
+unlock:
Torsten Duwe 22291c
 	mutex_unlock(&drbg->drbg_mutex);
Torsten Duwe 22291c
 
Torsten Duwe 22291c
 	memzero_explicit(entropy, entropylen);
Torsten Duwe 22291c
@@ -1081,7 +1140,12 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
Torsten Duwe 22291c
 		BUG_ON((entropylen * 2) > sizeof(entropy));
Torsten Duwe 22291c
 
Torsten Duwe 22291c
 		/* Get seed from in-kernel /dev/urandom */
Torsten Duwe 22291c
-		get_random_bytes(entropy, entropylen);
Torsten Duwe 22291c
+		do {
Torsten Duwe 22291c
+			get_random_bytes(entropy, entropylen);
Torsten Duwe 22291c
+			ret = drbg_fips_continuous_test(drbg, entropy);
Torsten Duwe 22291c
+			if (ret && ret != -EAGAIN)
Torsten Duwe 22291c
+				goto out;
Torsten Duwe 22291c
+		} while (ret);
Torsten Duwe 22291c
 
Torsten Duwe 22291c
 		if (!drbg->jent) {
Torsten Duwe 22291c
 			drbg_string_fill(&data1, entropy, entropylen);
Torsten Duwe 22291c
@@ -1094,7 +1158,7 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
Torsten Duwe 22291c
 						   entropylen);
Torsten Duwe 22291c
 			if (ret) {
Torsten Duwe 22291c
 				pr_devel("DRBG: jent failed with %d\n", ret);
Torsten Duwe 22291c
-				return ret;
Torsten Duwe 22291c
+				goto out;
Torsten Duwe 22291c
 			}
Torsten Duwe 22291c
 
Torsten Duwe 22291c
 			drbg_string_fill(&data1, entropy, entropylen * 2);
Torsten Duwe 22291c
@@ -1121,6 +1185,7 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers,
Torsten Duwe 22291c
 
Torsten Duwe 22291c
 	ret = __drbg_seed(drbg, &seedlist, reseed);
Torsten Duwe 22291c
 
Torsten Duwe 22291c
+out:
Torsten Duwe 22291c
 	memzero_explicit(entropy, entropylen * 2);
Torsten Duwe 22291c
 
Torsten Duwe 22291c
 	return ret;
Torsten Duwe 22291c
@@ -1142,6 +1207,11 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg)
Torsten Duwe 22291c
 	drbg->reseed_ctr = 0;
Torsten Duwe 22291c
 	drbg->d_ops = NULL;
Torsten Duwe 22291c
 	drbg->core = NULL;
Torsten Duwe 22291c
+	if (IS_ENABLED(CONFIG_CRYPTO_FIPS)) {
Torsten Duwe 22291c
+		kzfree(drbg->prev);
Torsten Duwe 22291c
+		drbg->prev = NULL;
Torsten Duwe 22291c
+		drbg->fips_primed = false;
Torsten Duwe 22291c
+	}
Torsten Duwe 22291c
 }
Torsten Duwe 22291c
 
Torsten Duwe 22291c
 /*
Torsten Duwe 22291c
@@ -1211,6 +1281,14 @@ static inline int drbg_alloc_state(struct drbg_state *drbg)
Torsten Duwe 22291c
 		drbg->scratchpad = PTR_ALIGN(drbg->scratchpadbuf, ret + 1);
Torsten Duwe 22291c
 	}
Torsten Duwe 22291c
 
Torsten Duwe 22291c
+	if (IS_ENABLED(CONFIG_CRYPTO_FIPS)) {
Torsten Duwe 22291c
+		drbg->prev = kzalloc(drbg_sec_strength(drbg->core->flags),
Torsten Duwe 22291c
+				     GFP_KERNEL);
Torsten Duwe 22291c
+		if (!drbg->prev)
Torsten Duwe 22291c
+			goto fini;
Torsten Duwe 22291c
+		drbg->fips_primed = false;
Torsten Duwe 22291c
+	}
Torsten Duwe 22291c
+
Torsten Duwe 22291c
 	return 0;
Torsten Duwe 22291c
 
Torsten Duwe 22291c
 fini:
Torsten Duwe 22291c
diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h
Torsten Duwe 22291c
index 3fb581bf3b87..8c9af21efce1 100644
Torsten Duwe 22291c
--- a/include/crypto/drbg.h
Torsten Duwe 22291c
+++ b/include/crypto/drbg.h
Torsten Duwe 22291c
@@ -129,6 +129,8 @@ struct drbg_state {
Torsten Duwe 22291c
 
Torsten Duwe 22291c
 	bool seeded;		/* DRBG fully seeded? */
Torsten Duwe 22291c
 	bool pr;		/* Prediction resistance enabled? */
Torsten Duwe 22291c
+	bool fips_primed;	/* Continuous test primed? */
Torsten Duwe 22291c
+	unsigned char *prev;	/* FIPS 140-2 continuous test value */
Torsten Duwe 22291c
 	struct work_struct seed_work;	/* asynchronous seeding support */
Torsten Duwe 22291c
 	struct crypto_rng *jent;
Torsten Duwe 22291c
 	const struct drbg_state_ops *d_ops;
Torsten Duwe 22291c
-- 
Torsten Duwe 22291c
2.21.0
Torsten Duwe 22291c