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 | * 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-endian | 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 | return ret; | 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 | static void drbg_async_seed(struct work_struct *work) | 1068 | static 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 | ||
| 1104 | unlock: | ||
| 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 | ||
| 1198 | out: | ||
| 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 | ||
| 1216 | fini: | 1304 | fini: |
| @@ -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; |