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