1b077aed3SPierre Pronchery /* 244096ebdSEnji Cooper * Copyright 2011-2024 The OpenSSL Project Authors. All Rights Reserved. 3b077aed3SPierre Pronchery * 4b077aed3SPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use 5b077aed3SPierre Pronchery * this file except in compliance with the License. You can obtain a copy 6b077aed3SPierre Pronchery * in the file LICENSE in the source distribution or at 7b077aed3SPierre Pronchery * https://www.openssl.org/source/license.html 8b077aed3SPierre Pronchery */ 9b077aed3SPierre Pronchery 10b077aed3SPierre Pronchery #include <string.h> 11b077aed3SPierre Pronchery #include <openssl/crypto.h> 12b077aed3SPierre Pronchery #include <openssl/err.h> 13b077aed3SPierre Pronchery #include <openssl/rand.h> 14b077aed3SPierre Pronchery #include <openssl/evp.h> 15b077aed3SPierre Pronchery #include "crypto/rand.h" 16b077aed3SPierre Pronchery #include <openssl/proverr.h> 17b077aed3SPierre Pronchery #include "drbg_local.h" 18b077aed3SPierre Pronchery #include "internal/thread_once.h" 19b077aed3SPierre Pronchery #include "crypto/cryptlib.h" 20b077aed3SPierre Pronchery #include "prov/seeding.h" 21b077aed3SPierre Pronchery #include "crypto/rand_pool.h" 22b077aed3SPierre Pronchery #include "prov/provider_ctx.h" 23b077aed3SPierre Pronchery #include "prov/providercommon.h" 24b077aed3SPierre Pronchery 25b077aed3SPierre Pronchery /* 26b077aed3SPierre Pronchery * Support framework for NIST SP 800-90A DRBG 27b077aed3SPierre Pronchery * 28b077aed3SPierre Pronchery * See manual page PROV_DRBG(7) for a general overview. 29b077aed3SPierre Pronchery * 30b077aed3SPierre Pronchery * The OpenSSL model is to have new and free functions, and that new 31b077aed3SPierre Pronchery * does all initialization. That is not the NIST model, which has 32b077aed3SPierre Pronchery * instantiation and un-instantiate, and re-use within a new/free 33b077aed3SPierre Pronchery * lifecycle. (No doubt this comes from the desire to support hardware 34b077aed3SPierre Pronchery * DRBG, where allocation of resources on something like an HSM is 35b077aed3SPierre Pronchery * a much bigger deal than just re-setting an allocated resource.) 36b077aed3SPierre Pronchery */ 37b077aed3SPierre Pronchery 38b077aed3SPierre Pronchery /* NIST SP 800-90A DRBG recommends the use of a personalization string. */ 39b077aed3SPierre Pronchery static const char ossl_pers_string[] = DRBG_DEFAULT_PERS_STRING; 40b077aed3SPierre Pronchery 41b077aed3SPierre Pronchery static const OSSL_DISPATCH *find_call(const OSSL_DISPATCH *dispatch, 42b077aed3SPierre Pronchery int function); 43b077aed3SPierre Pronchery 44b077aed3SPierre Pronchery static int rand_drbg_restart(PROV_DRBG *drbg); 45b077aed3SPierre Pronchery 46b077aed3SPierre Pronchery int ossl_drbg_lock(void *vctx) 47b077aed3SPierre Pronchery { 48b077aed3SPierre Pronchery PROV_DRBG *drbg = vctx; 49b077aed3SPierre Pronchery 50b077aed3SPierre Pronchery if (drbg == NULL || drbg->lock == NULL) 51b077aed3SPierre Pronchery return 1; 52b077aed3SPierre Pronchery return CRYPTO_THREAD_write_lock(drbg->lock); 53b077aed3SPierre Pronchery } 54b077aed3SPierre Pronchery 55b077aed3SPierre Pronchery void ossl_drbg_unlock(void *vctx) 56b077aed3SPierre Pronchery { 57b077aed3SPierre Pronchery PROV_DRBG *drbg = vctx; 58b077aed3SPierre Pronchery 59b077aed3SPierre Pronchery if (drbg != NULL && drbg->lock != NULL) 60b077aed3SPierre Pronchery CRYPTO_THREAD_unlock(drbg->lock); 61b077aed3SPierre Pronchery } 62b077aed3SPierre Pronchery 63b077aed3SPierre Pronchery static int ossl_drbg_lock_parent(PROV_DRBG *drbg) 64b077aed3SPierre Pronchery { 65b077aed3SPierre Pronchery void *parent = drbg->parent; 66b077aed3SPierre Pronchery 67b077aed3SPierre Pronchery if (parent != NULL 68b077aed3SPierre Pronchery && drbg->parent_lock != NULL 69b077aed3SPierre Pronchery && !drbg->parent_lock(parent)) { 70b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED); 71b077aed3SPierre Pronchery return 0; 72b077aed3SPierre Pronchery } 73b077aed3SPierre Pronchery return 1; 74b077aed3SPierre Pronchery } 75b077aed3SPierre Pronchery 76b077aed3SPierre Pronchery static void ossl_drbg_unlock_parent(PROV_DRBG *drbg) 77b077aed3SPierre Pronchery { 78b077aed3SPierre Pronchery void *parent = drbg->parent; 79b077aed3SPierre Pronchery 80b077aed3SPierre Pronchery if (parent != NULL && drbg->parent_unlock != NULL) 81b077aed3SPierre Pronchery drbg->parent_unlock(parent); 82b077aed3SPierre Pronchery } 83b077aed3SPierre Pronchery 84b077aed3SPierre Pronchery static int get_parent_strength(PROV_DRBG *drbg, unsigned int *str) 85b077aed3SPierre Pronchery { 86b077aed3SPierre Pronchery OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; 87b077aed3SPierre Pronchery void *parent = drbg->parent; 88b077aed3SPierre Pronchery int res; 89b077aed3SPierre Pronchery 90b077aed3SPierre Pronchery if (drbg->parent_get_ctx_params == NULL) { 91b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PARENT_STRENGTH); 92b077aed3SPierre Pronchery return 0; 93b077aed3SPierre Pronchery } 94b077aed3SPierre Pronchery 95b077aed3SPierre Pronchery *params = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH, str); 96b077aed3SPierre Pronchery if (!ossl_drbg_lock_parent(drbg)) { 97b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOCK_PARENT); 98b077aed3SPierre Pronchery return 0; 99b077aed3SPierre Pronchery } 100b077aed3SPierre Pronchery res = drbg->parent_get_ctx_params(parent, params); 101b077aed3SPierre Pronchery ossl_drbg_unlock_parent(drbg); 102b077aed3SPierre Pronchery if (!res) { 103b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PARENT_STRENGTH); 104b077aed3SPierre Pronchery return 0; 105b077aed3SPierre Pronchery } 106b077aed3SPierre Pronchery return 1; 107b077aed3SPierre Pronchery } 108b077aed3SPierre Pronchery 109b077aed3SPierre Pronchery static unsigned int get_parent_reseed_count(PROV_DRBG *drbg) 110b077aed3SPierre Pronchery { 111b077aed3SPierre Pronchery OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; 112b077aed3SPierre Pronchery void *parent = drbg->parent; 113b077aed3SPierre Pronchery unsigned int r = 0; 114b077aed3SPierre Pronchery 115b077aed3SPierre Pronchery *params = OSSL_PARAM_construct_uint(OSSL_DRBG_PARAM_RESEED_COUNTER, &r); 116b077aed3SPierre Pronchery if (!ossl_drbg_lock_parent(drbg)) { 117b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOCK_PARENT); 118b077aed3SPierre Pronchery goto err; 119b077aed3SPierre Pronchery } 120b077aed3SPierre Pronchery if (!drbg->parent_get_ctx_params(parent, params)) 121b077aed3SPierre Pronchery r = 0; 122b077aed3SPierre Pronchery ossl_drbg_unlock_parent(drbg); 123b077aed3SPierre Pronchery return r; 124b077aed3SPierre Pronchery 125b077aed3SPierre Pronchery err: 126b077aed3SPierre Pronchery r = tsan_load(&drbg->reseed_counter) - 2; 127b077aed3SPierre Pronchery if (r == 0) 128b077aed3SPierre Pronchery r = UINT_MAX; 129b077aed3SPierre Pronchery return r; 130b077aed3SPierre Pronchery } 131b077aed3SPierre Pronchery 132b077aed3SPierre Pronchery /* 133b077aed3SPierre Pronchery * Implements the get_entropy() callback 134b077aed3SPierre Pronchery * 135b077aed3SPierre Pronchery * If the DRBG has a parent, then the required amount of entropy input 136b077aed3SPierre Pronchery * is fetched using the parent's ossl_prov_drbg_generate(). 137b077aed3SPierre Pronchery * 138b077aed3SPierre Pronchery * Otherwise, the entropy is polled from the system entropy sources 139b077aed3SPierre Pronchery * using ossl_pool_acquire_entropy(). 140b077aed3SPierre Pronchery * 141b077aed3SPierre Pronchery * If a random pool has been added to the DRBG using RAND_add(), then 142b077aed3SPierre Pronchery * its entropy will be used up first. 143b077aed3SPierre Pronchery */ 144b077aed3SPierre Pronchery size_t ossl_drbg_get_seed(void *vdrbg, unsigned char **pout, 145b077aed3SPierre Pronchery int entropy, size_t min_len, 146b077aed3SPierre Pronchery size_t max_len, int prediction_resistance, 147b077aed3SPierre Pronchery const unsigned char *adin, size_t adin_len) 148b077aed3SPierre Pronchery { 149b077aed3SPierre Pronchery PROV_DRBG *drbg = (PROV_DRBG *)vdrbg; 150b077aed3SPierre Pronchery size_t bytes_needed; 151b077aed3SPierre Pronchery unsigned char *buffer; 152b077aed3SPierre Pronchery 153b077aed3SPierre Pronchery /* Figure out how many bytes we need */ 154b077aed3SPierre Pronchery bytes_needed = entropy >= 0 ? (entropy + 7) / 8 : 0; 155b077aed3SPierre Pronchery if (bytes_needed < min_len) 156b077aed3SPierre Pronchery bytes_needed = min_len; 157b077aed3SPierre Pronchery if (bytes_needed > max_len) 158b077aed3SPierre Pronchery bytes_needed = max_len; 159b077aed3SPierre Pronchery 160b077aed3SPierre Pronchery /* Allocate storage */ 161b077aed3SPierre Pronchery buffer = OPENSSL_secure_malloc(bytes_needed); 162b077aed3SPierre Pronchery if (buffer == NULL) { 163b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); 164b077aed3SPierre Pronchery return 0; 165b077aed3SPierre Pronchery } 166b077aed3SPierre Pronchery 167b077aed3SPierre Pronchery /* 168b077aed3SPierre Pronchery * Get random data. Include our DRBG address as 169b077aed3SPierre Pronchery * additional input, in order to provide a distinction between 170b077aed3SPierre Pronchery * different DRBG child instances. 171b077aed3SPierre Pronchery * 172b077aed3SPierre Pronchery * Note: using the sizeof() operator on a pointer triggers 173b077aed3SPierre Pronchery * a warning in some static code analyzers, but it's 174b077aed3SPierre Pronchery * intentional and correct here. 175b077aed3SPierre Pronchery */ 176b077aed3SPierre Pronchery if (!ossl_prov_drbg_generate(drbg, buffer, bytes_needed, 177b077aed3SPierre Pronchery drbg->strength, prediction_resistance, 178b077aed3SPierre Pronchery (unsigned char *)&drbg, sizeof(drbg))) { 179b077aed3SPierre Pronchery OPENSSL_secure_clear_free(buffer, bytes_needed); 180b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_GENERATE_ERROR); 181b077aed3SPierre Pronchery return 0; 182b077aed3SPierre Pronchery } 183b077aed3SPierre Pronchery *pout = buffer; 184b077aed3SPierre Pronchery return bytes_needed; 185b077aed3SPierre Pronchery } 186b077aed3SPierre Pronchery 187b077aed3SPierre Pronchery /* Implements the cleanup_entropy() callback */ 188b077aed3SPierre Pronchery void ossl_drbg_clear_seed(ossl_unused void *vdrbg, 189b077aed3SPierre Pronchery unsigned char *out, size_t outlen) 190b077aed3SPierre Pronchery { 191b077aed3SPierre Pronchery OPENSSL_secure_clear_free(out, outlen); 192b077aed3SPierre Pronchery } 193b077aed3SPierre Pronchery 194b077aed3SPierre Pronchery static size_t get_entropy(PROV_DRBG *drbg, unsigned char **pout, int entropy, 195b077aed3SPierre Pronchery size_t min_len, size_t max_len, 196b077aed3SPierre Pronchery int prediction_resistance) 197b077aed3SPierre Pronchery { 198b077aed3SPierre Pronchery size_t bytes; 199b077aed3SPierre Pronchery unsigned int p_str; 200b077aed3SPierre Pronchery 201b077aed3SPierre Pronchery if (drbg->parent == NULL) 202b077aed3SPierre Pronchery #ifdef FIPS_MODULE 203b077aed3SPierre Pronchery return ossl_crngt_get_entropy(drbg, pout, entropy, min_len, max_len, 204b077aed3SPierre Pronchery prediction_resistance); 205b077aed3SPierre Pronchery #else 206*a7148ab3SEnji Cooper /* 207*a7148ab3SEnji Cooper * In normal use (i.e. OpenSSL's own uses), this is never called. 208*a7148ab3SEnji Cooper * Outside of the FIPS provider, OpenSSL sets its DRBGs up so that 209*a7148ab3SEnji Cooper * they always have a parent. This remains purely for legacy reasons. 210*a7148ab3SEnji Cooper */ 211b077aed3SPierre Pronchery return ossl_prov_get_entropy(drbg->provctx, pout, entropy, min_len, 212b077aed3SPierre Pronchery max_len); 213b077aed3SPierre Pronchery #endif 214b077aed3SPierre Pronchery 215b077aed3SPierre Pronchery if (drbg->parent_get_seed == NULL) { 216b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_CANNOT_SUPPLY_ENTROPY_SEED); 217b077aed3SPierre Pronchery return 0; 218b077aed3SPierre Pronchery } 219b077aed3SPierre Pronchery if (!get_parent_strength(drbg, &p_str)) 220b077aed3SPierre Pronchery return 0; 221b077aed3SPierre Pronchery if (drbg->strength > p_str) { 222b077aed3SPierre Pronchery /* 223b077aed3SPierre Pronchery * We currently don't support the algorithm from NIST SP 800-90C 224b077aed3SPierre Pronchery * 10.1.2 to use a weaker DRBG as source 225b077aed3SPierre Pronchery */ 226b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_STRENGTH_TOO_WEAK); 227b077aed3SPierre Pronchery return 0; 228b077aed3SPierre Pronchery } 229b077aed3SPierre Pronchery 230b077aed3SPierre Pronchery /* 231b077aed3SPierre Pronchery * Our lock is already held, but we need to lock our parent before 232b077aed3SPierre Pronchery * generating bits from it. Note: taking the lock will be a no-op 233b077aed3SPierre Pronchery * if locking is not required (while drbg->parent->lock == NULL). 234b077aed3SPierre Pronchery */ 235b077aed3SPierre Pronchery if (!ossl_drbg_lock_parent(drbg)) 236b077aed3SPierre Pronchery return 0; 237b077aed3SPierre Pronchery /* 238b077aed3SPierre Pronchery * Get random data from parent. Include our DRBG address as 239b077aed3SPierre Pronchery * additional input, in order to provide a distinction between 240b077aed3SPierre Pronchery * different DRBG child instances. 241b077aed3SPierre Pronchery * 242b077aed3SPierre Pronchery * Note: using the sizeof() operator on a pointer triggers 243b077aed3SPierre Pronchery * a warning in some static code analyzers, but it's 244b077aed3SPierre Pronchery * intentional and correct here. 245b077aed3SPierre Pronchery */ 246b077aed3SPierre Pronchery bytes = drbg->parent_get_seed(drbg->parent, pout, drbg->strength, 247b077aed3SPierre Pronchery min_len, max_len, prediction_resistance, 248b077aed3SPierre Pronchery (unsigned char *)&drbg, sizeof(drbg)); 249b077aed3SPierre Pronchery ossl_drbg_unlock_parent(drbg); 250b077aed3SPierre Pronchery return bytes; 251b077aed3SPierre Pronchery } 252b077aed3SPierre Pronchery 253b077aed3SPierre Pronchery static void cleanup_entropy(PROV_DRBG *drbg, unsigned char *out, size_t outlen) 254b077aed3SPierre Pronchery { 255b077aed3SPierre Pronchery if (drbg->parent == NULL) { 256b077aed3SPierre Pronchery #ifdef FIPS_MODULE 257b077aed3SPierre Pronchery ossl_crngt_cleanup_entropy(drbg, out, outlen); 258b077aed3SPierre Pronchery #else 259b077aed3SPierre Pronchery ossl_prov_cleanup_entropy(drbg->provctx, out, outlen); 260b077aed3SPierre Pronchery #endif 261b077aed3SPierre Pronchery } else if (drbg->parent_clear_seed != NULL) { 262b077aed3SPierre Pronchery if (!ossl_drbg_lock_parent(drbg)) 263b077aed3SPierre Pronchery return; 264b077aed3SPierre Pronchery drbg->parent_clear_seed(drbg->parent, out, outlen); 265b077aed3SPierre Pronchery ossl_drbg_unlock_parent(drbg); 266b077aed3SPierre Pronchery } 267b077aed3SPierre Pronchery } 268b077aed3SPierre Pronchery 269b077aed3SPierre Pronchery #ifndef PROV_RAND_GET_RANDOM_NONCE 270b077aed3SPierre Pronchery typedef struct prov_drbg_nonce_global_st { 271b077aed3SPierre Pronchery CRYPTO_RWLOCK *rand_nonce_lock; 272b077aed3SPierre Pronchery int rand_nonce_count; 273b077aed3SPierre Pronchery } PROV_DRBG_NONCE_GLOBAL; 274b077aed3SPierre Pronchery 275b077aed3SPierre Pronchery /* 276b077aed3SPierre Pronchery * drbg_ossl_ctx_new() calls drgb_setup() which calls rand_drbg_get_nonce() 277b077aed3SPierre Pronchery * which needs to get the rand_nonce_lock out of the OSSL_LIB_CTX...but since 278b077aed3SPierre Pronchery * drbg_ossl_ctx_new() hasn't finished running yet we need the rand_nonce_lock 279b077aed3SPierre Pronchery * to be in a different global data object. Otherwise we will go into an 280b077aed3SPierre Pronchery * infinite recursion loop. 281b077aed3SPierre Pronchery */ 282b077aed3SPierre Pronchery static void *prov_drbg_nonce_ossl_ctx_new(OSSL_LIB_CTX *libctx) 283b077aed3SPierre Pronchery { 284b077aed3SPierre Pronchery PROV_DRBG_NONCE_GLOBAL *dngbl = OPENSSL_zalloc(sizeof(*dngbl)); 285b077aed3SPierre Pronchery 286b077aed3SPierre Pronchery if (dngbl == NULL) 287b077aed3SPierre Pronchery return NULL; 288b077aed3SPierre Pronchery 289b077aed3SPierre Pronchery dngbl->rand_nonce_lock = CRYPTO_THREAD_lock_new(); 290b077aed3SPierre Pronchery if (dngbl->rand_nonce_lock == NULL) { 291b077aed3SPierre Pronchery OPENSSL_free(dngbl); 292b077aed3SPierre Pronchery return NULL; 293b077aed3SPierre Pronchery } 294b077aed3SPierre Pronchery 295b077aed3SPierre Pronchery return dngbl; 296b077aed3SPierre Pronchery } 297b077aed3SPierre Pronchery 298b077aed3SPierre Pronchery static void prov_drbg_nonce_ossl_ctx_free(void *vdngbl) 299b077aed3SPierre Pronchery { 300b077aed3SPierre Pronchery PROV_DRBG_NONCE_GLOBAL *dngbl = vdngbl; 301b077aed3SPierre Pronchery 302b077aed3SPierre Pronchery if (dngbl == NULL) 303b077aed3SPierre Pronchery return; 304b077aed3SPierre Pronchery 305b077aed3SPierre Pronchery CRYPTO_THREAD_lock_free(dngbl->rand_nonce_lock); 306b077aed3SPierre Pronchery 307b077aed3SPierre Pronchery OPENSSL_free(dngbl); 308b077aed3SPierre Pronchery } 309b077aed3SPierre Pronchery 310b077aed3SPierre Pronchery static const OSSL_LIB_CTX_METHOD drbg_nonce_ossl_ctx_method = { 311b077aed3SPierre Pronchery OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY, 312b077aed3SPierre Pronchery prov_drbg_nonce_ossl_ctx_new, 313b077aed3SPierre Pronchery prov_drbg_nonce_ossl_ctx_free, 314b077aed3SPierre Pronchery }; 315b077aed3SPierre Pronchery 316b077aed3SPierre Pronchery /* Get a nonce from the operating system */ 317b077aed3SPierre Pronchery static size_t prov_drbg_get_nonce(PROV_DRBG *drbg, unsigned char **pout, 318b077aed3SPierre Pronchery size_t min_len, size_t max_len) 319b077aed3SPierre Pronchery { 320b077aed3SPierre Pronchery size_t ret = 0, n; 321b077aed3SPierre Pronchery unsigned char *buf = NULL; 322b077aed3SPierre Pronchery OSSL_LIB_CTX *libctx = ossl_prov_ctx_get0_libctx(drbg->provctx); 323b077aed3SPierre Pronchery PROV_DRBG_NONCE_GLOBAL *dngbl 324b077aed3SPierre Pronchery = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_DRBG_NONCE_INDEX, 325b077aed3SPierre Pronchery &drbg_nonce_ossl_ctx_method); 326b077aed3SPierre Pronchery struct { 327b077aed3SPierre Pronchery void *drbg; 328b077aed3SPierre Pronchery int count; 329b077aed3SPierre Pronchery } data; 330b077aed3SPierre Pronchery 331b077aed3SPierre Pronchery if (dngbl == NULL) 332b077aed3SPierre Pronchery return 0; 333b077aed3SPierre Pronchery 334b077aed3SPierre Pronchery if (drbg->parent != NULL && drbg->parent_nonce != NULL) { 335b077aed3SPierre Pronchery n = drbg->parent_nonce(drbg->parent, NULL, 0, drbg->min_noncelen, 336b077aed3SPierre Pronchery drbg->max_noncelen); 337b077aed3SPierre Pronchery if (n > 0 && (buf = OPENSSL_malloc(n)) != NULL) { 338b077aed3SPierre Pronchery ret = drbg->parent_nonce(drbg->parent, buf, 0, 339b077aed3SPierre Pronchery drbg->min_noncelen, drbg->max_noncelen); 340b077aed3SPierre Pronchery if (ret == n) { 341b077aed3SPierre Pronchery *pout = buf; 342b077aed3SPierre Pronchery return ret; 343b077aed3SPierre Pronchery } 344b077aed3SPierre Pronchery OPENSSL_free(buf); 345b077aed3SPierre Pronchery } 346b077aed3SPierre Pronchery } 347b077aed3SPierre Pronchery 348b077aed3SPierre Pronchery /* Use the built in nonce source plus some of our specifics */ 349b077aed3SPierre Pronchery memset(&data, 0, sizeof(data)); 350b077aed3SPierre Pronchery data.drbg = drbg; 351b077aed3SPierre Pronchery CRYPTO_atomic_add(&dngbl->rand_nonce_count, 1, &data.count, 352b077aed3SPierre Pronchery dngbl->rand_nonce_lock); 353b077aed3SPierre Pronchery return ossl_prov_get_nonce(drbg->provctx, pout, min_len, max_len, 354b077aed3SPierre Pronchery &data, sizeof(data)); 355b077aed3SPierre Pronchery } 356b077aed3SPierre Pronchery #endif /* PROV_RAND_GET_RANDOM_NONCE */ 357b077aed3SPierre Pronchery 358b077aed3SPierre Pronchery /* 359b077aed3SPierre Pronchery * Instantiate |drbg|, after it has been initialized. Use |pers| and 360b077aed3SPierre Pronchery * |perslen| as prediction-resistance input. 361b077aed3SPierre Pronchery * 362b077aed3SPierre Pronchery * Requires that drbg->lock is already locked for write, if non-null. 363b077aed3SPierre Pronchery * 364b077aed3SPierre Pronchery * Returns 1 on success, 0 on failure. 365b077aed3SPierre Pronchery */ 366b077aed3SPierre Pronchery int ossl_prov_drbg_instantiate(PROV_DRBG *drbg, unsigned int strength, 367b077aed3SPierre Pronchery int prediction_resistance, 368b077aed3SPierre Pronchery const unsigned char *pers, size_t perslen) 369b077aed3SPierre Pronchery { 370b077aed3SPierre Pronchery unsigned char *nonce = NULL, *entropy = NULL; 371b077aed3SPierre Pronchery size_t noncelen = 0, entropylen = 0; 372b077aed3SPierre Pronchery size_t min_entropy, min_entropylen, max_entropylen; 373b077aed3SPierre Pronchery 374b077aed3SPierre Pronchery if (strength > drbg->strength) { 375b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_INSUFFICIENT_DRBG_STRENGTH); 376b077aed3SPierre Pronchery goto end; 377b077aed3SPierre Pronchery } 378b077aed3SPierre Pronchery min_entropy = drbg->strength; 379b077aed3SPierre Pronchery min_entropylen = drbg->min_entropylen; 380b077aed3SPierre Pronchery max_entropylen = drbg->max_entropylen; 381b077aed3SPierre Pronchery 382b077aed3SPierre Pronchery if (pers == NULL) { 383b077aed3SPierre Pronchery pers = (const unsigned char *)ossl_pers_string; 384b077aed3SPierre Pronchery perslen = sizeof(ossl_pers_string); 385b077aed3SPierre Pronchery } 386b077aed3SPierre Pronchery if (perslen > drbg->max_perslen) { 387b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_PERSONALISATION_STRING_TOO_LONG); 388b077aed3SPierre Pronchery goto end; 389b077aed3SPierre Pronchery } 390b077aed3SPierre Pronchery 391b077aed3SPierre Pronchery if (drbg->state != EVP_RAND_STATE_UNINITIALISED) { 392b077aed3SPierre Pronchery if (drbg->state == EVP_RAND_STATE_ERROR) 393b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_IN_ERROR_STATE); 394b077aed3SPierre Pronchery else 395b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_ALREADY_INSTANTIATED); 396b077aed3SPierre Pronchery goto end; 397b077aed3SPierre Pronchery } 398b077aed3SPierre Pronchery 399b077aed3SPierre Pronchery drbg->state = EVP_RAND_STATE_ERROR; 400b077aed3SPierre Pronchery 401b077aed3SPierre Pronchery if (drbg->min_noncelen > 0) { 402b077aed3SPierre Pronchery if (drbg->parent_nonce != NULL) { 403b077aed3SPierre Pronchery noncelen = drbg->parent_nonce(drbg->parent, NULL, drbg->strength, 404b077aed3SPierre Pronchery drbg->min_noncelen, 405b077aed3SPierre Pronchery drbg->max_noncelen); 406b077aed3SPierre Pronchery if (noncelen == 0) { 407b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_NONCE); 408b077aed3SPierre Pronchery goto end; 409b077aed3SPierre Pronchery } 410b077aed3SPierre Pronchery nonce = OPENSSL_malloc(noncelen); 411b077aed3SPierre Pronchery if (nonce == NULL) { 412b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_NONCE); 413b077aed3SPierre Pronchery goto end; 414b077aed3SPierre Pronchery } 415b077aed3SPierre Pronchery if (noncelen != drbg->parent_nonce(drbg->parent, nonce, 416b077aed3SPierre Pronchery drbg->strength, 417b077aed3SPierre Pronchery drbg->min_noncelen, 418b077aed3SPierre Pronchery drbg->max_noncelen)) { 419b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_NONCE); 420b077aed3SPierre Pronchery goto end; 421b077aed3SPierre Pronchery } 422b077aed3SPierre Pronchery #ifndef PROV_RAND_GET_RANDOM_NONCE 423b077aed3SPierre Pronchery } else if (drbg->parent != NULL) { 424b077aed3SPierre Pronchery #endif 425b077aed3SPierre Pronchery /* 426b077aed3SPierre Pronchery * NIST SP800-90Ar1 section 9.1 says you can combine getting 427b077aed3SPierre Pronchery * the entropy and nonce in 1 call by increasing the entropy 428b077aed3SPierre Pronchery * with 50% and increasing the minimum length to accommodate 429b077aed3SPierre Pronchery * the length of the nonce. We do this in case a nonce is 430b077aed3SPierre Pronchery * required and there is no parental nonce capability. 431b077aed3SPierre Pronchery */ 432b077aed3SPierre Pronchery min_entropy += drbg->strength / 2; 433b077aed3SPierre Pronchery min_entropylen += drbg->min_noncelen; 434b077aed3SPierre Pronchery max_entropylen += drbg->max_noncelen; 435b077aed3SPierre Pronchery } 436b077aed3SPierre Pronchery #ifndef PROV_RAND_GET_RANDOM_NONCE 437b077aed3SPierre Pronchery else { /* parent == NULL */ 438b077aed3SPierre Pronchery noncelen = prov_drbg_get_nonce(drbg, &nonce, drbg->min_noncelen, 439b077aed3SPierre Pronchery drbg->max_noncelen); 440b077aed3SPierre Pronchery if (noncelen < drbg->min_noncelen 441b077aed3SPierre Pronchery || noncelen > drbg->max_noncelen) { 442b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_NONCE); 443b077aed3SPierre Pronchery goto end; 444b077aed3SPierre Pronchery } 445b077aed3SPierre Pronchery } 446b077aed3SPierre Pronchery #endif 447b077aed3SPierre Pronchery } 448b077aed3SPierre Pronchery 449b077aed3SPierre Pronchery drbg->reseed_next_counter = tsan_load(&drbg->reseed_counter); 450b077aed3SPierre Pronchery if (drbg->reseed_next_counter) { 451b077aed3SPierre Pronchery drbg->reseed_next_counter++; 452b077aed3SPierre Pronchery if (!drbg->reseed_next_counter) 453b077aed3SPierre Pronchery drbg->reseed_next_counter = 1; 454b077aed3SPierre Pronchery } 455b077aed3SPierre Pronchery 456b077aed3SPierre Pronchery entropylen = get_entropy(drbg, &entropy, min_entropy, 457b077aed3SPierre Pronchery min_entropylen, max_entropylen, 458b077aed3SPierre Pronchery prediction_resistance); 459b077aed3SPierre Pronchery if (entropylen < min_entropylen 460b077aed3SPierre Pronchery || entropylen > max_entropylen) { 461b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_ENTROPY); 462b077aed3SPierre Pronchery goto end; 463b077aed3SPierre Pronchery } 464b077aed3SPierre Pronchery 465b077aed3SPierre Pronchery if (!drbg->instantiate(drbg, entropy, entropylen, nonce, noncelen, 466b077aed3SPierre Pronchery pers, perslen)) { 467b077aed3SPierre Pronchery cleanup_entropy(drbg, entropy, entropylen); 468b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_ERROR_INSTANTIATING_DRBG); 469b077aed3SPierre Pronchery goto end; 470b077aed3SPierre Pronchery } 471b077aed3SPierre Pronchery cleanup_entropy(drbg, entropy, entropylen); 472b077aed3SPierre Pronchery 473b077aed3SPierre Pronchery drbg->state = EVP_RAND_STATE_READY; 474b077aed3SPierre Pronchery drbg->generate_counter = 1; 475b077aed3SPierre Pronchery drbg->reseed_time = time(NULL); 476b077aed3SPierre Pronchery tsan_store(&drbg->reseed_counter, drbg->reseed_next_counter); 477b077aed3SPierre Pronchery 478b077aed3SPierre Pronchery end: 479b077aed3SPierre Pronchery if (nonce != NULL) 480b077aed3SPierre Pronchery ossl_prov_cleanup_nonce(drbg->provctx, nonce, noncelen); 481b077aed3SPierre Pronchery if (drbg->state == EVP_RAND_STATE_READY) 482b077aed3SPierre Pronchery return 1; 483b077aed3SPierre Pronchery return 0; 484b077aed3SPierre Pronchery } 485b077aed3SPierre Pronchery 486b077aed3SPierre Pronchery /* 487b077aed3SPierre Pronchery * Uninstantiate |drbg|. Must be instantiated before it can be used. 488b077aed3SPierre Pronchery * 489b077aed3SPierre Pronchery * Requires that drbg->lock is already locked for write, if non-null. 490b077aed3SPierre Pronchery * 491b077aed3SPierre Pronchery * Returns 1 on success, 0 on failure. 492b077aed3SPierre Pronchery */ 493b077aed3SPierre Pronchery int ossl_prov_drbg_uninstantiate(PROV_DRBG *drbg) 494b077aed3SPierre Pronchery { 495b077aed3SPierre Pronchery drbg->state = EVP_RAND_STATE_UNINITIALISED; 496b077aed3SPierre Pronchery return 1; 497b077aed3SPierre Pronchery } 498b077aed3SPierre Pronchery 499b077aed3SPierre Pronchery /* 500b077aed3SPierre Pronchery * Reseed |drbg|, mixing in the specified data 501b077aed3SPierre Pronchery * 502b077aed3SPierre Pronchery * Requires that drbg->lock is already locked for write, if non-null. 503b077aed3SPierre Pronchery * 504b077aed3SPierre Pronchery * Returns 1 on success, 0 on failure. 505b077aed3SPierre Pronchery */ 506b077aed3SPierre Pronchery int ossl_prov_drbg_reseed(PROV_DRBG *drbg, int prediction_resistance, 507b077aed3SPierre Pronchery const unsigned char *ent, size_t ent_len, 508b077aed3SPierre Pronchery const unsigned char *adin, size_t adinlen) 509b077aed3SPierre Pronchery { 510b077aed3SPierre Pronchery unsigned char *entropy = NULL; 511b077aed3SPierre Pronchery size_t entropylen = 0; 512b077aed3SPierre Pronchery 513b077aed3SPierre Pronchery if (!ossl_prov_is_running()) 514b077aed3SPierre Pronchery return 0; 515b077aed3SPierre Pronchery 516b077aed3SPierre Pronchery if (drbg->state != EVP_RAND_STATE_READY) { 517b077aed3SPierre Pronchery /* try to recover from previous errors */ 518b077aed3SPierre Pronchery rand_drbg_restart(drbg); 519b077aed3SPierre Pronchery 520b077aed3SPierre Pronchery if (drbg->state == EVP_RAND_STATE_ERROR) { 521b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_IN_ERROR_STATE); 522b077aed3SPierre Pronchery return 0; 523b077aed3SPierre Pronchery } 524b077aed3SPierre Pronchery if (drbg->state == EVP_RAND_STATE_UNINITIALISED) { 525b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_NOT_INSTANTIATED); 526b077aed3SPierre Pronchery return 0; 527b077aed3SPierre Pronchery } 528b077aed3SPierre Pronchery } 529b077aed3SPierre Pronchery 530b077aed3SPierre Pronchery if (ent != NULL) { 531b077aed3SPierre Pronchery if (ent_len < drbg->min_entropylen) { 532b077aed3SPierre Pronchery ERR_raise(ERR_LIB_RAND, RAND_R_ENTROPY_OUT_OF_RANGE); 533b077aed3SPierre Pronchery drbg->state = EVP_RAND_STATE_ERROR; 534b077aed3SPierre Pronchery return 0; 535b077aed3SPierre Pronchery } 536b077aed3SPierre Pronchery if (ent_len > drbg->max_entropylen) { 537b077aed3SPierre Pronchery ERR_raise(ERR_LIB_RAND, RAND_R_ENTROPY_INPUT_TOO_LONG); 538b077aed3SPierre Pronchery drbg->state = EVP_RAND_STATE_ERROR; 539b077aed3SPierre Pronchery return 0; 540b077aed3SPierre Pronchery } 541b077aed3SPierre Pronchery } 542b077aed3SPierre Pronchery 543b077aed3SPierre Pronchery if (adin == NULL) { 544b077aed3SPierre Pronchery adinlen = 0; 545b077aed3SPierre Pronchery } else if (adinlen > drbg->max_adinlen) { 546b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_ADDITIONAL_INPUT_TOO_LONG); 547b077aed3SPierre Pronchery return 0; 548b077aed3SPierre Pronchery } 549b077aed3SPierre Pronchery 550b077aed3SPierre Pronchery drbg->state = EVP_RAND_STATE_ERROR; 551b077aed3SPierre Pronchery 552b077aed3SPierre Pronchery drbg->reseed_next_counter = tsan_load(&drbg->reseed_counter); 553b077aed3SPierre Pronchery if (drbg->reseed_next_counter) { 554b077aed3SPierre Pronchery drbg->reseed_next_counter++; 555b077aed3SPierre Pronchery if (!drbg->reseed_next_counter) 556b077aed3SPierre Pronchery drbg->reseed_next_counter = 1; 557b077aed3SPierre Pronchery } 558b077aed3SPierre Pronchery 559b077aed3SPierre Pronchery if (ent != NULL) { 560b077aed3SPierre Pronchery #ifdef FIPS_MODULE 561b077aed3SPierre Pronchery /* 562b077aed3SPierre Pronchery * NIST SP-800-90A mandates that entropy *shall not* be provided 563b077aed3SPierre Pronchery * by the consuming application. Instead the data is added as additional 564b077aed3SPierre Pronchery * input. 565b077aed3SPierre Pronchery * 566b077aed3SPierre Pronchery * (NIST SP-800-90Ar1, Sections 9.1 and 9.2) 567b077aed3SPierre Pronchery */ 568b077aed3SPierre Pronchery if (!drbg->reseed(drbg, NULL, 0, ent, ent_len)) { 569b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_RESEED); 570b077aed3SPierre Pronchery return 0; 571b077aed3SPierre Pronchery } 572b077aed3SPierre Pronchery #else 573b077aed3SPierre Pronchery if (!drbg->reseed(drbg, ent, ent_len, adin, adinlen)) { 574b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_RESEED); 575b077aed3SPierre Pronchery return 0; 576b077aed3SPierre Pronchery } 577b077aed3SPierre Pronchery /* There isn't much point adding the same additional input twice */ 578b077aed3SPierre Pronchery adin = NULL; 579b077aed3SPierre Pronchery adinlen = 0; 580b077aed3SPierre Pronchery #endif 581b077aed3SPierre Pronchery } 582b077aed3SPierre Pronchery 583b077aed3SPierre Pronchery /* Reseed using our sources in addition */ 584b077aed3SPierre Pronchery entropylen = get_entropy(drbg, &entropy, drbg->strength, 585b077aed3SPierre Pronchery drbg->min_entropylen, drbg->max_entropylen, 586b077aed3SPierre Pronchery prediction_resistance); 587b077aed3SPierre Pronchery if (entropylen < drbg->min_entropylen 588b077aed3SPierre Pronchery || entropylen > drbg->max_entropylen) { 589b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_ERROR_RETRIEVING_ENTROPY); 590b077aed3SPierre Pronchery goto end; 591b077aed3SPierre Pronchery } 592b077aed3SPierre Pronchery 593b077aed3SPierre Pronchery if (!drbg->reseed(drbg, entropy, entropylen, adin, adinlen)) 594b077aed3SPierre Pronchery goto end; 595b077aed3SPierre Pronchery 596b077aed3SPierre Pronchery drbg->state = EVP_RAND_STATE_READY; 597b077aed3SPierre Pronchery drbg->generate_counter = 1; 598b077aed3SPierre Pronchery drbg->reseed_time = time(NULL); 599b077aed3SPierre Pronchery tsan_store(&drbg->reseed_counter, drbg->reseed_next_counter); 600b077aed3SPierre Pronchery if (drbg->parent != NULL) 601b077aed3SPierre Pronchery drbg->parent_reseed_counter = get_parent_reseed_count(drbg); 602b077aed3SPierre Pronchery 603b077aed3SPierre Pronchery end: 604b077aed3SPierre Pronchery cleanup_entropy(drbg, entropy, entropylen); 605b077aed3SPierre Pronchery if (drbg->state == EVP_RAND_STATE_READY) 606b077aed3SPierre Pronchery return 1; 607b077aed3SPierre Pronchery return 0; 608b077aed3SPierre Pronchery } 609b077aed3SPierre Pronchery 610b077aed3SPierre Pronchery /* 611b077aed3SPierre Pronchery * Generate |outlen| bytes into the buffer at |out|. Reseed if we need 612b077aed3SPierre Pronchery * to or if |prediction_resistance| is set. Additional input can be 613b077aed3SPierre Pronchery * sent in |adin| and |adinlen|. 614b077aed3SPierre Pronchery * 615b077aed3SPierre Pronchery * Requires that drbg->lock is already locked for write, if non-null. 616b077aed3SPierre Pronchery * 617b077aed3SPierre Pronchery * Returns 1 on success, 0 on failure. 618b077aed3SPierre Pronchery * 619b077aed3SPierre Pronchery */ 620b077aed3SPierre Pronchery int ossl_prov_drbg_generate(PROV_DRBG *drbg, unsigned char *out, size_t outlen, 621b077aed3SPierre Pronchery unsigned int strength, int prediction_resistance, 622b077aed3SPierre Pronchery const unsigned char *adin, size_t adinlen) 623b077aed3SPierre Pronchery { 624b077aed3SPierre Pronchery int fork_id; 625b077aed3SPierre Pronchery int reseed_required = 0; 626b077aed3SPierre Pronchery 627b077aed3SPierre Pronchery if (!ossl_prov_is_running()) 628b077aed3SPierre Pronchery return 0; 629b077aed3SPierre Pronchery 630b077aed3SPierre Pronchery if (drbg->state != EVP_RAND_STATE_READY) { 631b077aed3SPierre Pronchery /* try to recover from previous errors */ 632b077aed3SPierre Pronchery rand_drbg_restart(drbg); 633b077aed3SPierre Pronchery 634b077aed3SPierre Pronchery if (drbg->state == EVP_RAND_STATE_ERROR) { 635b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_IN_ERROR_STATE); 636b077aed3SPierre Pronchery return 0; 637b077aed3SPierre Pronchery } 638b077aed3SPierre Pronchery if (drbg->state == EVP_RAND_STATE_UNINITIALISED) { 639b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_NOT_INSTANTIATED); 640b077aed3SPierre Pronchery return 0; 641b077aed3SPierre Pronchery } 642b077aed3SPierre Pronchery } 643b077aed3SPierre Pronchery if (strength > drbg->strength) { 644b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_INSUFFICIENT_DRBG_STRENGTH); 645b077aed3SPierre Pronchery return 0; 646b077aed3SPierre Pronchery } 647b077aed3SPierre Pronchery 648b077aed3SPierre Pronchery if (outlen > drbg->max_request) { 649b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_REQUEST_TOO_LARGE_FOR_DRBG); 650b077aed3SPierre Pronchery return 0; 651b077aed3SPierre Pronchery } 652b077aed3SPierre Pronchery if (adinlen > drbg->max_adinlen) { 653b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_ADDITIONAL_INPUT_TOO_LONG); 654b077aed3SPierre Pronchery return 0; 655b077aed3SPierre Pronchery } 656b077aed3SPierre Pronchery 657b077aed3SPierre Pronchery fork_id = openssl_get_fork_id(); 658b077aed3SPierre Pronchery 659b077aed3SPierre Pronchery if (drbg->fork_id != fork_id) { 660b077aed3SPierre Pronchery drbg->fork_id = fork_id; 661b077aed3SPierre Pronchery reseed_required = 1; 662b077aed3SPierre Pronchery } 663b077aed3SPierre Pronchery 664b077aed3SPierre Pronchery if (drbg->reseed_interval > 0) { 665b077aed3SPierre Pronchery if (drbg->generate_counter >= drbg->reseed_interval) 666b077aed3SPierre Pronchery reseed_required = 1; 667b077aed3SPierre Pronchery } 668b077aed3SPierre Pronchery if (drbg->reseed_time_interval > 0) { 669b077aed3SPierre Pronchery time_t now = time(NULL); 670b077aed3SPierre Pronchery if (now < drbg->reseed_time 671b077aed3SPierre Pronchery || now - drbg->reseed_time >= drbg->reseed_time_interval) 672b077aed3SPierre Pronchery reseed_required = 1; 673b077aed3SPierre Pronchery } 674b077aed3SPierre Pronchery if (drbg->parent != NULL 675b077aed3SPierre Pronchery && get_parent_reseed_count(drbg) != drbg->parent_reseed_counter) 676b077aed3SPierre Pronchery reseed_required = 1; 677b077aed3SPierre Pronchery 678b077aed3SPierre Pronchery if (reseed_required || prediction_resistance) { 679b077aed3SPierre Pronchery if (!ossl_prov_drbg_reseed(drbg, prediction_resistance, NULL, 0, 680b077aed3SPierre Pronchery adin, adinlen)) { 681b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_RESEED_ERROR); 682b077aed3SPierre Pronchery return 0; 683b077aed3SPierre Pronchery } 684b077aed3SPierre Pronchery adin = NULL; 685b077aed3SPierre Pronchery adinlen = 0; 686b077aed3SPierre Pronchery } 687b077aed3SPierre Pronchery 688b077aed3SPierre Pronchery if (!drbg->generate(drbg, out, outlen, adin, adinlen)) { 689b077aed3SPierre Pronchery drbg->state = EVP_RAND_STATE_ERROR; 690b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_GENERATE_ERROR); 691b077aed3SPierre Pronchery return 0; 692b077aed3SPierre Pronchery } 693b077aed3SPierre Pronchery 694b077aed3SPierre Pronchery drbg->generate_counter++; 695b077aed3SPierre Pronchery 696b077aed3SPierre Pronchery return 1; 697b077aed3SPierre Pronchery } 698b077aed3SPierre Pronchery 699b077aed3SPierre Pronchery /* 700b077aed3SPierre Pronchery * Restart |drbg|, using the specified entropy or additional input 701b077aed3SPierre Pronchery * 702b077aed3SPierre Pronchery * Tries its best to get the drbg instantiated by all means, 703b077aed3SPierre Pronchery * regardless of its current state. 704b077aed3SPierre Pronchery * 705b077aed3SPierre Pronchery * Optionally, a |buffer| of |len| random bytes can be passed, 706b077aed3SPierre Pronchery * which is assumed to contain at least |entropy| bits of entropy. 707b077aed3SPierre Pronchery * 708b077aed3SPierre Pronchery * If |entropy| > 0, the buffer content is used as entropy input. 709b077aed3SPierre Pronchery * 710b077aed3SPierre Pronchery * If |entropy| == 0, the buffer content is used as additional input 711b077aed3SPierre Pronchery * 712b077aed3SPierre Pronchery * Returns 1 on success, 0 on failure. 713b077aed3SPierre Pronchery * 714b077aed3SPierre Pronchery * This function is used internally only. 715b077aed3SPierre Pronchery */ 716b077aed3SPierre Pronchery static int rand_drbg_restart(PROV_DRBG *drbg) 717b077aed3SPierre Pronchery { 718b077aed3SPierre Pronchery /* repair error state */ 719b077aed3SPierre Pronchery if (drbg->state == EVP_RAND_STATE_ERROR) 720b077aed3SPierre Pronchery drbg->uninstantiate(drbg); 721b077aed3SPierre Pronchery 722b077aed3SPierre Pronchery /* repair uninitialized state */ 723b077aed3SPierre Pronchery if (drbg->state == EVP_RAND_STATE_UNINITIALISED) 724b077aed3SPierre Pronchery /* reinstantiate drbg */ 725b077aed3SPierre Pronchery ossl_prov_drbg_instantiate(drbg, drbg->strength, 0, NULL, 0); 726b077aed3SPierre Pronchery 727b077aed3SPierre Pronchery return drbg->state == EVP_RAND_STATE_READY; 728b077aed3SPierre Pronchery } 729b077aed3SPierre Pronchery 730b077aed3SPierre Pronchery /* Provider support from here down */ 731b077aed3SPierre Pronchery static const OSSL_DISPATCH *find_call(const OSSL_DISPATCH *dispatch, 732b077aed3SPierre Pronchery int function) 733b077aed3SPierre Pronchery { 734b077aed3SPierre Pronchery if (dispatch != NULL) 735b077aed3SPierre Pronchery while (dispatch->function_id != 0) { 736b077aed3SPierre Pronchery if (dispatch->function_id == function) 737b077aed3SPierre Pronchery return dispatch; 738b077aed3SPierre Pronchery dispatch++; 739b077aed3SPierre Pronchery } 740b077aed3SPierre Pronchery return NULL; 741b077aed3SPierre Pronchery } 742b077aed3SPierre Pronchery 743b077aed3SPierre Pronchery int ossl_drbg_enable_locking(void *vctx) 744b077aed3SPierre Pronchery { 745b077aed3SPierre Pronchery PROV_DRBG *drbg = vctx; 746b077aed3SPierre Pronchery 747b077aed3SPierre Pronchery if (drbg != NULL && drbg->lock == NULL) { 748b077aed3SPierre Pronchery if (drbg->parent_enable_locking != NULL) 749b077aed3SPierre Pronchery if (!drbg->parent_enable_locking(drbg->parent)) { 750b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED); 751b077aed3SPierre Pronchery return 0; 752b077aed3SPierre Pronchery } 753b077aed3SPierre Pronchery drbg->lock = CRYPTO_THREAD_lock_new(); 754b077aed3SPierre Pronchery if (drbg->lock == NULL) { 755b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_CREATE_LOCK); 756b077aed3SPierre Pronchery return 0; 757b077aed3SPierre Pronchery } 758b077aed3SPierre Pronchery } 759b077aed3SPierre Pronchery return 1; 760b077aed3SPierre Pronchery } 761b077aed3SPierre Pronchery 762b077aed3SPierre Pronchery /* 763b077aed3SPierre Pronchery * Allocate memory and initialize a new DRBG. The DRBG is allocated on 764b077aed3SPierre Pronchery * the secure heap if |secure| is nonzero and the secure heap is enabled. 765b077aed3SPierre Pronchery * The |parent|, if not NULL, will be used as random source for reseeding. 766b077aed3SPierre Pronchery * This also requires the parent's provider context and the parent's lock. 767b077aed3SPierre Pronchery * 768b077aed3SPierre Pronchery * Returns a pointer to the new DRBG instance on success, NULL on failure. 769b077aed3SPierre Pronchery */ 770b077aed3SPierre Pronchery PROV_DRBG *ossl_rand_drbg_new 771b077aed3SPierre Pronchery (void *provctx, void *parent, const OSSL_DISPATCH *p_dispatch, 772b077aed3SPierre Pronchery int (*dnew)(PROV_DRBG *ctx), 77344096ebdSEnji Cooper void (*dfree)(void *vctx), 774b077aed3SPierre Pronchery int (*instantiate)(PROV_DRBG *drbg, 775b077aed3SPierre Pronchery const unsigned char *entropy, size_t entropylen, 776b077aed3SPierre Pronchery const unsigned char *nonce, size_t noncelen, 777b077aed3SPierre Pronchery const unsigned char *pers, size_t perslen), 778b077aed3SPierre Pronchery int (*uninstantiate)(PROV_DRBG *ctx), 779b077aed3SPierre Pronchery int (*reseed)(PROV_DRBG *drbg, const unsigned char *ent, size_t ent_len, 780b077aed3SPierre Pronchery const unsigned char *adin, size_t adin_len), 781b077aed3SPierre Pronchery int (*generate)(PROV_DRBG *, unsigned char *out, size_t outlen, 782b077aed3SPierre Pronchery const unsigned char *adin, size_t adin_len)) 783b077aed3SPierre Pronchery { 784b077aed3SPierre Pronchery PROV_DRBG *drbg; 785b077aed3SPierre Pronchery unsigned int p_str; 786b077aed3SPierre Pronchery const OSSL_DISPATCH *pfunc; 787b077aed3SPierre Pronchery 788b077aed3SPierre Pronchery if (!ossl_prov_is_running()) 789b077aed3SPierre Pronchery return NULL; 790b077aed3SPierre Pronchery 791b077aed3SPierre Pronchery drbg = OPENSSL_zalloc(sizeof(*drbg)); 792b077aed3SPierre Pronchery if (drbg == NULL) { 793b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); 794b077aed3SPierre Pronchery return NULL; 795b077aed3SPierre Pronchery } 796b077aed3SPierre Pronchery 797b077aed3SPierre Pronchery drbg->provctx = provctx; 798b077aed3SPierre Pronchery drbg->instantiate = instantiate; 799b077aed3SPierre Pronchery drbg->uninstantiate = uninstantiate; 800b077aed3SPierre Pronchery drbg->reseed = reseed; 801b077aed3SPierre Pronchery drbg->generate = generate; 802b077aed3SPierre Pronchery drbg->fork_id = openssl_get_fork_id(); 803b077aed3SPierre Pronchery 804b077aed3SPierre Pronchery /* Extract parent's functions */ 805b077aed3SPierre Pronchery drbg->parent = parent; 806b077aed3SPierre Pronchery if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_ENABLE_LOCKING)) != NULL) 807b077aed3SPierre Pronchery drbg->parent_enable_locking = OSSL_FUNC_rand_enable_locking(pfunc); 808b077aed3SPierre Pronchery if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_LOCK)) != NULL) 809b077aed3SPierre Pronchery drbg->parent_lock = OSSL_FUNC_rand_lock(pfunc); 810b077aed3SPierre Pronchery if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_UNLOCK)) != NULL) 811b077aed3SPierre Pronchery drbg->parent_unlock = OSSL_FUNC_rand_unlock(pfunc); 812b077aed3SPierre Pronchery if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_GET_CTX_PARAMS)) != NULL) 813b077aed3SPierre Pronchery drbg->parent_get_ctx_params = OSSL_FUNC_rand_get_ctx_params(pfunc); 814b077aed3SPierre Pronchery if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_NONCE)) != NULL) 815b077aed3SPierre Pronchery drbg->parent_nonce = OSSL_FUNC_rand_nonce(pfunc); 816b077aed3SPierre Pronchery if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_GET_SEED)) != NULL) 817b077aed3SPierre Pronchery drbg->parent_get_seed = OSSL_FUNC_rand_get_seed(pfunc); 818b077aed3SPierre Pronchery if ((pfunc = find_call(p_dispatch, OSSL_FUNC_RAND_CLEAR_SEED)) != NULL) 819b077aed3SPierre Pronchery drbg->parent_clear_seed = OSSL_FUNC_rand_clear_seed(pfunc); 820b077aed3SPierre Pronchery 821b077aed3SPierre Pronchery /* Set some default maximums up */ 822b077aed3SPierre Pronchery drbg->max_entropylen = DRBG_MAX_LENGTH; 823b077aed3SPierre Pronchery drbg->max_noncelen = DRBG_MAX_LENGTH; 824b077aed3SPierre Pronchery drbg->max_perslen = DRBG_MAX_LENGTH; 825b077aed3SPierre Pronchery drbg->max_adinlen = DRBG_MAX_LENGTH; 826b077aed3SPierre Pronchery drbg->generate_counter = 1; 827b077aed3SPierre Pronchery drbg->reseed_counter = 1; 828b077aed3SPierre Pronchery drbg->reseed_interval = RESEED_INTERVAL; 829b077aed3SPierre Pronchery drbg->reseed_time_interval = TIME_INTERVAL; 830b077aed3SPierre Pronchery 831b077aed3SPierre Pronchery if (!dnew(drbg)) 832b077aed3SPierre Pronchery goto err; 833b077aed3SPierre Pronchery 834b077aed3SPierre Pronchery if (parent != NULL) { 835b077aed3SPierre Pronchery if (!get_parent_strength(drbg, &p_str)) 836b077aed3SPierre Pronchery goto err; 837b077aed3SPierre Pronchery if (drbg->strength > p_str) { 838b077aed3SPierre Pronchery /* 839b077aed3SPierre Pronchery * We currently don't support the algorithm from NIST SP 800-90C 840b077aed3SPierre Pronchery * 10.1.2 to use a weaker DRBG as source 841b077aed3SPierre Pronchery */ 842b077aed3SPierre Pronchery ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_STRENGTH_TOO_WEAK); 843b077aed3SPierre Pronchery goto err; 844b077aed3SPierre Pronchery } 845b077aed3SPierre Pronchery } 846b077aed3SPierre Pronchery #ifdef TSAN_REQUIRES_LOCKING 847b077aed3SPierre Pronchery if (!ossl_drbg_enable_locking(drbg)) 848b077aed3SPierre Pronchery goto err; 849b077aed3SPierre Pronchery #endif 850b077aed3SPierre Pronchery return drbg; 851b077aed3SPierre Pronchery 852b077aed3SPierre Pronchery err: 85344096ebdSEnji Cooper dfree(drbg); 854b077aed3SPierre Pronchery return NULL; 855b077aed3SPierre Pronchery } 856b077aed3SPierre Pronchery 857b077aed3SPierre Pronchery void ossl_rand_drbg_free(PROV_DRBG *drbg) 858b077aed3SPierre Pronchery { 859b077aed3SPierre Pronchery if (drbg == NULL) 860b077aed3SPierre Pronchery return; 861b077aed3SPierre Pronchery 862b077aed3SPierre Pronchery CRYPTO_THREAD_lock_free(drbg->lock); 863b077aed3SPierre Pronchery OPENSSL_free(drbg); 864b077aed3SPierre Pronchery } 865b077aed3SPierre Pronchery 866b077aed3SPierre Pronchery int ossl_drbg_get_ctx_params(PROV_DRBG *drbg, OSSL_PARAM params[]) 867b077aed3SPierre Pronchery { 868b077aed3SPierre Pronchery OSSL_PARAM *p; 869b077aed3SPierre Pronchery 870b077aed3SPierre Pronchery p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STATE); 871b077aed3SPierre Pronchery if (p != NULL && !OSSL_PARAM_set_int(p, drbg->state)) 872b077aed3SPierre Pronchery return 0; 873b077aed3SPierre Pronchery 874b077aed3SPierre Pronchery p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STRENGTH); 875b077aed3SPierre Pronchery if (p != NULL && !OSSL_PARAM_set_int(p, drbg->strength)) 876b077aed3SPierre Pronchery return 0; 877b077aed3SPierre Pronchery 878b077aed3SPierre Pronchery p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST); 879b077aed3SPierre Pronchery if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_request)) 880b077aed3SPierre Pronchery return 0; 881b077aed3SPierre Pronchery 882b077aed3SPierre Pronchery p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MIN_ENTROPYLEN); 883b077aed3SPierre Pronchery if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->min_entropylen)) 884b077aed3SPierre Pronchery return 0; 885b077aed3SPierre Pronchery 886b077aed3SPierre Pronchery p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_ENTROPYLEN); 887b077aed3SPierre Pronchery if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_entropylen)) 888b077aed3SPierre Pronchery return 0; 889b077aed3SPierre Pronchery 890b077aed3SPierre Pronchery p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MIN_NONCELEN); 891b077aed3SPierre Pronchery if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->min_noncelen)) 892b077aed3SPierre Pronchery return 0; 893b077aed3SPierre Pronchery 894b077aed3SPierre Pronchery p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_NONCELEN); 895b077aed3SPierre Pronchery if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_noncelen)) 896b077aed3SPierre Pronchery return 0; 897b077aed3SPierre Pronchery 898b077aed3SPierre Pronchery p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_PERSLEN); 899b077aed3SPierre Pronchery if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_perslen)) 900b077aed3SPierre Pronchery return 0; 901b077aed3SPierre Pronchery 902b077aed3SPierre Pronchery p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAX_ADINLEN); 903b077aed3SPierre Pronchery if (p != NULL && !OSSL_PARAM_set_size_t(p, drbg->max_adinlen)) 904b077aed3SPierre Pronchery return 0; 905b077aed3SPierre Pronchery 906b077aed3SPierre Pronchery p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_REQUESTS); 907b077aed3SPierre Pronchery if (p != NULL && !OSSL_PARAM_set_uint(p, drbg->reseed_interval)) 908b077aed3SPierre Pronchery return 0; 909b077aed3SPierre Pronchery 910b077aed3SPierre Pronchery p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_TIME); 911b077aed3SPierre Pronchery if (p != NULL && !OSSL_PARAM_set_time_t(p, drbg->reseed_time)) 912b077aed3SPierre Pronchery return 0; 913b077aed3SPierre Pronchery 914b077aed3SPierre Pronchery p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL); 915b077aed3SPierre Pronchery if (p != NULL && !OSSL_PARAM_set_time_t(p, drbg->reseed_time_interval)) 916b077aed3SPierre Pronchery return 0; 917b077aed3SPierre Pronchery 918b077aed3SPierre Pronchery p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_RESEED_COUNTER); 919b077aed3SPierre Pronchery if (p != NULL 920b077aed3SPierre Pronchery && !OSSL_PARAM_set_uint(p, tsan_load(&drbg->reseed_counter))) 921b077aed3SPierre Pronchery return 0; 922b077aed3SPierre Pronchery return 1; 923b077aed3SPierre Pronchery } 924b077aed3SPierre Pronchery 925b077aed3SPierre Pronchery int ossl_drbg_set_ctx_params(PROV_DRBG *drbg, const OSSL_PARAM params[]) 926b077aed3SPierre Pronchery { 927b077aed3SPierre Pronchery const OSSL_PARAM *p; 928b077aed3SPierre Pronchery 929b077aed3SPierre Pronchery if (params == NULL) 930b077aed3SPierre Pronchery return 1; 931b077aed3SPierre Pronchery 932b077aed3SPierre Pronchery p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_RESEED_REQUESTS); 933b077aed3SPierre Pronchery if (p != NULL && !OSSL_PARAM_get_uint(p, &drbg->reseed_interval)) 934b077aed3SPierre Pronchery return 0; 935b077aed3SPierre Pronchery 936b077aed3SPierre Pronchery p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL); 937b077aed3SPierre Pronchery if (p != NULL && !OSSL_PARAM_get_time_t(p, &drbg->reseed_time_interval)) 938b077aed3SPierre Pronchery return 0; 939b077aed3SPierre Pronchery return 1; 940b077aed3SPierre Pronchery } 941