summaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorRichard Levitte <levitte@openssl.org>2019-03-14 10:53:27 +0100
committerRichard Levitte <levitte@openssl.org>2019-03-19 14:06:58 +0100
commite55008a9f2ae299374dcf868b660389e84dd2e0b (patch)
tree972ecb9fbe04f18923a4885947c27c907c824e41 /crypto
parent6a6d9ecd1dff669c162e8ab940dac5db2e82679d (diff)
Replumbing: add fallback provider capability
To ensure that old applications aren't left without any provider, and at the same time not forcing any default provider on applications that know how to deal with them, we device the concept of fallback providers, which are automatically activated if no other provider is already activated. Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/8480)
Diffstat (limited to 'crypto')
-rw-r--r--crypto/cpt_err.c2
-rw-r--r--crypto/err/openssl.txt1
-rw-r--r--crypto/provider_core.c122
3 files changed, 114 insertions, 11 deletions
diff --git a/crypto/cpt_err.c b/crypto/cpt_err.c
index bf7985cee9..88bee489f2 100644
--- a/crypto/cpt_err.c
+++ b/crypto/cpt_err.c
@@ -57,6 +57,8 @@ static const ERR_STRING_DATA CRYPTO_str_functs[] = {
"pkey_poly1305_init"},
{ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_PKEY_SIPHASH_INIT, 0),
"pkey_siphash_init"},
+ {ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_PROVIDER_ACTIVATE, 0),
+ "provider_activate"},
{ERR_PACK(ERR_LIB_CRYPTO, CRYPTO_F_SK_RESERVE, 0), "sk_reserve"},
{0, NULL}
};
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 4853a05331..9f84dbc99f 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -396,6 +396,7 @@ CRYPTO_F_OSSL_PROVIDER_NEW:131:ossl_provider_new
CRYPTO_F_PKEY_HMAC_INIT:123:pkey_hmac_init
CRYPTO_F_PKEY_POLY1305_INIT:124:pkey_poly1305_init
CRYPTO_F_PKEY_SIPHASH_INIT:125:pkey_siphash_init
+CRYPTO_F_PROVIDER_ACTIVATE:134:provider_activate
CRYPTO_F_SK_RESERVE:129:sk_reserve
CT_F_CTLOG_NEW:117:CTLOG_new
CT_F_CTLOG_NEW_FROM_BASE64:118:CTLOG_new_from_base64
diff --git a/crypto/provider_core.c b/crypto/provider_core.c
index 8af5b1f14d..c136e42e16 100644
--- a/crypto/provider_core.c
+++ b/crypto/provider_core.c
@@ -25,6 +25,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 +33,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 +60,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;
@@ -80,8 +83,9 @@ static void *provider_store_new(void)
|| (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;
return store;
}
@@ -185,6 +189,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 +213,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 +254,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 +308,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 +342,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 +392,50 @@ int ossl_provider_forall_loaded(OPENSSL_CTX *ctx,
struct provider_store_st *store = get_provider_store(ctx);
if (store != NULL) {
+ int found_activated = 0;
+
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);
+ ret = provider_forall_loaded(store, &found_activated, cb, cbdata);
- if (prov->flag_initialized
- && !(ret = cb(prov, cbdata)))
- break;
+ /*
+ * 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 +443,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)
{