Add functions to see if a provider is available for use.

Public function OSSL_PROVIDER_available() takes a library context and
a provider name, and returns 1 if it's available for use, i.e. if it's
possible to fetch implementations from it, otherwise 0.

Internal function ossl_provider_activated() returns 1 if the given
OSSL_PROVIDER is activated, otherwise 0.

To make this possible, the activation of fallbacks got refactored out
to a separate function, which ended up simplifying the code.

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9398)
This commit is contained in:
Richard Levitte 2019-07-17 11:29:04 +02:00
parent 166c0b98fd
commit 36f5ec55e6
9 changed files with 101 additions and 45 deletions

View File

@ -9,6 +9,11 @@
Changes between 1.1.1 and 3.0.0 [xx XXX xxxx] Changes between 1.1.1 and 3.0.0 [xx XXX xxxx]
*) Introduced a new function, OSSL_PROVIDER_available(), which can be used
to check if a named provider is loaded and available. When called, it
will also activate all fallback providers if such are still present.
[Richard Levitte]
*) Enforce a minimum DH modulus size of 512 bits. *) Enforce a minimum DH modulus size of 512 bits.
[Bernd Edlinger] [Bernd Edlinger]

View File

@ -35,6 +35,18 @@ int OSSL_PROVIDER_unload(OSSL_PROVIDER *prov)
return 1; return 1;
} }
int OSSL_PROVIDER_available(OPENSSL_CTX *libctx, const char *name)
{
OSSL_PROVIDER *prov = NULL;
int available = 0;
/* Find it or create it */
prov = ossl_provider_find(libctx, name);
available = ossl_provider_available(prov);
ossl_provider_free(prov);
return available;
}
const OSSL_PARAM *OSSL_PROVIDER_get_param_types(const OSSL_PROVIDER *prov) const OSSL_PARAM *OSSL_PROVIDER_get_param_types(const OSSL_PROVIDER *prov)
{ {
return ossl_provider_get_param_types(prov); return ossl_provider_get_param_types(prov);

View File

@ -572,67 +572,79 @@ static int provider_forall_loaded(struct provider_store_st *store,
return ret; return ret;
} }
/*
* This function only does something once when store->use_fallbacks == 1,
* and then sets store->use_fallbacks = 0, so the second call and so on is
* effectively a no-op.
*/
static void provider_activate_fallbacks(struct provider_store_st *store)
{
if (store->use_fallbacks) {
int num_provs = sk_OSSL_PROVIDER_num(store->providers);
int activated_fallback_count = 0;
int i;
for (i = 0; i < num_provs; i++) {
OSSL_PROVIDER *prov = sk_OSSL_PROVIDER_value(store->providers, i);
/*
* Note that we don't care if the activation succeeds or not.
* If it doesn't succeed, then any attempt to use any of the
* fallback providers will fail anyway.
*/
if (prov->flag_fallback) {
activated_fallback_count++;
provider_activate(prov);
}
}
/*
* We assume that all fallbacks have been added to the store before
* any fallback is activated.
* TODO: We may have to reconsider this, IF we find ourselves adding
* fallbacks after any previous fallback has been activated.
*/
if (activated_fallback_count > 0)
store->use_fallbacks = 0;
}
}
int ossl_provider_forall_loaded(OPENSSL_CTX *ctx, int ossl_provider_forall_loaded(OPENSSL_CTX *ctx,
int (*cb)(OSSL_PROVIDER *provider, int (*cb)(OSSL_PROVIDER *provider,
void *cbdata), void *cbdata),
void *cbdata) void *cbdata)
{ {
int ret = 1; int ret = 1;
int i;
struct provider_store_st *store = get_provider_store(ctx); struct provider_store_st *store = get_provider_store(ctx);
if (store != NULL) { if (store != NULL) {
int found_activated = 0;
CRYPTO_THREAD_read_lock(store->lock); CRYPTO_THREAD_read_lock(store->lock);
ret = provider_forall_loaded(store, &found_activated, cb, cbdata);
provider_activate_fallbacks(store);
/* /*
* If there's nothing activated ever in this store, try to activate * Now, we sweep through all providers
* all fallbacks.
*/ */
if (!found_activated && store->use_fallbacks) { ret = provider_forall_loaded(store, NULL, cb, cbdata);
int num_provs = sk_OSSL_PROVIDER_num(store->providers);
int activated_fallback_count = 0;
for (i = 0; i < num_provs; i++) {
OSSL_PROVIDER *prov =
sk_OSSL_PROVIDER_value(store->providers, i);
/*
* Note that we don't care if the activation succeeds or
* not. If it doesn't succeed, then the next loop will
* fail anyway.
*/
if (prov->flag_fallback) {
activated_fallback_count++;
provider_activate(prov);
}
}
if (activated_fallback_count > 0) {
/*
* We assume that all fallbacks have been added to the store
* before any fallback is activated.
* TODO: We may have to reconsider this, IF we find ourselves
* adding fallbacks after any previous fallback has been
* activated.
*/
store->use_fallbacks = 0;
/*
* Now that we've activated available fallbacks, try a
* second sweep
*/
ret = provider_forall_loaded(store, NULL, cb, cbdata);
}
}
CRYPTO_THREAD_unlock(store->lock); CRYPTO_THREAD_unlock(store->lock);
} }
return ret; return ret;
} }
int ossl_provider_available(OSSL_PROVIDER *prov)
{
if (prov != NULL) {
CRYPTO_THREAD_read_lock(prov->store->lock);
provider_activate_fallbacks(prov->store);
CRYPTO_THREAD_unlock(prov->store->lock);
return prov->flag_initialized;
}
return 0;
}
/* Setters of Provider Object data */ /* Setters of Provider Object data */
int ossl_provider_set_fallback(OSSL_PROVIDER *prov) int ossl_provider_set_fallback(OSSL_PROVIDER *prov)
{ {

View File

@ -6,7 +6,7 @@ ossl_provider_find, ossl_provider_new, ossl_provider_up_ref,
ossl_provider_free, ossl_provider_free,
ossl_provider_set_fallback, ossl_provider_set_module_path, ossl_provider_set_fallback, ossl_provider_set_module_path,
ossl_provider_add_parameter, ossl_provider_add_parameter,
ossl_provider_activate, ossl_provider_activate, ossl_provider_available,
ossl_provider_ctx, ossl_provider_ctx,
ossl_provider_forall_loaded, ossl_provider_forall_loaded,
ossl_provider_name, ossl_provider_dso, ossl_provider_name, ossl_provider_dso,
@ -33,6 +33,8 @@ ossl_provider_get_params, ossl_provider_query_operation
/* Load and initialize the Provider */ /* Load and initialize the Provider */
int ossl_provider_activate(OSSL_PROVIDER *prov); int ossl_provider_activate(OSSL_PROVIDER *prov);
/* Check if provider is available */
int ossl_provider_available(OSSL_PROVIDER *prov);
/* Return pointer to the provider's context */ /* Return pointer to the provider's context */
void *ossl_provider_ctx(const OSSL_PROVIDER *prov); void *ossl_provider_ctx(const OSSL_PROVIDER *prov);
@ -148,6 +150,10 @@ be located in that module, and called.
=back =back
ossl_provider_available() activates all fallbacks if no provider is
activated yet, then checks if given provider object I<prov> is
activated.
ossl_provider_ctx() returns a context created by the provider. ossl_provider_ctx() returns a context created by the provider.
Outside of the provider, it's completely opaque, but it needs to be Outside of the provider, it's completely opaque, but it needs to be
passed back to some of the provider functions. passed back to some of the provider functions.
@ -228,6 +234,9 @@ ossl_provider_free() doesn't return any value.
ossl_provider_set_module_path(), ossl_provider_set_fallback() and ossl_provider_set_module_path(), ossl_provider_set_fallback() and
ossl_provider_activate() return 1 on success, or 0 on error. ossl_provider_activate() return 1 on success, or 0 on error.
ossl_provider_available() return 1 if the provider is available,
otherwise 0.
ossl_provider_name(), ossl_provider_dso(), ossl_provider_name(), ossl_provider_dso(),
ossl_provider_module_name(), and ossl_provider_module_path() return a ossl_provider_module_name(), and ossl_provider_module_path() return a
pointer to their respective data if it's available, otherwise NULL pointer to their respective data if it's available, otherwise NULL

View File

@ -3,6 +3,7 @@
=head1 NAME =head1 NAME
OSSL_PROVIDER, OSSL_PROVIDER_load, OSSL_PROVIDER_unload, OSSL_PROVIDER, OSSL_PROVIDER_load, OSSL_PROVIDER_unload,
OSSL_PROVIDER_available,
OSSL_PROVIDER_get_param_types, OSSL_PROVIDER_get_params, OSSL_PROVIDER_get_param_types, OSSL_PROVIDER_get_params,
OSSL_PROVIDER_add_builtin, OSSL_PROVIDER_name - provider routines OSSL_PROVIDER_add_builtin, OSSL_PROVIDER_name - provider routines
@ -12,13 +13,14 @@ OSSL_PROVIDER_add_builtin, OSSL_PROVIDER_name - provider routines
typedef struct ossl_provider_st OSSL_PROVIDER; typedef struct ossl_provider_st OSSL_PROVIDER;
OSSL_PROVIDER *OSSL_PROVIDER_load(OPENSSL_CTX *, const char *name); OSSL_PROVIDER *OSSL_PROVIDER_load(OPENSSL_CTX *libctx, const char *name);
int OSSL_PROVIDER_unload(OSSL_PROVIDER *prov); int OSSL_PROVIDER_unload(OSSL_PROVIDER *prov);
int OSSL_PROVIDER_available(OPENSSL_CTX *libctx, const char *name);
const OSSL_PARAM *OSSL_PROVIDER_get_param_types(OSSL_PROVIDER *prov); const OSSL_PARAM *OSSL_PROVIDER_get_param_types(OSSL_PROVIDER *prov);
int OSSL_PROVIDER_get_params(OSSL_PROVIDER *prov, OSSL_PARAM params[]); int OSSL_PROVIDER_get_params(OSSL_PROVIDER *prov, OSSL_PARAM params[]);
int OSSL_PROVIDER_add_builtin(OPENSSL_CTX *, const char *name, int OSSL_PROVIDER_add_builtin(OPENSSL_CTX *libctx, const char *name,
ossl_provider_init_fn *init_fn); ossl_provider_init_fn *init_fn);
const char *OSSL_PROVIDER_name(const OSSL_PROVIDER *prov); const char *OSSL_PROVIDER_name(const OSSL_PROVIDER *prov);
@ -32,6 +34,9 @@ A provider can be built in to the application or the OpenSSL
libraries, or can be a loadable module. libraries, or can be a loadable module.
The functions described here handle both forms. The functions described here handle both forms.
Some of these functions operate within a library context, please see
L<OPENSSL_CTX(3)> for further details.
=head2 Functions =head2 Functions
OSSL_PROVIDER_add_builtin() is used to add a built in provider to OSSL_PROVIDER_add_builtin() is used to add a built in provider to
@ -49,6 +54,9 @@ OSSL_PROVIDER_unload() unloads the given provider.
For a provider added with OSSL_PROVIDER_add_builtin(), this simply For a provider added with OSSL_PROVIDER_add_builtin(), this simply
runs its teardown function. runs its teardown function.
OSSL_PROVIDER_available() checks if a named provider is available
for use.
OSSL_PROVIDER_get_param_types() is used to get a provider parameter OSSL_PROVIDER_get_param_types() is used to get a provider parameter
descriptor set as a constant B<OSSL_PARAM> array. descriptor set as a constant B<OSSL_PARAM> array.
See L<OSSL_PARAM(3)> for more information. See L<OSSL_PARAM(3)> for more information.
@ -69,6 +77,9 @@ success, or B<NULL> on error.
OSSL_PROVIDER_unload() returns 1 on success, or 0 on error. OSSL_PROVIDER_unload() returns 1 on success, or 0 on error.
OSSL_PROVIDER_available() returns 1 if the named provider is available,
otherwise 0.
OSSL_PROVIDER_get_param_types() returns a pointer to an array OSSL_PROVIDER_get_param_types() returns a pointer to an array
of constant B<OSSL_PARAM>, or NULL if none is provided. of constant B<OSSL_PARAM>, or NULL if none is provided.
@ -95,7 +106,7 @@ its build number.
=head1 SEE ALSO =head1 SEE ALSO
L<openssl-core.h(7)>, L<provider(7)> L<openssl-core.h(7)>, L<OPENSSL_CTX(3)>, L<provider(7)>
=head1 HISTORY =head1 HISTORY

View File

@ -44,6 +44,8 @@ int ossl_provider_add_parameter(OSSL_PROVIDER *prov, const char *name,
* Inactivation is done by freeing the Provider * Inactivation is done by freeing the Provider
*/ */
int ossl_provider_activate(OSSL_PROVIDER *prov); int ossl_provider_activate(OSSL_PROVIDER *prov);
/* Check if the provider is available */
int ossl_provider_available(OSSL_PROVIDER *prov);
/* Return pointer to the provider's context */ /* Return pointer to the provider's context */
void *ossl_provider_ctx(const OSSL_PROVIDER *prov); void *ossl_provider_ctx(const OSSL_PROVIDER *prov);

View File

@ -14,6 +14,9 @@
# if defined(OPENSSL_SYS_VMS) # if defined(OPENSSL_SYS_VMS)
/* ossl_provider_available vs OSSL_PROVIDER_available */
# undef ossl_provider_available
# define ossl_provider_available ossl_int_prov_available
/* ossl_provider_get_param_types vs OSSL_PROVIDER_get_param_types */ /* ossl_provider_get_param_types vs OSSL_PROVIDER_get_param_types */
# undef ossl_provider_get_param_types # undef ossl_provider_get_param_types
# define ossl_provider_get_param_types ossl_int_prov_get_param_types # define ossl_provider_get_param_types ossl_int_prov_get_param_types

View File

@ -19,6 +19,7 @@ extern "C" {
/* Load and unload a provider */ /* Load and unload a provider */
OSSL_PROVIDER *OSSL_PROVIDER_load(OPENSSL_CTX *, const char *name); OSSL_PROVIDER *OSSL_PROVIDER_load(OPENSSL_CTX *, const char *name);
int OSSL_PROVIDER_unload(OSSL_PROVIDER *prov); int OSSL_PROVIDER_unload(OSSL_PROVIDER *prov);
int OSSL_PROVIDER_available(OPENSSL_CTX *, const char *name);
const OSSL_PARAM *OSSL_PROVIDER_get_param_types(const OSSL_PROVIDER *prov); const OSSL_PARAM *OSSL_PROVIDER_get_param_types(const OSSL_PROVIDER *prov);
int OSSL_PROVIDER_get_params(const OSSL_PROVIDER *prov, OSSL_PARAM params[]); int OSSL_PROVIDER_get_params(const OSSL_PROVIDER *prov, OSSL_PARAM params[]);

View File

@ -4699,3 +4699,4 @@ OSSL_PROVIDER_name 4804 3_0_0 EXIST::FUNCTION:
EVP_CIPHER_do_all_ex 4805 3_0_0 EXIST::FUNCTION: EVP_CIPHER_do_all_ex 4805 3_0_0 EXIST::FUNCTION:
EVP_MD_do_all_ex 4806 3_0_0 EXIST::FUNCTION: EVP_MD_do_all_ex 4806 3_0_0 EXIST::FUNCTION:
EVP_KEYEXCH_provider 4807 3_0_0 EXIST::FUNCTION: EVP_KEYEXCH_provider 4807 3_0_0 EXIST::FUNCTION:
OSSL_PROVIDER_available 4808 3_0_0 EXIST::FUNCTION: