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.
Unified · Split
| @@ -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 | + */ | |
| 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 | + | |
| 222 | 273 | /* |
| 223 | 274 | * Convert an integer into a byte representation of this integer. |
| 224 | 275 | * 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 | 1049 | return ret; |
| 999 | 1050 | } |
| 1000 | 1051 | |
| 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 | + | |
| 1001 | 1068 | static void drbg_async_seed(struct work_struct *work) |
| 1002 | 1069 | { |
| 1003 | 1070 | struct drbg_string data; |
| @@ -1006,16 +1073,20 @@ static void drbg_async_seed(struct work_struct *work) · 2 unmodified lines | ||
| 1006 | 1073 | seed_work); |
| 1007 | 1074 | unsigned int entropylen = drbg_sec_strength(drbg->core->flags); |
| 1008 | 1075 | unsigned char entropy[32]; |
| 1076 | + int ret; | |
| 1009 | 1077 | |
| 1010 | 1078 | BUG_ON(!entropylen); |
| 1011 | 1079 | BUG_ON(entropylen > sizeof(entropy)); |
| 1012 | − get_random_bytes(entropy, entropylen); | |
| 1013 | 1080 | |
| 1014 | 1081 | drbg_string_fill(&data, entropy, entropylen); |
| 1015 | 1082 | list_add_tail(&data.list, &seedlist); |
| 1016 | 1083 | |
| 1017 | 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 | 1090 | /* If nonblocking pool is initialized, deactivate Jitter RNG */ |
| 1020 | 1091 | crypto_free_rng(drbg->jent); |
| 1021 | 1092 | drbg->jent = NULL; |
| @@ -1030,6 +1101,7 @@ static void drbg_async_seed(struct work_struct *work) · 8 unmodified lines | ||
| 1030 | 1101 | if (drbg->seeded) |
| 1031 | 1102 | drbg->reseed_threshold = drbg_max_requests(drbg); |
| 1032 | 1103 | |
| 1104 | +unlock: | |
| 1033 | 1105 | mutex_unlock(&drbg->drbg_mutex); |
| 1034 | 1106 | |
| 1035 | 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 | 1153 | BUG_ON((entropylen * 2) > sizeof(entropy)); |
| 1082 | 1154 | |
| 1083 | 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 | 1160 | if (!drbg->jent) { |
| 1087 | 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 | 1168 | entropylen); |
| 1095 | 1169 | if (ret) { |
| 1096 | 1170 | pr_devel("DRBG: jent failed with %d\n", ret); |
| 1097 | − return ret; | |
| 1171 | + goto out; | |
| 1098 | 1172 | } |
| 1099 | 1173 | |
| 1100 | 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 | 1196 | ret = __drbg_seed(drbg, &seedlist, reseed); |
| 1123 | 1197 | |
| 1198 | +out: | |
| 1124 | 1199 | memzero_explicit(entropy, entropylen * 2); |
| 1125 | 1200 | |
| 1126 | 1201 | return ret; |
| @@ -1142,6 +1217,11 @@ static inline void drbg_dealloc_state(struct drbg_state *drbg) · 15 unmodified lines | ||
| 1142 | 1217 | drbg->reseed_ctr = 0; |
| 1143 | 1218 | drbg->d_ops = NULL; |
| 1144 | 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 | 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 | 1302 | return 0; |
| 1215 | 1303 | |
| 1216 | 1304 | fini: |
| @@ -129,6 +129,8 @@ struct drbg_state { · 128 unmodified lines | ||
| 129 | 129 | |
| 130 | 130 | bool seeded; /* DRBG fully seeded? */ |
| 131 | 131 | bool pr; /* Prediction resistance enabled? */ |
| 132 | + bool fips_primed; /* Continuous test primed? */ | |
| 133 | + unsigned char *prev; /* FIPS 140-2 continuous test value */ | |
| 132 | 134 | struct work_struct seed_work; /* asynchronous seeding support */ |
| 133 | 135 | struct crypto_rng *jent; |
| 134 | 136 | const struct drbg_state_ops *d_ops; |