From: Pauli Date: Thu, 23 May 2024 02:14:47 +0000 (+1000) Subject: Add support for random provider X-Git-Tag: openssl-3.5.0-alpha1~662 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b1cca2599938df2cec608d138851801565a81e78;p=thirdparty%2Fopenssl.git Add support for random provider Reviewed-by: Tim Hudson Reviewed-by: Shane Lontis (Merged from https://github.com/openssl/openssl/pull/24498) --- diff --git a/crypto/provider_core.c b/crypto/provider_core.c index e1025f2ee18..7e0fe851fa6 100644 --- a/crypto/provider_core.c +++ b/crypto/provider_core.c @@ -175,7 +175,7 @@ struct ossl_provider_st { OSSL_FUNC_provider_get_params_fn *get_params; OSSL_FUNC_provider_get_capabilities_fn *get_capabilities; OSSL_FUNC_provider_self_test_fn *self_test; - OSSL_FUNC_provider_random_fn *random; + OSSL_FUNC_provider_random_bytes_fn *random_bytes; OSSL_FUNC_provider_query_operation_fn *query_operation; OSSL_FUNC_provider_unquery_operation_fn *unquery_operation; @@ -1068,8 +1068,9 @@ static int provider_init(OSSL_PROVIDER *prov) prov->self_test = OSSL_FUNC_provider_self_test(provider_dispatch); break; - case OSSL_FUNC_PROVIDER_RANDOM: - prov->random = OSSL_FUNC_provider_random(provider_dispatch); + case OSSL_FUNC_PROVIDER_RANDOM_BYTES: + prov->random_bytes = + OSSL_FUNC_provider_random_bytes(provider_dispatch); break; case OSSL_FUNC_PROVIDER_GET_CAPABILITIES: prov->get_capabilities = @@ -1168,6 +1169,12 @@ static int provider_deactivate(OSSL_PROVIDER *prov, int upcalls, if (!ossl_assert(prov != NULL)) return -1; +#ifndef FIPS_MODULE + if (prov->random_bytes != NULL + && !ossl_rand_check_random_provider_on_unload(prov->libctx, prov)) + return -1; +#endif + /* * No need to lock if we've got no store because we've not been shared with * other threads. @@ -1264,6 +1271,10 @@ static int provider_activate(OSSL_PROVIDER *prov, int lock, int upcalls) } #ifndef FIPS_MODULE + if (prov->random_bytes != NULL + && !ossl_rand_check_random_provider_on_load(prov->libctx, prov)) + return -1; + if (prov->ischild && upcalls && !ossl_provider_up_ref_parent(prov, 1)) return -1; #endif @@ -1864,11 +1875,12 @@ int ossl_provider_self_test(const OSSL_PROVIDER *prov) * If tracing is enabled, a message is printed indicating the requested * capabilities. */ -int ossl_provider_random(const OSSL_PROVIDER *prov, int which, void *buf, size_t n, - unsigned int strength) +int ossl_provider_random_bytes(const OSSL_PROVIDER *prov, int which, + void *buf, size_t n, unsigned int strength) { - return prov->random == NULL ? 0 : prov->random(prov->provctx, which, buf, n, - strength); + return prov->random_bytes == NULL ? 0 + : prov->random_bytes(prov->provctx, which, + buf, n, strength); } int ossl_provider_get_capabilities(const OSSL_PROVIDER *prov, diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c index eb983a60676..ce7dfb12c80 100644 --- a/crypto/rand/rand_lib.c +++ b/crypto/rand/rand_lib.c @@ -22,7 +22,6 @@ #include "rand_local.h" #include "crypto/context.h" - #ifndef OPENSSL_DEFAULT_SEED_SRC # define OPENSSL_DEFAULT_SEED_SRC SEED-SRC #endif @@ -58,6 +57,7 @@ typedef struct rand_global_st { */ #ifndef FIPS_MODULE OSSL_PROVIDER *random_provider; + char *random_provider_name; #endif /* !FIPS_MODULE */ /* @@ -91,6 +91,7 @@ typedef struct rand_global_st { char *seed_propq; } RAND_GLOBAL; +static EVP_RAND_CTX *rand_get0_primary(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl); static EVP_RAND_CTX *rand_get0_public(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl); static EVP_RAND_CTX *rand_get0_private(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl); @@ -111,6 +112,24 @@ static RAND_GLOBAL *rand_get_global(OSSL_LIB_CTX *libctx) # include "internal/e_os.h" # include "internal/property.h" +/* + * The default name for the random provider. + * This ensures that the FIPS provider will supply libcrypto's random byte + * requirements. + */ +static const char random_provider_fips_name[] = "fips"; + +static int set_random_provider_name(RAND_GLOBAL *dgbl, const char *name) +{ + if (dgbl->random_provider_name != NULL + && OPENSSL_strcasecmp(dgbl->random_provider_name, name) == 0) + return 1; + + OPENSSL_free(dgbl->random_provider_name); + dgbl->random_provider_name = strdup(name); + return dgbl->random_provider_name != NULL; +} + # ifndef OPENSSL_NO_ENGINE /* non-NULL if default_RAND_meth is ENGINE-provided */ static ENGINE *funct_ref; @@ -431,9 +450,9 @@ int RAND_priv_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num, return 0; #ifndef FIPS_MODULE if (dgbl->random_provider != NULL) - return ossl_provider_random(dgbl->random_provider, - OSSL_PROV_RANDOM_PRIVATE, - buf, num, strength); + return ossl_provider_random_bytes(dgbl->random_provider, + OSSL_PROV_RANDOM_PRIVATE, + buf, num, strength); #endif /* !FIPS_MODULE */ rand = rand_get0_private(ctx, dgbl); if (rand != NULL) @@ -470,9 +489,9 @@ int RAND_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num, return 0; #ifndef FIPS_MODULE if (dgbl->random_provider != NULL) - return ossl_provider_random(dgbl->random_provider, - OSSL_PROV_RANDOM_PRIVATE, - buf, num, strength); + return ossl_provider_random_bytes(dgbl->random_provider, + OSSL_PROV_RANDOM_PUBLIC, + buf, num, strength); #endif /* !FIPS_MODULE */ rand = rand_get0_public(ctx, dgbl); @@ -505,7 +524,12 @@ void *ossl_rand_ctx_new(OSSL_LIB_CTX *libctx) * We need to ensure that base libcrypto thread handling has been * initialised. */ - OPENSSL_init_crypto(OPENSSL_INIT_BASE_ONLY, NULL); + OPENSSL_init_crypto(OPENSSL_INIT_BASE_ONLY, NULL); + + /* Prepopulate the random provider name */ + dgbl->random_provider_name = strdup(random_provider_fips_name); + if (dgbl->random_provider_name == NULL) + goto err0; #endif dgbl->lock = CRYPTO_THREAD_lock_new(); @@ -524,6 +548,10 @@ void *ossl_rand_ctx_new(OSSL_LIB_CTX *libctx) CRYPTO_THREAD_cleanup_local(&dgbl->private); err1: CRYPTO_THREAD_lock_free(dgbl->lock); +#ifndef FIPS_MODULE + err0: + OPENSSL_free(dgbl->random_provider_name); +#endif OPENSSL_free(dgbl); return NULL; } @@ -541,7 +569,7 @@ void ossl_rand_ctx_free(void *vdgbl) EVP_RAND_CTX_free(dgbl->primary); EVP_RAND_CTX_free(dgbl->seed); #ifndef FIPS_MODULE - OSSL_PROVIDER_unload(dgbl->random_provider); + OPENSSL_free(dgbl->random_provider_name); #endif /* !FIPS_MODULE */ OPENSSL_free(dgbl->rng_name); OPENSSL_free(dgbl->rng_cipher); @@ -778,9 +806,8 @@ static EVP_RAND_CTX *rand_new_crngt(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent) * Returns pointer to its EVP_RAND_CTX on success, NULL on failure. * */ -EVP_RAND_CTX *RAND_get0_primary(OSSL_LIB_CTX *ctx) +static EVP_RAND_CTX *rand_get0_primary(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl) { - RAND_GLOBAL *dgbl = rand_get_global(ctx); EVP_RAND_CTX *ret; if (dgbl == NULL) @@ -836,6 +863,18 @@ EVP_RAND_CTX *RAND_get0_primary(OSSL_LIB_CTX *ctx) return ret; } +/* + * Get the primary random generator. + * Returns pointer to its EVP_RAND_CTX on success, NULL on failure. + * + */ +EVP_RAND_CTX *RAND_get0_primary(OSSL_LIB_CTX *ctx) +{ + RAND_GLOBAL *dgbl = rand_get_global(ctx); + + return dgbl == NULL ? NULL : rand_get0_primary(ctx, dgbl); +} + static EVP_RAND_CTX *rand_get0_public(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl) { EVP_RAND_CTX *rand, *primary; @@ -845,7 +884,7 @@ static EVP_RAND_CTX *rand_get0_public(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl) rand = CRYPTO_THREAD_get_local(&dgbl->public); if (rand == NULL) { - primary = RAND_get0_primary(ctx); + primary = rand_get0_primary(ctx, dgbl); if (primary == NULL) return NULL; @@ -884,7 +923,7 @@ static EVP_RAND_CTX *rand_get0_private(OSSL_LIB_CTX *ctx, RAND_GLOBAL *dgbl) rand = CRYPTO_THREAD_get_local(&dgbl->private); if (rand == NULL) { - primary = RAND_get0_primary(ctx); + primary = rand_get0_primary(ctx, dgbl); if (primary == NULL) return NULL; @@ -979,7 +1018,8 @@ static int random_conf_init(CONF_IMODULE *md, const CONF *cnf) { STACK_OF(CONF_VALUE) *elist; CONF_VALUE *cval; - RAND_GLOBAL *dgbl = rand_get_global(NCONF_get0_libctx((CONF *)cnf)); + OSSL_LIB_CTX *libctx = NCONF_get0_libctx((CONF *)cnf); + RAND_GLOBAL *dgbl = rand_get_global(libctx); int i, r = 1; OSSL_TRACE1(CONF, "Loading random module: section %s\n", @@ -1015,6 +1055,31 @@ static int random_conf_init(CONF_IMODULE *md, const CONF *cnf) } else if (OPENSSL_strcasecmp(cval->name, "seed_properties") == 0) { if (!random_set_string(&dgbl->seed_propq, cval->value)) return 0; + } else if (OPENSSL_strcasecmp(cval->name, "random_provider") == 0) { +# ifndef FIPS_MODULE + OSSL_PROVIDER *prov = ossl_provider_find(libctx, cval->value, 0); + + if (prov != NULL) { + if (!RAND_set1_random_provider(libctx, prov)) { + ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); + OSSL_PROVIDER_unload(prov); + return 0; + } + /* + * We need to release the reference from ossl_provider_find because + * we don't want to keep a reference counted handle to the provider. + * + * The provider unload code checks for the random provider and, + * if present, our reference will be NULLed when it is fully freed. + * The provider load code, conversely, checks the provider name + * and re-hooks our reference if required. This means that a load, + * hook random provider, use, unload, reload, reuse sequence will + * work as expected. + */ + OSSL_PROVIDER_unload(prov); + } else if (!set_random_provider_name(dgbl, cval->value)) + return 0; +# endif } else { ERR_raise_data(ERR_LIB_CRYPTO, CRYPTO_R_UNKNOWN_NAME_IN_RANDOM_SECTION, @@ -1069,16 +1134,69 @@ int RAND_set_seed_source_type(OSSL_LIB_CTX *ctx, const char *seed, && random_set_string(&dgbl->seed_propq, propq); } -int RAND_set0_random_provider(OSSL_LIB_CTX *ctx, OSSL_PROVIDER *p) +int RAND_set1_random_provider(OSSL_LIB_CTX *ctx, OSSL_PROVIDER *prov) { RAND_GLOBAL *dgbl = rand_get_global(ctx); - OSSL_PROVIDER *old; if (dgbl == NULL) return 0; - old = dgbl->random_provider; - dgbl->random_provider = p; - OSSL_PROVIDER_unload(old); + + if (prov == NULL) { + OPENSSL_free(dgbl->random_provider_name); + dgbl->random_provider_name = NULL; + dgbl->random_provider = NULL; + return 1; + } + + if (dgbl->random_provider == prov) + return 1; + + if (!set_random_provider_name(dgbl, OSSL_PROVIDER_get0_name(prov))) + return 0; + + dgbl->random_provider = prov; return 1; } + +/* + * When a new provider is loaded, we need to check to see if it is the + * designated randomness provider and register it if it is. + */ +int ossl_rand_check_random_provider_on_load(OSSL_LIB_CTX *ctx, + OSSL_PROVIDER *prov) +{ + RAND_GLOBAL *dgbl = rand_get_global(ctx); + + if (dgbl == NULL) + return 0; + + /* No random provider name specified, or one is installed already */ + if (dgbl->random_provider_name == NULL || dgbl->random_provider != NULL) + return 1; + + /* Does this provider match the name we're using? */ + if (strcmp(dgbl->random_provider_name, OSSL_PROVIDER_get0_name(prov)) != 0) + return 1; + + dgbl->random_provider = prov; + return 1; +} + +/* + * When a provider is being unloaded, if it is the randomness provider, + * we need to deregister it. + */ +int ossl_rand_check_random_provider_on_unload(OSSL_LIB_CTX *ctx, + OSSL_PROVIDER *prov) +{ + RAND_GLOBAL *dgbl = rand_get_global(ctx); + + if (dgbl == NULL) + return 0; + + if (dgbl->random_provider == prov) + dgbl->random_provider = NULL; + return 1; +} + #endif /* !FIPS_MODULE */ diff --git a/include/crypto/rand.h b/include/crypto/rand.h index d375c2f933c..b7b5ae35641 100644 --- a/include/crypto/rand.h +++ b/include/crypto/rand.h @@ -151,4 +151,15 @@ uint32_t ossl_rand_uniform_uint32(OSSL_LIB_CTX *ctx, uint32_t upper, int *err); uint32_t ossl_rand_range_uint32(OSSL_LIB_CTX *ctx, uint32_t lower, uint32_t upper, int *err); +/* + * Check if the named provider is the nominated entropy/random provider. + * If it is, use it. + */ +# ifndef FIPS_MODULE +int ossl_rand_check_random_provider_on_load(OSSL_LIB_CTX *ctx, + OSSL_PROVIDER *prov); +int ossl_rand_check_random_provider_on_unload(OSSL_LIB_CTX *ctx, + OSSL_PROVIDER *prov); +# endif /* FIPS_MODULE */ + #endif diff --git a/include/internal/provider.h b/include/internal/provider.h index eb8f1fbdb9f..3df3c609396 100644 --- a/include/internal/provider.h +++ b/include/internal/provider.h @@ -84,8 +84,8 @@ int ossl_provider_get_capabilities(const OSSL_PROVIDER *prov, OSSL_CALLBACK *cb, void *arg); int ossl_provider_self_test(const OSSL_PROVIDER *prov); -int ossl_provider_random(const OSSL_PROVIDER *prov, int which, void *buf, size_t n, - unsigned int strength); +int ossl_provider_random_bytes(const OSSL_PROVIDER *prov, int which, + void *buf, size_t n, unsigned int strength); const OSSL_ALGORITHM *ossl_provider_query_operation(const OSSL_PROVIDER *prov, int operation_id, int *no_cache); diff --git a/include/openssl/core_dispatch.h b/include/openssl/core_dispatch.h index 315baffa55e..2be592d9362 100644 --- a/include/openssl/core_dispatch.h +++ b/include/openssl/core_dispatch.h @@ -269,10 +269,10 @@ OSSL_CORE_MAKE_FUNC(int, provider_get_capabilities, (void *provctx, const char *capability, OSSL_CALLBACK *cb, void *arg)) # define OSSL_FUNC_PROVIDER_SELF_TEST 1031 OSSL_CORE_MAKE_FUNC(int, provider_self_test, (void *provctx)) -# define OSSL_FUNC_PROVIDER_RANDOM 1032 -OSSL_CORE_MAKE_FUNC(int, provider_random, (void *provctx, int which, - void *buf, size_t n, - unsigned int strength)) +# define OSSL_FUNC_PROVIDER_RANDOM_BYTES 1032 +OSSL_CORE_MAKE_FUNC(int, provider_random_bytes, (void *provctx, int which, + void *buf, size_t n, + unsigned int strength)) /* Operations */ diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index 568d9a6f957..d939db92c25 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -41,7 +41,7 @@ static OSSL_FUNC_provider_gettable_params_fn fips_gettable_params; static OSSL_FUNC_provider_get_params_fn fips_get_params; static OSSL_FUNC_provider_query_operation_fn fips_query; static OSSL_FUNC_provider_query_operation_fn fips_query_internal; -static OSSL_FUNC_provider_random_fn fips_random; +static OSSL_FUNC_provider_random_bytes_fn fips_random_bytes; #define ALGC(NAMES, FUNC, CHECK) \ { { NAMES, FIPS_DEFAULT_PROPERTIES, FUNC }, CHECK } @@ -122,8 +122,8 @@ void ossl_fips_prov_ossl_ctx_free(void *fgbl) OPENSSL_free(fgbl); } -static int fips_random(ossl_unused void *vprov, int which, void *buf, size_t n, - unsigned int strength) +static int fips_random_bytes(ossl_unused void *vprov, int which, + void *buf, size_t n, unsigned int strength) { OSSL_LIB_CTX *libctx; PROV_CTX *prov = (PROV_CTX *)vprov; @@ -619,7 +619,7 @@ static const OSSL_DISPATCH fips_dispatch_table[] = { { OSSL_FUNC_PROVIDER_GET_CAPABILITIES, (void (*)(void))ossl_prov_get_capabilities }, { OSSL_FUNC_PROVIDER_SELF_TEST, (void (*)(void))fips_self_test }, - { OSSL_FUNC_PROVIDER_RANDOM, (void (*)(void))fips_random }, + { OSSL_FUNC_PROVIDER_RANDOM_BYTES, (void (*)(void))fips_random_bytes }, OSSL_DISPATCH_END };