1 /* 2 * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 /* 11 * Implementation of SP 800-90B section 4.4 Approved Continuous Health Tests. 12 */ 13 14 #include <string.h> 15 #include <openssl/evp.h> 16 #include <openssl/core_dispatch.h> 17 #include <openssl/params.h> 18 #include <openssl/self_test.h> 19 #include <openssl/proverr.h> 20 #include "prov/providercommon.h" 21 #include "prov/provider_ctx.h" 22 #include "prov/implementations.h" 23 #include "internal/cryptlib.h" 24 #include "crypto/rand_pool.h" 25 #include "drbg_local.h" 26 #include "prov/seeding.h" 27 #include "crypto/context.h" 28 29 static OSSL_FUNC_rand_newctx_fn crng_test_new; 30 static OSSL_FUNC_rand_freectx_fn crng_test_free; 31 static OSSL_FUNC_rand_instantiate_fn crng_test_instantiate; 32 static OSSL_FUNC_rand_uninstantiate_fn crng_test_uninstantiate; 33 static OSSL_FUNC_rand_generate_fn crng_test_generate; 34 static OSSL_FUNC_rand_reseed_fn crng_test_reseed; 35 static OSSL_FUNC_rand_gettable_ctx_params_fn crng_test_gettable_ctx_params; 36 static OSSL_FUNC_rand_get_ctx_params_fn crng_test_get_ctx_params; 37 static OSSL_FUNC_rand_verify_zeroization_fn crng_test_verify_zeroization; 38 static OSSL_FUNC_rand_enable_locking_fn crng_test_enable_locking; 39 static OSSL_FUNC_rand_lock_fn crng_test_lock; 40 static OSSL_FUNC_rand_unlock_fn crng_test_unlock; 41 static OSSL_FUNC_rand_get_seed_fn crng_test_get_seed; 42 static OSSL_FUNC_rand_clear_seed_fn crng_test_clear_seed; 43 44 #ifndef ENTROPY_H 45 # define ENTROPY_H 6 /* default to six bits per byte of entropy */ 46 #endif 47 #ifndef ENTROPY_APT_W 48 # define ENTROPY_APT_W 512 49 #endif 50 51 typedef struct crng_testal_st { 52 void *provctx; 53 CRYPTO_RWLOCK *lock; 54 int state; 55 56 /* State for SP 800-90B 4.4.1 Repetition Count Test */ 57 struct { 58 unsigned int b; 59 uint8_t a; 60 } rct; 61 62 /* State for SP 800-90B 4.4.2 Adaptive Proportion Test */ 63 struct { 64 unsigned int b; 65 unsigned int i; 66 uint8_t a; 67 } apt; 68 69 /* Parent PROV_RAND and its dispatch table functions */ 70 void *parent; 71 OSSL_FUNC_rand_enable_locking_fn *parent_enable_locking; 72 OSSL_FUNC_rand_lock_fn *parent_lock; 73 OSSL_FUNC_rand_unlock_fn *parent_unlock; 74 OSSL_FUNC_rand_get_ctx_params_fn *parent_get_ctx_params; 75 OSSL_FUNC_rand_gettable_ctx_params_fn *parent_gettable_ctx_params; 76 OSSL_FUNC_rand_get_seed_fn *parent_get_seed; 77 OSSL_FUNC_rand_clear_seed_fn *parent_clear_seed; 78 } CRNG_TEST; 79 80 /* 81 * Some helper functions 82 */ 83 static int lock_parent(CRNG_TEST *crngt) 84 { 85 void *parent = crngt->parent; 86 87 if (parent != NULL 88 && crngt->parent_lock != NULL 89 && !crngt->parent_lock(parent)) { 90 ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED); 91 return 0; 92 } 93 return 1; 94 } 95 96 static void unlock_parent(CRNG_TEST *crngt) 97 { 98 void *parent = crngt->parent; 99 100 if (parent != NULL && crngt->parent_unlock != NULL) 101 crngt->parent_unlock(parent); 102 } 103 104 /* 105 * Implementation of SP 800-90B section 4.4.1: Repetition Count Test 106 */ 107 static int RCT_test(CRNG_TEST *crngt, uint8_t next) 108 { 109 /* 110 * Critical values for this test are computed using: 111 * 112 * C = 1 + \left\lceil\frac{-log_2 \alpha}H\right\rceil 113 * 114 * where alpha = 2^-20 and H is the expected entropy per sample. 115 */ 116 static const unsigned int rct_c[9] = { 117 41, /* H = 0.5 */ 118 21, 11, 8, 6, 5, 5, 4, 4 /* H = 1, ..., 8 */ 119 }; 120 121 if (ossl_likely(crngt->rct.b != 0) 122 && ossl_unlikely(next == crngt->rct.a)) 123 return ossl_likely(++crngt->rct.b < rct_c[ENTROPY_H]); 124 crngt->rct.a = next; 125 crngt->rct.b = 1; 126 return 1; 127 } 128 129 /* 130 * Implementation of SP 800-90B section 4.4.2: Adaptive Proportion Test 131 */ 132 static int APT_test(CRNG_TEST *crngt, uint8_t next) 133 { 134 /* 135 * Critical values for this test are drawn from a binomial 136 * distribution with n = 512, p = 2^-H at a critical threshold of 137 * 2^-20. H being the expected entropy per sample. Refer SP 800-90B 138 * section 4.4.2, table 2. 139 */ 140 static const unsigned int apt_c[9] = { 141 410, /* H = 0.5 */ 142 311, 177, 103, 62, 39, 25, 18, 13 /* H = 1, ..., 8 */ 143 }; 144 145 if (ossl_likely(crngt->apt.b != 0)) { 146 if (ossl_unlikely(crngt->apt.a == next) 147 && ossl_unlikely(++crngt->apt.b >= apt_c[ENTROPY_H])) { 148 crngt->apt.b = 0; 149 return 0; 150 } 151 if (ossl_unlikely(++crngt->apt.i >= ENTROPY_APT_W)) 152 crngt->apt.b = 0; 153 return 1; 154 } 155 crngt->apt.a = next; 156 crngt->apt.b = 1; 157 crngt->apt.i = 1; 158 return 1; 159 } 160 161 static int crng_test(CRNG_TEST *crngt, const unsigned char *buf, size_t n) 162 { 163 size_t i; 164 165 for (i = 0; i < n; i++) 166 if (!RCT_test(crngt, buf[i]) || !APT_test(crngt, buf[i])) { 167 crngt->state = EVP_RAND_STATE_ERROR; 168 ERR_raise(ERR_LIB_PROV, 169 PROV_R_ENTROPY_SOURCE_FAILED_CONTINUOUS_TESTS); 170 return 0; 171 } 172 return 1; 173 } 174 175 static const OSSL_DISPATCH *find_call(const OSSL_DISPATCH *dispatch, 176 int function) 177 { 178 if (dispatch != NULL) 179 while (dispatch->function_id != 0) { 180 if (dispatch->function_id == function) 181 return dispatch; 182 dispatch++; 183 } 184 return NULL; 185 } 186 187 static void *crng_test_new(void *provctx, void *parent, 188 const OSSL_DISPATCH *p_dispatch) 189 { 190 CRNG_TEST *crngt = OPENSSL_zalloc(sizeof(*crngt)); 191 const OSSL_DISPATCH *pfunc; 192 193 if (crngt == NULL) 194 return NULL; 195 196 crngt->provctx = provctx; 197 crngt->state = EVP_RAND_STATE_UNINITIALISED; 198 199 /* Extract parent's functions */ 200 if (parent != NULL) { 201 crngt->parent = parent; 202 if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_ENABLE_LOCKING)) != NULL) 203 crngt->parent_enable_locking = OSSL_FUNC_rand_enable_locking(pfunc); 204 if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_LOCK)) != NULL) 205 crngt->parent_lock = OSSL_FUNC_rand_lock(pfunc); 206 if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_UNLOCK)) != NULL) 207 crngt->parent_unlock = OSSL_FUNC_rand_unlock(pfunc); 208 if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS)) != NULL) 209 crngt->parent_gettable_ctx_params = OSSL_FUNC_rand_gettable_ctx_params(pfunc); 210 if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_GET_CTX_PARAMS)) != NULL) 211 crngt->parent_get_ctx_params = OSSL_FUNC_rand_get_ctx_params(pfunc); 212 if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_GET_SEED)) != NULL) 213 crngt->parent_get_seed = OSSL_FUNC_rand_get_seed(pfunc); 214 if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_CLEAR_SEED)) != NULL) 215 crngt->parent_clear_seed = OSSL_FUNC_rand_clear_seed(pfunc); 216 } 217 218 return crngt; 219 } 220 221 static void crng_test_free(void *vcrngt) 222 { 223 CRNG_TEST *crngt = (CRNG_TEST *)vcrngt; 224 225 if (crngt != NULL) { 226 CRYPTO_THREAD_lock_free(crngt->lock); 227 OPENSSL_free(crngt); 228 } 229 } 230 231 static int crng_test_instantiate(void *vcrngt, unsigned int strength, 232 int prediction_resistance, 233 const unsigned char *pstr, 234 size_t pstr_len, 235 ossl_unused const OSSL_PARAM params[]) 236 { 237 CRNG_TEST *crngt = (CRNG_TEST *)vcrngt; 238 239 /* Start up health tests should go here */ 240 crngt->state = EVP_RAND_STATE_READY; 241 return 1; 242 } 243 244 static int crng_test_uninstantiate(void *vcrngt) 245 { 246 CRNG_TEST *crngt = (CRNG_TEST *)vcrngt; 247 248 crngt->state = EVP_RAND_STATE_UNINITIALISED; 249 return 1; 250 } 251 252 static int crng_test_generate(void *vcrngt, unsigned char *out, size_t outlen, 253 unsigned int strength, int prediction_resistance, 254 const unsigned char *adin, size_t adin_len) 255 { 256 unsigned char *p; 257 CRNG_TEST *crngt = (CRNG_TEST *)vcrngt; 258 259 if (!crng_test_get_seed(crngt, &p, 0, outlen, outlen, prediction_resistance, 260 adin, adin_len)) 261 return 0; 262 memcpy(out, p, outlen); 263 crng_test_clear_seed(crngt, p, outlen); 264 return 1; 265 } 266 267 static int crng_test_reseed(ossl_unused void *vcrngt, 268 ossl_unused int prediction_resistance, 269 ossl_unused const unsigned char *ent, 270 ossl_unused size_t ent_len, 271 ossl_unused const unsigned char *adin, 272 ossl_unused size_t adin_len) 273 { 274 return 1; 275 } 276 277 static int crng_test_verify_zeroization(ossl_unused void *vcrngt) 278 { 279 return 1; 280 } 281 282 static size_t crng_test_get_seed(void *vcrngt, unsigned char **pout, 283 int entropy, size_t min_len, 284 size_t max_len, 285 int prediction_resistance, 286 const unsigned char *adin, 287 size_t adin_len) 288 { 289 CRNG_TEST *crngt = (CRNG_TEST *)vcrngt; 290 size_t n; 291 int r = 0; 292 293 /* Without a parent, we rely on the up calls */ 294 if (crngt->parent == NULL 295 || crngt->parent_get_seed == NULL) { 296 n = ossl_prov_get_entropy(crngt->provctx, pout, entropy, 297 min_len, max_len); 298 if (n == 0) 299 return 0; 300 r = crng_test(crngt, *pout, n); 301 return r > 0 ? n : 0; 302 } 303 304 /* Grab seed from our parent */ 305 if (!lock_parent(crngt)) 306 return 0; 307 308 n = crngt->parent_get_seed(crngt->parent, pout, entropy, 309 min_len, max_len, prediction_resistance, 310 adin, adin_len); 311 if (n > 0 && crng_test(crngt, *pout, n) > 0) 312 r = n; 313 else if (crngt->parent_clear_seed != NULL) 314 crngt->parent_clear_seed(crngt->parent, *pout, n); 315 unlock_parent(crngt); 316 return r; 317 } 318 319 static void crng_test_clear_seed(void *vcrngt, 320 unsigned char *out, size_t outlen) 321 { 322 CRNG_TEST *crngt = (CRNG_TEST *)vcrngt; 323 324 if (crngt->parent == NULL || crngt->parent_get_seed == NULL) 325 ossl_prov_cleanup_entropy(crngt->provctx, out, outlen); 326 else if (crngt->parent_clear_seed != NULL) 327 crngt->parent_clear_seed(crngt->parent, out, outlen); 328 } 329 330 static int crng_test_enable_locking(void *vcrngt) 331 { 332 CRNG_TEST *crngt = (CRNG_TEST *)vcrngt; 333 334 if (crngt != NULL && crngt->lock == NULL) { 335 if (crngt->parent_enable_locking != NULL) 336 if (!crngt->parent_enable_locking(crngt->parent)) { 337 ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED); 338 return 0; 339 } 340 crngt->lock = CRYPTO_THREAD_lock_new(); 341 if (crngt->lock == NULL) { 342 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_CREATE_LOCK); 343 return 0; 344 } 345 } 346 return 1; 347 } 348 349 static int crng_test_lock(ossl_unused void *vcrngt) 350 { 351 CRNG_TEST *crngt = (CRNG_TEST *)vcrngt; 352 353 return crngt->lock == NULL || CRYPTO_THREAD_write_lock(crngt->lock); 354 } 355 356 static void crng_test_unlock(ossl_unused void *vcrngt) 357 { 358 CRNG_TEST *crngt = (CRNG_TEST *)vcrngt; 359 360 if (crngt->lock != NULL) 361 CRYPTO_THREAD_unlock(crngt->lock); 362 } 363 364 static int crng_test_get_ctx_params(void *vcrngt, OSSL_PARAM params[]) 365 { 366 CRNG_TEST *crngt = (CRNG_TEST *)vcrngt; 367 OSSL_PARAM *p; 368 369 if (crngt->parent != NULL && crngt->parent_get_ctx_params != NULL) 370 return crngt->parent_get_ctx_params(crngt->parent, params); 371 372 /* No parent means we are using call backs for entropy */ 373 p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STATE); 374 if (p != NULL && !OSSL_PARAM_set_int(p, crngt->state)) 375 return 0; 376 377 p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STRENGTH); 378 if (p != NULL && !OSSL_PARAM_set_int(p, 1024)) 379 return 0; 380 381 p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST); 382 if (p != NULL && !OSSL_PARAM_set_size_t(p, 128)) 383 return 0; 384 385 p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_FIPS_APPROVED_INDICATOR); 386 if (p != NULL && !OSSL_PARAM_set_int(p, 0)) 387 return 0; 388 return 1; 389 } 390 391 static const OSSL_PARAM *crng_test_gettable_ctx_params(void *vcrngt, 392 void *provctx) 393 { 394 CRNG_TEST *crngt = (CRNG_TEST *)vcrngt; 395 static const OSSL_PARAM known_gettable_ctx_params[] = { 396 OSSL_PARAM_int(OSSL_RAND_PARAM_STATE, NULL), 397 OSSL_PARAM_uint(OSSL_RAND_PARAM_STRENGTH, NULL), 398 OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_REQUEST, NULL), 399 OSSL_PARAM_int(OSSL_RAND_PARAM_FIPS_APPROVED_INDICATOR, NULL), 400 OSSL_PARAM_END 401 }; 402 403 if (crngt->parent != NULL && crngt->parent_gettable_ctx_params != NULL) 404 return crngt->parent_gettable_ctx_params(crngt->parent, provctx); 405 return known_gettable_ctx_params; 406 } 407 408 const OSSL_DISPATCH ossl_crng_test_functions[] = { 409 { OSSL_FUNC_RAND_NEWCTX, (void(*)(void))crng_test_new }, 410 { OSSL_FUNC_RAND_FREECTX, (void(*)(void))crng_test_free }, 411 { OSSL_FUNC_RAND_INSTANTIATE, 412 (void(*)(void))crng_test_instantiate }, 413 { OSSL_FUNC_RAND_UNINSTANTIATE, 414 (void(*)(void))crng_test_uninstantiate }, 415 { OSSL_FUNC_RAND_GENERATE, (void(*)(void))crng_test_generate }, 416 { OSSL_FUNC_RAND_RESEED, (void(*)(void))crng_test_reseed }, 417 { OSSL_FUNC_RAND_ENABLE_LOCKING, (void(*)(void))crng_test_enable_locking }, 418 { OSSL_FUNC_RAND_LOCK, (void(*)(void))crng_test_lock }, 419 { OSSL_FUNC_RAND_UNLOCK, (void(*)(void))crng_test_unlock }, 420 { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS, 421 (void(*)(void))crng_test_gettable_ctx_params }, 422 { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))crng_test_get_ctx_params }, 423 { OSSL_FUNC_RAND_VERIFY_ZEROIZATION, 424 (void(*)(void))crng_test_verify_zeroization }, 425 { OSSL_FUNC_RAND_GET_SEED, (void(*)(void))crng_test_get_seed }, 426 { OSSL_FUNC_RAND_CLEAR_SEED, (void(*)(void))crng_test_clear_seed }, 427 OSSL_DISPATCH_END 428 }; 429