Latest update
This commit is contained in:
+175
-37
@@ -11,9 +11,14 @@
|
||||
#include <openssl/core_numbers.h>
|
||||
#include <openssl/opensslv.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/nelem.h"
|
||||
#include "internal/thread_once.h"
|
||||
#include "internal/provider.h"
|
||||
#include "internal/refcount.h"
|
||||
#include "provider_local.h"
|
||||
|
||||
static OSSL_PROVIDER *provider_new(const char *name,
|
||||
OSSL_provider_init_fn *init_function);
|
||||
|
||||
/*-
|
||||
* Provider Object structure
|
||||
@@ -25,6 +30,7 @@ struct provider_store_st; /* Forward declaration */
|
||||
struct ossl_provider_st {
|
||||
/* Flag bits */
|
||||
unsigned int flag_initialized:1;
|
||||
unsigned int flag_fallback:1;
|
||||
|
||||
/* OpenSSL library side data */
|
||||
CRYPTO_REF_COUNT refcnt;
|
||||
@@ -32,6 +38,7 @@ struct ossl_provider_st {
|
||||
char *name;
|
||||
DSO *module;
|
||||
OSSL_provider_init_fn *init_function;
|
||||
struct provider_store_st *store; /* The store this instance belongs to */
|
||||
|
||||
/* Provider side functions */
|
||||
OSSL_provider_teardown_fn *teardown;
|
||||
@@ -58,6 +65,7 @@ static int ossl_provider_cmp(const OSSL_PROVIDER * const *a,
|
||||
struct provider_store_st {
|
||||
STACK_OF(OSSL_PROVIDER) *providers;
|
||||
CRYPTO_RWLOCK *lock;
|
||||
unsigned int use_fallbacks:1;
|
||||
};
|
||||
static int provider_store_index = -1;
|
||||
|
||||
@@ -75,13 +83,37 @@ static void provider_store_free(void *vstore)
|
||||
static void *provider_store_new(void)
|
||||
{
|
||||
struct provider_store_st *store = OPENSSL_zalloc(sizeof(*store));
|
||||
const struct predefined_providers_st *p = NULL;
|
||||
|
||||
if (store == NULL
|
||||
|| (store->providers = sk_OSSL_PROVIDER_new(ossl_provider_cmp)) == NULL
|
||||
|| (store->lock = CRYPTO_THREAD_lock_new()) == NULL) {
|
||||
provider_store_free(store);
|
||||
store = NULL;
|
||||
return NULL;
|
||||
}
|
||||
store->use_fallbacks = 1;
|
||||
|
||||
for (p = predefined_providers; p->name != NULL; p++) {
|
||||
OSSL_PROVIDER *prov = NULL;
|
||||
|
||||
/*
|
||||
* We use the internal constructor directly here,
|
||||
* otherwise we get a call loop
|
||||
*/
|
||||
prov = provider_new(p->name, p->init);
|
||||
|
||||
if (prov == NULL
|
||||
|| sk_OSSL_PROVIDER_push(store->providers, prov) == 0) {
|
||||
ossl_provider_free(prov);
|
||||
provider_store_free(store);
|
||||
CRYPTOerr(CRYPTO_F_PROVIDER_STORE_NEW, ERR_R_INTERNAL_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
prov->store = store;
|
||||
if(p->is_fallback)
|
||||
ossl_provider_set_fallback(prov);
|
||||
}
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
@@ -112,20 +144,6 @@ static struct provider_store_st *get_provider_store(OPENSSL_CTX *libctx)
|
||||
return store;
|
||||
}
|
||||
|
||||
/*-
|
||||
* Provider Object methods
|
||||
* =======================
|
||||
*/
|
||||
|
||||
int ossl_provider_upref(OSSL_PROVIDER *prov)
|
||||
{
|
||||
int ref = 0;
|
||||
|
||||
CRYPTO_UP_REF(&prov->refcnt, &ref, prov->refcnt_lock);
|
||||
return ref;
|
||||
}
|
||||
|
||||
/* Finder, constructor and destructor */
|
||||
OSSL_PROVIDER *ossl_provider_find(OPENSSL_CTX *libctx, const char *name)
|
||||
{
|
||||
struct provider_store_st *store = NULL;
|
||||
@@ -147,6 +165,39 @@ OSSL_PROVIDER *ossl_provider_find(OPENSSL_CTX *libctx, const char *name)
|
||||
return prov;
|
||||
}
|
||||
|
||||
/*-
|
||||
* Provider Object methods
|
||||
* =======================
|
||||
*/
|
||||
|
||||
static OSSL_PROVIDER *provider_new(const char *name,
|
||||
OSSL_provider_init_fn *init_function)
|
||||
{
|
||||
OSSL_PROVIDER *prov = NULL;
|
||||
|
||||
if ((prov = OPENSSL_zalloc(sizeof(*prov))) == NULL
|
||||
#ifndef HAVE_ATOMICS
|
||||
|| (prov->refcnt_lock = CRYPTO_THREAD_lock_new()) == NULL
|
||||
#endif
|
||||
|| !ossl_provider_upref(prov) /* +1 One reference to be returned */
|
||||
|| (prov->name = OPENSSL_strdup(name)) == NULL) {
|
||||
ossl_provider_free(prov);
|
||||
CRYPTOerr(CRYPTO_F_PROVIDER_NEW, ERR_R_MALLOC_FAILURE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
prov->init_function = init_function;
|
||||
return prov;
|
||||
}
|
||||
|
||||
int ossl_provider_upref(OSSL_PROVIDER *prov)
|
||||
{
|
||||
int ref = 0;
|
||||
|
||||
CRYPTO_UP_REF(&prov->refcnt, &ref, prov->refcnt_lock);
|
||||
return ref;
|
||||
}
|
||||
|
||||
OSSL_PROVIDER *ossl_provider_new(OPENSSL_CTX *libctx, const char *name,
|
||||
OSSL_provider_init_fn *init_function)
|
||||
{
|
||||
@@ -164,18 +215,9 @@ OSSL_PROVIDER *ossl_provider_new(OPENSSL_CTX *libctx, const char *name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((prov = OPENSSL_zalloc(sizeof(*prov))) == NULL
|
||||
#ifndef HAVE_ATOMICS
|
||||
|| (prov->refcnt_lock = CRYPTO_THREAD_lock_new()) == NULL
|
||||
#endif
|
||||
|| !ossl_provider_upref(prov) /* +1 One reference to be returned */
|
||||
|| (prov->name = OPENSSL_strdup(name)) == NULL) {
|
||||
ossl_provider_free(prov);
|
||||
CRYPTOerr(CRYPTO_F_OSSL_PROVIDER_NEW, ERR_R_MALLOC_FAILURE);
|
||||
/* provider_new() generates an error, so no need here */
|
||||
if ((prov = provider_new(name, init_function)) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
prov->init_function = init_function;
|
||||
|
||||
CRYPTO_THREAD_write_lock(store->lock);
|
||||
if (!ossl_provider_upref(prov)) { /* +1 One reference for the store */
|
||||
@@ -185,6 +227,8 @@ OSSL_PROVIDER *ossl_provider_new(OPENSSL_CTX *libctx, const char *name,
|
||||
ossl_provider_free(prov); /* -1 Store reference */
|
||||
ossl_provider_free(prov); /* -1 Reference that was to be returned */
|
||||
prov = NULL;
|
||||
} else {
|
||||
prov->store = store;
|
||||
}
|
||||
CRYPTO_THREAD_unlock(store->lock);
|
||||
|
||||
@@ -207,11 +251,13 @@ void ossl_provider_free(OSSL_PROVIDER *prov)
|
||||
CRYPTO_DOWN_REF(&prov->refcnt, &ref, prov->refcnt_lock);
|
||||
|
||||
/*
|
||||
* When the refcount drops down to one, there is only one reference,
|
||||
* the store.
|
||||
* When the refcount drops below two, the store is the only
|
||||
* possible reference, or it has already been taken away from
|
||||
* the store (this may happen if a provider was activated
|
||||
* because it's a fallback, but isn't currently used)
|
||||
* When that happens, the provider is inactivated.
|
||||
*/
|
||||
if (ref == 1 && prov->flag_initialized) {
|
||||
if (ref < 2 && prov->flag_initialized) {
|
||||
if (prov->teardown != NULL)
|
||||
prov->teardown();
|
||||
prov->flag_initialized = 0;
|
||||
@@ -246,7 +292,12 @@ void ossl_provider_free(OSSL_PROVIDER *prov)
|
||||
*/
|
||||
static const OSSL_DISPATCH *core_dispatch; /* Define further down */
|
||||
|
||||
int ossl_provider_activate(OSSL_PROVIDER *prov)
|
||||
/*
|
||||
* Internal version that doesn't affect the store flags, and thereby avoid
|
||||
* locking. Direct callers must remember to set the store flags when
|
||||
* appropriate
|
||||
*/
|
||||
static int provider_activate(OSSL_PROVIDER *prov)
|
||||
{
|
||||
const OSSL_DISPATCH *provider_dispatch = NULL;
|
||||
|
||||
@@ -295,7 +346,7 @@ int ossl_provider_activate(OSSL_PROVIDER *prov)
|
||||
|
||||
if (prov->init_function == NULL
|
||||
|| !prov->init_function(prov, core_dispatch, &provider_dispatch)) {
|
||||
CRYPTOerr(CRYPTO_F_OSSL_PROVIDER_ACTIVATE, ERR_R_INIT_FAIL);
|
||||
CRYPTOerr(CRYPTO_F_PROVIDER_ACTIVATE, ERR_R_INIT_FAIL);
|
||||
ERR_add_error_data(2, "name=", prov->name);
|
||||
DSO_free(prov->module);
|
||||
prov->module = NULL;
|
||||
@@ -329,6 +380,46 @@ int ossl_provider_activate(OSSL_PROVIDER *prov)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_provider_activate(OSSL_PROVIDER *prov)
|
||||
{
|
||||
if (provider_activate(prov)) {
|
||||
CRYPTO_THREAD_write_lock(prov->store->lock);
|
||||
prov->store->use_fallbacks = 0;
|
||||
CRYPTO_THREAD_unlock(prov->store->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int provider_forall_loaded(struct provider_store_st *store,
|
||||
int *found_activated,
|
||||
int (*cb)(OSSL_PROVIDER *provider,
|
||||
void *cbdata),
|
||||
void *cbdata)
|
||||
{
|
||||
int i;
|
||||
int ret = 1;
|
||||
int num_provs = sk_OSSL_PROVIDER_num(store->providers);
|
||||
|
||||
if (found_activated != NULL)
|
||||
*found_activated = 0;
|
||||
for (i = 0; i < num_provs; i++) {
|
||||
OSSL_PROVIDER *prov =
|
||||
sk_OSSL_PROVIDER_value(store->providers, i);
|
||||
|
||||
if (prov->flag_initialized) {
|
||||
if (found_activated != NULL)
|
||||
*found_activated = 1;
|
||||
if (!(ret = cb(prov, cbdata)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ossl_provider_forall_loaded(OPENSSL_CTX *ctx,
|
||||
int (*cb)(OSSL_PROVIDER *provider,
|
||||
void *cbdata),
|
||||
@@ -339,13 +430,50 @@ int ossl_provider_forall_loaded(OPENSSL_CTX *ctx,
|
||||
struct provider_store_st *store = get_provider_store(ctx);
|
||||
|
||||
if (store != NULL) {
|
||||
CRYPTO_THREAD_read_lock(store->lock);
|
||||
for (i = 0; i < sk_OSSL_PROVIDER_num(store->providers); i++) {
|
||||
OSSL_PROVIDER *prov = sk_OSSL_PROVIDER_value(store->providers, i);
|
||||
int found_activated = 0;
|
||||
|
||||
if (prov->flag_initialized
|
||||
&& !(ret = cb(prov, cbdata)))
|
||||
break;
|
||||
CRYPTO_THREAD_read_lock(store->lock);
|
||||
ret = provider_forall_loaded(store, &found_activated, cb, cbdata);
|
||||
|
||||
/*
|
||||
* If there's nothing activated ever in this store, try to activate
|
||||
* all fallbacks.
|
||||
*/
|
||||
if (!found_activated && store->use_fallbacks) {
|
||||
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);
|
||||
}
|
||||
@@ -353,6 +481,16 @@ int ossl_provider_forall_loaded(OPENSSL_CTX *ctx,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Setters of Provider Object data */
|
||||
int ossl_provider_set_fallback(OSSL_PROVIDER *prov)
|
||||
{
|
||||
if (prov == NULL)
|
||||
return 0;
|
||||
|
||||
prov->flag_fallback = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Getters of Provider Object data */
|
||||
const char *ossl_provider_name(OSSL_PROVIDER *prov)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user