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
219 }219 }
220}220}
221 221
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 */
241static 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
222/*273/*
223 * Convert an integer into a byte representation of this integer.274 * Convert an integer into a byte representation of this integer.
224 * The byte representation is big-endian275 * 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
998 return ret;1049 return ret;
999}1050}
1000 1051
1052static 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
1001static void drbg_async_seed(struct work_struct *work)1068static void drbg_async_seed(struct work_struct *work)
1002{1069{
1003 struct drbg_string data;1070 struct drbg_string data;
@@ -1006,16 +1073,20 @@ static void drbg_async_seed(struct work_struct *work) · 2 unmodified lines
1006 seed_work);1073 seed_work);
1007 unsigned int entropylen = drbg_sec_strength(drbg->core->flags);1074 unsigned int entropylen = drbg_sec_strength(drbg->core->flags);
1008 unsigned char entropy[32];1075 unsigned char entropy[32];
1076 int ret;
1009 1077
1010 BUG_ON(!entropylen);1078 BUG_ON(!entropylen);
1011 BUG_ON(entropylen > sizeof(entropy));1079 BUG_ON(entropylen > sizeof(entropy));
1012 get_random_bytes(entropy, entropylen);
1013 1080
1014 drbg_string_fill(&data, entropy, entropylen);1081 drbg_string_fill(&data, entropy, entropylen);
1015 list_add_tail(&data.list, &seedlist);1082 list_add_tail(&data.list, &seedlist);
1016 1083
1017 mutex_lock(&drbg->drbg_mutex);1084 mutex_lock(&drbg->drbg_mutex);
1018 1085
1086 ret = drbg_get_random_bytes(drbg, entropy, entropylen);
1087 if (ret)
1088 goto unlock;
1089
1019 /* If nonblocking pool is initialized, deactivate Jitter RNG */1090 /* If nonblocking pool is initialized, deactivate Jitter RNG */
1020 crypto_free_rng(drbg->jent);1091 crypto_free_rng(drbg->jent);
1021 drbg->jent = NULL;1092 drbg->jent = NULL;
@@ -1030,6 +1101,7 @@ static void drbg_async_seed(struct work_struct *work) · 8 unmodified lines
1030 if (drbg->seeded)1101 if (drbg->seeded)
1031 drbg->reseed_threshold = drbg_max_requests(drbg);1102 drbg->reseed_threshold = drbg_max_requests(drbg);
1032 1103
1104unlock:
1033 mutex_unlock(&drbg->drbg_mutex);1105 mutex_unlock(&drbg->drbg_mutex);
1034 1106
1035 memzero_explicit(entropy, entropylen);1107 memzero_explicit(entropy, entropylen);
@@ -1081,7 +1153,9 @@ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, · 45 unmodified lines
1081 BUG_ON((entropylen * 2) > sizeof(entropy));1153 BUG_ON((entropylen * 2) > sizeof(entropy));
1082 1154
1083 /* Get seed from in-kernel /dev/urandom */1155 /* 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;
1085 1159
1086 if (!drbg->jent) {1160 if (!drbg->jent) {
1087 drbg_string_fill(&data1, entropy, entropylen);1161 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
1094 entropylen);1168 entropylen);
1095 if (ret) {1169 if (ret) {
1096 pr_devel("DRBG: jent failed with %d\n", ret);1170 pr_devel("DRBG: jent failed with %d\n", ret);
1097 return ret;1171 goto out;
1098 }1172 }
1099 1173
1100 drbg_string_fill(&data1, entropy, entropylen * 2);1174 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
1121 1195
1122 ret = __drbg_seed(drbg, &seedlist, reseed);1196 ret = __drbg_seed(drbg, &seedlist, reseed);
1123 1197
1198out:
1124 memzero_explicit(entropy, entropylen * 2);1199 memzero_explicit(entropy, entropylen * 2);
1125 1200
1126 return ret;1201 return ret;
@@ -1142,6 +1217,11 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) · 15 unmodified lines
1142 drbg->reseed_ctr = 0;1217 drbg->reseed_ctr = 0;
1143 drbg->d_ops = NULL;1218 drbg->d_ops = NULL;
1144 drbg->core = NULL;1219 drbg->core = NULL;
1220 if (IS_ENABLED(CONFIG_CRYPTO_FIPS)) {
1221 kzfree(drbg->prev);
1222 drbg->prev = NULL;
1223 drbg->fips_primed = false;
1224 }
1145}1225}
1146 1226
1147/*1227/*
@@ -1211,6 +1291,14 @@ static inline int drbg_alloc_state(struct drbg_state *drbg) · 63 unmodified lines
1211 drbg->scratchpad = PTR_ALIGN(drbg->scratchpadbuf, ret + 1);1291 drbg->scratchpad = PTR_ALIGN(drbg->scratchpadbuf, ret + 1);
1212 }1292 }
1213 1293
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
1214 return 0;1302 return 0;
1215 1303
1216fini:1304fini:
include/crypto/drbg.h+2−0
@@ -129,6 +129,8 @@ struct drbg_state { · 128 unmodified lines
129 129
130 bool seeded; /* DRBG fully seeded? */130 bool seeded; /* DRBG fully seeded? */
131 bool pr; /* Prediction resistance enabled? */131 bool pr; /* Prediction resistance enabled? */
132 bool fips_primed; /* Continuous test primed? */
133 unsigned char *prev; /* FIPS 140-2 continuous test value */
132 struct work_struct seed_work; /* asynchronous seeding support */134 struct work_struct seed_work; /* asynchronous seeding support */
133 struct crypto_rng *jent;135 struct crypto_rng *jent;
134 const struct drbg_state_ops *d_ops;136 const struct drbg_state_ops *d_ops;