History

crypto: drbg - add FIPS 140-2 CTRNG for noise source

FIPS 140-2 section 4.9.2 requires a continuous self test of the noise source. Up to kernel 4.8 drivers/char/random.c provided this continuous self test. Afterwards it was moved to a location that is inconsistent with the FIPS 140-2 requirements. The relevant patch was e192be9d9a30555aae2ca1dc3aad37cba484cd4a . Thus, the FIPS 140-2 CTRNG is added to the DRBG when it obtains the seed. This patch resurrects the function drbg_fips_continous_test that existed some time ago and applies it to the noise sources. The patch that removed the drbg_fips_continous_test was b3614763059b82c26bdd02ffcb1c016c1132aad0 . The Jitter RNG implements its own FIPS 140-2 self test and thus does not need to be subjected to the test in the DRBG. The patch contains a tiny fix to ensure proper zeroization in case of an error during the Jitter RNG data gathering.

Stephan Mueller committed 7 years ago

Commit db07cd21 parent a7cd9422 files · +93 −3Browse files

Unified · Split

2 files
  1. crypto/drbg.c +91 −3
  2. include/crypto/drbg.h +2 −0
crypto/drbg.c+91−3
@@ -219,6 +219,57 @@ static inline unsigned short drbg_sec_strength(drbg_flag_t flags) · 218 unmodified lines
219219 }
220220 }
221221
222+/*
223+ * FIPS 140-2 continuous self test for the noise source
224+ * The test is performed on the noise source input data. Thus, the function
225+ * implicitly knows the size of the buffer to be equal to the security
226+ * strength.
227+ *
228+ * Note, this function disregards the nonce trailing the entropy data during
229+ * initial seeding.
230+ *
231+ * drbg->drbg_mutex must have been taken.
232+ *
233+ * @drbg DRBG handle
234+ * @entropy buffer of seed data to be checked
235+ *
236+ * return:
237+ * 0 on success
238+ * -EAGAIN on when the CTRNG is not yet primed
239+ * < 0 on error
240+ */
241+static int drbg_fips_continuous_test(struct drbg_state *drbg,
242+ const unsigned char *entropy)
243+{
244+ unsigned short entropylen = drbg_sec_strength(drbg->core->flags);
245+ int ret = 0;
246+
247+ if (!IS_ENABLED(CONFIG_CRYPTO_FIPS))
248+ return 0;
249+
250+ /* skip test if we test the overall system */
251+ if (list_empty(&drbg->test_data.list))
252+ return 0;
253+ /* only perform test in FIPS mode */
254+ if (!fips_enabled)
255+ return 0;
256+
257+ if (!drbg->fips_primed) {
258+ /* Priming of FIPS test */
259+ memcpy(drbg->prev, entropy, entropylen);
260+ drbg->fips_primed = true;
261+ /* priming: another round is needed */
262+ return -EAGAIN;
263+ }
264+ ret = memcmp(drbg->prev, entropy, entropylen);
265+ if (!ret)
266+ panic("DRBG continuous self test failed\n");
267+ memcpy(drbg->prev, entropy, entropylen);
268+
269+ /* the test shall pass when the two values are not equal */
270+ return 0;
271+}
272+
222273 /*
223274 * Convert an integer into a byte representation of this integer.
224275 * The byte representation is big-endian
@@ -998,6 +1049,22 @@ static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, · 773 unmodified lines
9981049 return ret;
9991050 }
10001051
1052+static inline int drbg_get_random_bytes(struct drbg_state *drbg,
1053+ unsigned char *entropy,
1054+ unsigned int entropylen)
1055+{
1056+ int ret;
1057+
1058+ do {
1059+ get_random_bytes(entropy, entropylen);
1060+ ret = drbg_fips_continuous_test(drbg, entropy);
1061+ if (ret && ret != -EAGAIN)
1062+ return ret;
1063+ } while (ret);
1064+
1065+ return 0;
1066+}
1067+
10011068 static void drbg_async_seed(struct work_struct *work)
10021069 {
10031070 struct drbg_string data;
@@ -1006,16 +1073,20 @@ static void drbg_async_seed(struct work_struct *work) · 2 unmodified lines
10061073 seed_work);
10071074 unsigned int entropylen = drbg_sec_strength(drbg->core->flags);
10081075 unsigned char entropy[32];
1076+ int ret;
10091077
10101078 BUG_ON(!entropylen);
10111079 BUG_ON(entropylen > sizeof(entropy));
1012− get_random_bytes(entropy, entropylen);
10131080
10141081 drbg_string_fill(&data, entropy, entropylen);
10151082 list_add_tail(&data.list, &seedlist);
10161083
10171084 mutex_lock(&drbg->drbg_mutex);
10181085
1086+ ret = drbg_get_random_bytes(drbg, entropy, entropylen);
1087+ if (ret)
1088+ goto unlock;
1089+
10191090 /* If nonblocking pool is initialized, deactivate Jitter RNG */
10201091 crypto_free_rng(drbg->jent);
10211092 drbg->jent = NULL;
@@ -1030,6 +1101,7 @@ static void drbg_async_seed(struct work_struct *work) · 8 unmodified lines
10301101 if (drbg->seeded)
10311102 drbg->reseed_threshold = drbg_max_requests(drbg);
10321103
1104+unlock:
10331105 mutex_unlock(&drbg->drbg_mutex);
10341106
10351107 memzero_explicit(entropy, entropylen);
@@ -1081,7 +1153,9 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, · 45 unmodified lines
10811153 BUG_ON((entropylen * 2) > sizeof(entropy));
10821154
10831155 /* Get seed from in-kernel /dev/urandom */
1084− get_random_bytes(entropy, entropylen);
1156+ ret = drbg_get_random_bytes(drbg, entropy, entropylen);
1157+ if (ret)
1158+ goto out;
10851159
10861160 if (!drbg->jent) {
10871161 drbg_string_fill(&data1, entropy, entropylen);
@@ -1094,7 +1168,7 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, · 6 unmodified lines
10941168 entropylen);
10951169 if (ret) {
10961170 pr_devel("DRBG: jent failed with %d\n", ret);
1097− return ret;
1171+ goto out;
10981172 }
10991173
11001174 drbg_string_fill(&data1, entropy, entropylen * 2);
@@ -1121,6 +1195,7 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, · 20 unmodified lines
11211195
11221196 ret = __drbg_seed(drbg, &seedlist, reseed);
11231197
1198+out:
11241199 memzero_explicit(entropy, entropylen * 2);
11251200
11261201 return ret;
@@ -1142,6 +1217,11 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) · 15 unmodified lines
11421217 drbg->reseed_ctr = 0;
11431218 drbg->d_ops = NULL;
11441219 drbg->core = NULL;
1220+ if (IS_ENABLED(CONFIG_CRYPTO_FIPS)) {
1221+ kzfree(drbg->prev);
1222+ drbg->prev = NULL;
1223+ drbg->fips_primed = false;
1224+ }
11451225 }
11461226
11471227 /*
@@ -1211,6 +1291,14 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) · 63 unmodified lines
12111291 drbg->scratchpad = PTR_ALIGN(drbg->scratchpadbuf, ret + 1);
12121292 }
12131293
1294+ if (IS_ENABLED(CONFIG_CRYPTO_FIPS)) {
1295+ drbg->prev = kzalloc(drbg_sec_strength(drbg->core->flags),
1296+ GFP_KERNEL);
1297+ if (!drbg->prev)
1298+ goto fini;
1299+ drbg->fips_primed = false;
1300+ }
1301+
12141302 return 0;
12151303
12161304 fini:
include/crypto/drbg.h+2−0
@@ -129,6 +129,8 @@ struct drbg_state { · 128 unmodified lines
129129
130130 bool seeded; /* DRBG fully seeded? */
131131 bool pr; /* Prediction resistance enabled? */
132+ bool fips_primed; /* Continuous test primed? */
133+ unsigned char *prev; /* FIPS 140-2 continuous test value */
132134 struct work_struct seed_work; /* asynchronous seeding support */
133135 struct crypto_rng *jent;
134136 const struct drbg_state_ops *d_ops;