Add support for random provider

Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/24498)
This commit is contained in:
Pauli 2024-05-23 12:14:47 +10:00
parent 5b5c24d99e
commit b1cca25999
6 changed files with 177 additions and 36 deletions

View File

@ -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,

View File

@ -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 */

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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
};