/*
- * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
#include <openssl/params.h>
#include <openssl/opensslv.h>
#include "crypto/cryptlib.h"
-#include "crypto/evp.h" /* evp_method_store_flush */
+#ifndef FIPS_MODULE
+#include "crypto/decoder.h" /* ossl_decoder_store_cache_flush */
+#include "crypto/encoder.h" /* ossl_encoder_store_cache_flush */
+#include "crypto/store.h" /* ossl_store_loader_store_cache_flush */
+#endif
+#include "crypto/evp.h" /* evp_method_store_cache_flush */
#include "crypto/rand.h"
#include "internal/nelem.h"
#include "internal/thread_once.h"
#include "internal/bio.h"
#include "internal/core.h"
#include "provider_local.h"
+#include "crypto/context.h"
#ifndef FIPS_MODULE
# include <openssl/self_test.h>
#endif
* The locks available are:
*
* The provider flag_lock: Used to control updates to the various provider
- * "flags" (flag_initialized and flag_activated) and associated
- * "counts" (activatecnt).
+ * "flags" (flag_initialized and flag_activated).
*
- * The provider refcnt_lock: Only ever used to control updates to the provider
- * refcnt value.
+ * The provider activatecnt_lock: Used to control updates to the provider
+ * activatecnt value.
*
* The provider optbits_lock: Used to control access to the provider's
* operation_bits and operation_bits_sz fields.
* introducing the possibility of deadlock. The following rules MUST be adhered
* to in order to avoid that:
* - Holding multiple locks at the same time is only allowed for the
- * provider store lock, the provider flag_lock and the provider refcnt_lock.
+ * provider store lock, the provider activatecnt_lock and the provider flag_lock.
* - When holding multiple locks they must be acquired in the following order of
* precedence:
* 1) provider store lock
* 2) provider flag_lock
- * 3) provider refcnt_lock
+ * 3) provider activatecnt_lock
* - When releasing locks they must be released in the reverse order to which
* they were acquired
* - No locks may be held when making an upcall. NOTE: Some common functions
* some other function while holding a lock make sure you know whether it
* will make any upcalls or not. For example ossl_provider_up_ref() can call
* ossl_provider_up_ref_parent() which can call the c_prov_up_ref() upcall.
- * - It is permissible to hold the store lock when calling child provider
- * callbacks. No other locks may be held during such callbacks.
+ * - It is permissible to hold the store and flag locks when calling child
+ * provider callbacks. No other locks may be held during such callbacks.
*/
static OSSL_PROVIDER *provider_new(const char *name,
/* OpenSSL library side data */
CRYPTO_REF_COUNT refcnt;
- CRYPTO_RWLOCK *refcnt_lock; /* For the ref counter */
+ CRYPTO_RWLOCK *activatecnt_lock; /* For the activatecnt counter */
int activatecnt;
char *name;
char *path;
sk_INFOPAIR_pop_free(info->parameters, infopair_free);
}
-static void provider_store_free(void *vstore)
+void ossl_provider_store_free(void *vstore)
{
struct provider_store_st *store = vstore;
size_t i;
OPENSSL_free(store);
}
-static void *provider_store_new(OSSL_LIB_CTX *ctx)
+void *ossl_provider_store_new(OSSL_LIB_CTX *ctx)
{
struct provider_store_st *store = OPENSSL_zalloc(sizeof(*store));
|| (store->child_cbs = sk_OSSL_PROVIDER_CHILD_CB_new_null()) == NULL
#endif
|| (store->lock = CRYPTO_THREAD_lock_new()) == NULL) {
- provider_store_free(store);
+ ossl_provider_store_free(store);
return NULL;
}
store->libctx = ctx;
return store;
}
-static const OSSL_LIB_CTX_METHOD provider_store_method = {
- /* Needs to be freed before the child provider data is freed */
- OSSL_LIB_CTX_METHOD_PRIORITY_1,
- provider_store_new,
- provider_store_free,
-};
-
static struct provider_store_st *get_provider_store(OSSL_LIB_CTX *libctx)
{
struct provider_store_st *store = NULL;
- store = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_PROVIDER_STORE_INDEX,
- &provider_store_method);
+ store = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_PROVIDER_STORE_INDEX);
if (store == NULL)
ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
return store;
if (store->provinfosz == 0) {
store->provinfo = OPENSSL_zalloc(sizeof(*store->provinfo)
* BUILTINS_BLOCK_SIZE);
- if (store->provinfo == NULL) {
- ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
+ if (store->provinfo == NULL)
goto err;
- }
store->provinfosz = BUILTINS_BLOCK_SIZE;
} else if (store->numprovinfo == store->provinfosz) {
OSSL_PROVIDER_INFO *tmpbuiltins;
tmpbuiltins = OPENSSL_realloc(store->provinfo,
sizeof(*store->provinfo) * newsz);
- if (tmpbuiltins == NULL) {
- ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
+ if (tmpbuiltins == NULL)
goto err;
- }
store->provinfo = tmpbuiltins;
store->provinfosz = newsz;
}
}
OSSL_PROVIDER *ossl_provider_find(OSSL_LIB_CTX *libctx, const char *name,
- int noconfig)
+ ossl_unused int noconfig)
{
struct provider_store_st *store = NULL;
OSSL_PROVIDER *prov = NULL;
OSSL_PROVIDER tmpl = { 0, };
int i;
-#ifndef FIPS_MODULE
+#if !defined(FIPS_MODULE) && !defined(OPENSSL_NO_AUTOLOAD_CONFIG)
/*
* Make sure any providers are loaded from config before we try to find
* them.
#endif
tmpl.name = (char *)name;
- if (!CRYPTO_THREAD_read_lock(store->lock))
+ if (!CRYPTO_THREAD_write_lock(store->lock))
return NULL;
+ sk_OSSL_PROVIDER_sort(store->providers);
if ((i = sk_OSSL_PROVIDER_find(store->providers, &tmpl)) != -1)
prov = sk_OSSL_PROVIDER_value(store->providers, i);
CRYPTO_THREAD_unlock(store->lock);
{
OSSL_PROVIDER *prov = NULL;
- if ((prov = OPENSSL_zalloc(sizeof(*prov))) == NULL
-#ifndef HAVE_ATOMICS
- || (prov->refcnt_lock = CRYPTO_THREAD_lock_new()) == NULL
-#endif
- || (prov->opbits_lock = CRYPTO_THREAD_lock_new()) == NULL
+ if ((prov = OPENSSL_zalloc(sizeof(*prov))) == NULL)
+ return NULL;
+ if (!CRYPTO_NEW_REF(&prov->refcnt, 1)) {
+ OPENSSL_free(prov);
+ return NULL;
+ }
+ if ((prov->activatecnt_lock = CRYPTO_THREAD_lock_new()) == NULL) {
+ ossl_provider_free(prov);
+ ERR_raise(ERR_LIB_CRYPTO, ERR_R_CRYPTO_LIB);
+ return NULL;
+ }
+
+ if ((prov->opbits_lock = CRYPTO_THREAD_lock_new()) == NULL
|| (prov->flag_lock = CRYPTO_THREAD_lock_new()) == NULL
- || (prov->name = OPENSSL_strdup(name)) == NULL
|| (prov->parameters = sk_INFOPAIR_deep_copy(parameters,
infopair_copy,
infopair_free)) == NULL) {
ossl_provider_free(prov);
- ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_CRYPTO, ERR_R_CRYPTO_LIB);
+ return NULL;
+ }
+ if ((prov->name = OPENSSL_strdup(name)) == NULL) {
+ ossl_provider_free(prov);
return NULL;
}
- prov->refcnt = 1; /* 1 One reference to be returned */
prov->init_function = init_function;
return prov;
{
int ref = 0;
- if (CRYPTO_UP_REF(&prov->refcnt, &ref, prov->refcnt_lock) <= 0)
+ if (CRYPTO_UP_REF(&prov->refcnt, &ref) <= 0)
return 0;
#ifndef FIPS_MODULE
}
#endif
+/*
+ * We assume that the requested provider does not already exist in the store.
+ * The caller should check. If it does exist then adding it to the store later
+ * will fail.
+ */
OSSL_PROVIDER *ossl_provider_new(OSSL_LIB_CTX *libctx, const char *name,
OSSL_provider_init_fn *init_function,
- int noconfig)
+ OSSL_PARAM *params, int noconfig)
{
struct provider_store_st *store = NULL;
OSSL_PROVIDER_INFO template;
if ((store = get_provider_store(libctx)) == NULL)
return NULL;
- if ((prov = ossl_provider_find(libctx, name,
- noconfig)) != NULL) { /* refcount +1 */
- ossl_provider_free(prov); /* refcount -1 */
- ERR_raise_data(ERR_LIB_CRYPTO, CRYPTO_R_PROVIDER_ALREADY_EXISTS,
- "name=%s", name);
- return NULL;
- }
-
memset(&template, 0, sizeof(template));
if (init_function == NULL) {
const OSSL_PROVIDER_INFO *p;
}
}
if (p->name == NULL) {
- /* Check if this is a user added builtin provider */
+ /* Check if this is a user added provider */
if (!CRYPTO_THREAD_read_lock(store->lock))
return NULL;
for (i = 0, p = store->provinfo; i < store->numprovinfo; p++, i++) {
template.init = init_function;
}
+ if (params != NULL) {
+ int i;
+
+ template.parameters = sk_INFOPAIR_new_null();
+ if (template.parameters == NULL)
+ return NULL;
+
+ for (i = 0; params[i].key != NULL; i++) {
+ if (params[i].data_type != OSSL_PARAM_UTF8_STRING)
+ continue;
+ if (ossl_provider_info_add_parameter(&template, params[i].key,
+ (char *)params[i].data) <= 0) {
+ sk_INFOPAIR_pop_free(template.parameters, infopair_free);
+ return NULL;
+ }
+ }
+ }
+
/* provider_new() generates an error, so no need here */
- if ((prov = provider_new(name, template.init, template.parameters)) == NULL)
+ prov = provider_new(name, template.init, template.parameters);
+
+ if (params != NULL) /* We copied the parameters, let's free them */
+ sk_INFOPAIR_pop_free(template.parameters, infopair_free);
+
+ if (prov == NULL)
return NULL;
+ if (!ossl_provider_set_module_path(prov, template.path)) {
+ ossl_provider_free(prov);
+ return NULL;
+ }
+
prov->libctx = libctx;
#ifndef FIPS_MODULE
prov->error_lib = ERR_get_next_error_library();
OSSL_PROVIDER tmpl = { 0, };
OSSL_PROVIDER *actualtmp = NULL;
+ if (actualprov != NULL)
+ *actualprov = NULL;
+
if ((store = get_provider_store(prov->libctx)) == NULL)
return 0;
if (actualprov != NULL) {
if (!ossl_provider_up_ref(actualtmp)) {
- ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
+ ERR_raise(ERR_LIB_CRYPTO, ERR_R_CRYPTO_LIB);
actualtmp = NULL;
- goto err;
+ return 0;
}
*actualprov = actualtmp;
}
ossl_provider_deactivate(prov, 0);
ossl_provider_free(prov);
}
+#ifndef FIPS_MODULE
+ else {
+ /*
+ * This can be done outside the lock. We tolerate other threads getting
+ * the wrong result briefly when creating OSSL_DECODER_CTXs.
+ */
+ ossl_decoder_cache_flush(prov->libctx);
+ }
+#endif
return 1;
err:
CRYPTO_THREAD_unlock(store->lock);
- if (actualprov != NULL)
- ossl_provider_free(actualtmp);
return 0;
}
if (prov != NULL) {
int ref = 0;
- CRYPTO_DOWN_REF(&prov->refcnt, &ref, prov->refcnt_lock);
+ CRYPTO_DOWN_REF(&prov->refcnt, &ref);
/*
* When the refcount drops to zero, we clean up the provider.
sk_INFOPAIR_pop_free(prov->parameters, infopair_free);
CRYPTO_THREAD_lock_free(prov->opbits_lock);
CRYPTO_THREAD_lock_free(prov->flag_lock);
-#ifndef HAVE_ATOMICS
- CRYPTO_THREAD_lock_free(prov->refcnt_lock);
-#endif
+ CRYPTO_THREAD_lock_free(prov->activatecnt_lock);
+ CRYPTO_FREE_REF(&prov->refcnt);
OPENSSL_free(prov);
}
#ifndef FIPS_MODULE
return 1;
if ((prov->path = OPENSSL_strdup(module_path)) != NULL)
return 1;
- ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
return 0;
}
{
INFOPAIR *pair = NULL;
- if ((pair = OPENSSL_zalloc(sizeof(*pair))) != NULL
- && (*infopairsk != NULL
- || (*infopairsk = sk_INFOPAIR_new_null()) != NULL)
- && (pair->name = OPENSSL_strdup(name)) != NULL
- && (pair->value = OPENSSL_strdup(value)) != NULL
- && sk_INFOPAIR_push(*infopairsk, pair) > 0)
- return 1;
+ if ((pair = OPENSSL_zalloc(sizeof(*pair))) == NULL
+ || (pair->name = OPENSSL_strdup(name)) == NULL
+ || (pair->value = OPENSSL_strdup(value)) == NULL)
+ goto err;
+
+ if ((*infopairsk == NULL
+ && (*infopairsk = sk_INFOPAIR_new_null()) == NULL)
+ || sk_INFOPAIR_push(*infopairsk, pair) <= 0) {
+ ERR_raise(ERR_LIB_CRYPTO, ERR_R_CRYPTO_LIB);
+ goto err;
+ }
+ return 1;
+
+ err:
if (pair != NULL) {
OPENSSL_free(pair->name);
OPENSSL_free(pair->value);
OPENSSL_free(pair);
}
- ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
return 0;
}
if (path != NULL) {
p = OPENSSL_strdup(path);
- if (p == NULL) {
- ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
+ if (p == NULL)
return 0;
- }
}
if ((store = get_provider_store(libctx)) != NULL
&& CRYPTO_THREAD_write_lock(store->default_path_lock)) {
return 0;
}
+const char *OSSL_PROVIDER_get0_default_search_path(OSSL_LIB_CTX *libctx)
+{
+ struct provider_store_st *store;
+ char *path = NULL;
+
+ if ((store = get_provider_store(libctx)) != NULL
+ && CRYPTO_THREAD_read_lock(store->default_path_lock)) {
+ path = store->default_path;
+ CRYPTO_THREAD_unlock(store->default_path_lock);
+ }
+ return path;
+}
+
/*
* Internal version that doesn't affect the store flags, and thereby avoid
* locking. Direct callers must remember to set the store flags when
if (store->default_path != NULL) {
allocated_load_dir = OPENSSL_strdup(store->default_path);
CRYPTO_THREAD_unlock(store->default_path_lock);
- if (allocated_load_dir == NULL) {
- ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
+ if (allocated_load_dir == NULL)
goto end;
- }
load_dir = allocated_load_dir;
} else {
CRYPTO_THREAD_unlock(store->default_path_lock);
OPENSSL_free(allocated_load_dir);
}
- if (prov->module != NULL)
- prov->init_function = (OSSL_provider_init_fn *)
- DSO_bind_func(prov->module, "OSSL_provider_init");
+ if (prov->module == NULL) {
+ /* DSO has already recorded errors, this is just a tracepoint */
+ ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_DSO_LIB,
+ "name=%s", prov->name);
+ goto end;
+ }
+
+ prov->init_function = (OSSL_provider_init_fn *)
+ DSO_bind_func(prov->module, "OSSL_provider_init");
#endif
}
- /* Call the initialise function for the provider. */
- if (prov->init_function == NULL
- || !prov->init_function((OSSL_CORE_HANDLE *)prov, core_dispatch,
- &provider_dispatch, &tmp_provctx)) {
+ /* Check for and call the initialise function for the provider. */
+ if (prov->init_function == NULL) {
+ ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_UNSUPPORTED,
+ "name=%s, provider has no provider init function",
+ prov->name);
+ goto end;
+ }
+
+ if (!prov->init_function((OSSL_CORE_HANDLE *)prov, core_dispatch,
+ &provider_dispatch, &tmp_provctx)) {
ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INIT_FAIL,
"name=%s", prov->name);
goto end;
prov->provctx = tmp_provctx;
prov->dispatch = provider_dispatch;
- for (; provider_dispatch->function_id != 0; provider_dispatch++) {
- switch (provider_dispatch->function_id) {
- case OSSL_FUNC_PROVIDER_TEARDOWN:
- prov->teardown =
- OSSL_FUNC_provider_teardown(provider_dispatch);
- break;
- case OSSL_FUNC_PROVIDER_GETTABLE_PARAMS:
- prov->gettable_params =
- OSSL_FUNC_provider_gettable_params(provider_dispatch);
- break;
- case OSSL_FUNC_PROVIDER_GET_PARAMS:
- prov->get_params =
- OSSL_FUNC_provider_get_params(provider_dispatch);
- break;
- case OSSL_FUNC_PROVIDER_SELF_TEST:
- prov->self_test =
- OSSL_FUNC_provider_self_test(provider_dispatch);
- break;
- case OSSL_FUNC_PROVIDER_GET_CAPABILITIES:
- prov->get_capabilities =
- OSSL_FUNC_provider_get_capabilities(provider_dispatch);
- break;
- case OSSL_FUNC_PROVIDER_QUERY_OPERATION:
- prov->query_operation =
- OSSL_FUNC_provider_query_operation(provider_dispatch);
- break;
- case OSSL_FUNC_PROVIDER_UNQUERY_OPERATION:
- prov->unquery_operation =
- OSSL_FUNC_provider_unquery_operation(provider_dispatch);
- break;
+ if (provider_dispatch != NULL) {
+ for (; provider_dispatch->function_id != 0; provider_dispatch++) {
+ switch (provider_dispatch->function_id) {
+ case OSSL_FUNC_PROVIDER_TEARDOWN:
+ prov->teardown =
+ OSSL_FUNC_provider_teardown(provider_dispatch);
+ break;
+ case OSSL_FUNC_PROVIDER_GETTABLE_PARAMS:
+ prov->gettable_params =
+ OSSL_FUNC_provider_gettable_params(provider_dispatch);
+ break;
+ case OSSL_FUNC_PROVIDER_GET_PARAMS:
+ prov->get_params =
+ OSSL_FUNC_provider_get_params(provider_dispatch);
+ break;
+ case OSSL_FUNC_PROVIDER_SELF_TEST:
+ prov->self_test =
+ OSSL_FUNC_provider_self_test(provider_dispatch);
+ break;
+ case OSSL_FUNC_PROVIDER_GET_CAPABILITIES:
+ prov->get_capabilities =
+ OSSL_FUNC_provider_get_capabilities(provider_dispatch);
+ break;
+ case OSSL_FUNC_PROVIDER_QUERY_OPERATION:
+ prov->query_operation =
+ OSSL_FUNC_provider_query_operation(provider_dispatch);
+ break;
+ case OSSL_FUNC_PROVIDER_UNQUERY_OPERATION:
+ prov->unquery_operation =
+ OSSL_FUNC_provider_unquery_operation(provider_dispatch);
+ break;
#ifndef OPENSSL_NO_ERR
# ifndef FIPS_MODULE
- case OSSL_FUNC_PROVIDER_GET_REASON_STRINGS:
- p_get_reason_strings =
- OSSL_FUNC_provider_get_reason_strings(provider_dispatch);
- break;
+ case OSSL_FUNC_PROVIDER_GET_REASON_STRINGS:
+ p_get_reason_strings =
+ OSSL_FUNC_provider_get_reason_strings(provider_dispatch);
+ break;
# endif
#endif
+ }
}
}
#ifndef FIPS_MODULE
int freeparent = 0;
#endif
+ int lock = 1;
if (!ossl_assert(prov != NULL))
return -1;
+ /*
+ * No need to lock if we've got no store because we've not been shared with
+ * other threads.
+ */
store = get_provider_store(prov->libctx);
if (store == NULL)
- return -1;
+ lock = 0;
- if (!CRYPTO_THREAD_read_lock(store->lock))
+ if (lock && !CRYPTO_THREAD_read_lock(store->lock))
return -1;
- if (!CRYPTO_THREAD_write_lock(prov->flag_lock)) {
+ if (lock && !CRYPTO_THREAD_write_lock(prov->flag_lock)) {
CRYPTO_THREAD_unlock(store->lock);
return -1;
}
+ CRYPTO_atomic_add(&prov->activatecnt, -1, &count, prov->activatecnt_lock);
#ifndef FIPS_MODULE
- if (prov->activatecnt >= 2 && prov->ischild && upcalls) {
+ if (count >= 1 && prov->ischild && upcalls) {
/*
* We have had a direct activation in this child libctx so we need to
* now down the ref count in the parent provider. We do the actual down
}
#endif
- if ((count = --prov->activatecnt) < 1)
+ if (count < 1)
prov->flag_activated = 0;
#ifndef FIPS_MODULE
else
removechildren = 0;
#endif
- CRYPTO_THREAD_unlock(prov->flag_lock);
-
#ifndef FIPS_MODULE
- if (removechildren) {
+ if (removechildren && store != NULL) {
int i, max = sk_OSSL_PROVIDER_CHILD_CB_num(store->child_cbs);
OSSL_PROVIDER_CHILD_CB *child_cb;
}
}
#endif
- CRYPTO_THREAD_unlock(store->lock);
+ if (lock) {
+ CRYPTO_THREAD_unlock(prov->flag_lock);
+ CRYPTO_THREAD_unlock(store->lock);
+ /*
+ * This can be done outside the lock. We tolerate other threads getting
+ * the wrong result briefly when creating OSSL_DECODER_CTXs.
+ */
+#ifndef FIPS_MODULE
+ if (count < 1)
+ ossl_decoder_cache_flush(prov->libctx);
+#endif
+ }
#ifndef FIPS_MODULE
if (freeparent)
ossl_provider_free_parent(prov, 1);
{
int count = -1;
struct provider_store_st *store;
- int ret = 1, createchildren = 0;
+ int ret = 1;
store = prov->store;
/*
#endif
return -1;
}
+ if (CRYPTO_atomic_add(&prov->activatecnt, 1, &count, prov->activatecnt_lock)) {
+ prov->flag_activated = 1;
- count = ++prov->activatecnt;
- prov->flag_activated = 1;
-
- if (prov->activatecnt == 1 && store != NULL)
- createchildren = 1;
-
- if (lock)
+ if (count == 1 && store != NULL) {
+ ret = create_provider_children(prov);
+ }
+ }
+ if (lock) {
CRYPTO_THREAD_unlock(prov->flag_lock);
- if (createchildren)
- ret = create_provider_children(prov);
- if (lock)
CRYPTO_THREAD_unlock(store->lock);
+ /*
+ * This can be done outside the lock. We tolerate other threads getting
+ * the wrong result briefly when creating OSSL_DECODER_CTXs.
+ */
+#ifndef FIPS_MODULE
+ if (count == 1)
+ ossl_decoder_cache_flush(prov->libctx);
+#endif
+ }
if (!ret)
return -1;
freeing = store->freeing;
CRYPTO_THREAD_unlock(store->lock);
- if (!freeing)
- return evp_method_store_flush(prov->libctx);
+ if (!freeing) {
+ int acc
+ = evp_method_store_cache_flush(prov->libctx)
+#ifndef FIPS_MODULE
+ + ossl_encoder_store_cache_flush(prov->libctx)
+ + ossl_decoder_store_cache_flush(prov->libctx)
+ + ossl_store_loader_store_cache_flush(prov->libctx)
+#endif
+ ;
+
+#ifndef FIPS_MODULE
+ return acc == 4;
+#else
+ return acc == 1;
+#endif
+ }
+ return 1;
+}
+
+static int provider_remove_store_methods(OSSL_PROVIDER *prov)
+{
+ struct provider_store_st *store;
+ int freeing;
+
+ if ((store = get_provider_store(prov->libctx)) == NULL)
+ return 0;
+
+ if (!CRYPTO_THREAD_read_lock(store->lock))
+ return 0;
+ freeing = store->freeing;
+ CRYPTO_THREAD_unlock(store->lock);
+
+ if (!freeing) {
+ int acc;
+
+ if (!CRYPTO_THREAD_write_lock(prov->opbits_lock))
+ return 0;
+ OPENSSL_free(prov->operation_bits);
+ prov->operation_bits = NULL;
+ prov->operation_bits_sz = 0;
+ CRYPTO_THREAD_unlock(prov->opbits_lock);
+
+ acc = evp_method_store_remove_all_provided(prov)
+#ifndef FIPS_MODULE
+ + ossl_encoder_store_remove_all_provided(prov)
+ + ossl_decoder_store_remove_all_provided(prov)
+ + ossl_store_loader_store_remove_all_provided(prov)
+#endif
+ ;
+
+#ifndef FIPS_MODULE
+ return acc == 4;
+#else
+ return acc == 1;
+#endif
+ }
return 1;
}
if (prov == NULL
|| (count = provider_deactivate(prov, 1, removechildren)) < 0)
return 0;
- return count == 0 ? provider_flush_store_cache(prov) : 1;
+ return count == 0 ? provider_remove_store_methods(prov) : 1;
}
void *ossl_provider_ctx(const OSSL_PROVIDER *prov)
{
- return prov->provctx;
+ return prov != NULL ? prov->provctx : NULL;
}
/*
struct provider_store_st *store = get_provider_store(ctx);
STACK_OF(OSSL_PROVIDER) *provs = NULL;
-#ifndef FIPS_MODULE
+#if !defined(FIPS_MODULE) && !defined(OPENSSL_NO_AUTOLOAD_CONFIG)
/*
* Make sure any providers are loaded from config before we try to use
* them.
for (curr = max - 1; curr >= 0; curr--) {
OSSL_PROVIDER *prov = sk_OSSL_PROVIDER_value(provs, curr);
- if (!CRYPTO_THREAD_write_lock(prov->flag_lock))
+ if (!CRYPTO_THREAD_read_lock(prov->flag_lock))
goto err_unlock;
if (prov->flag_activated) {
/*
* to avoid upping the ref count on the parent provider, which we
* must not do while holding locks.
*/
- if (CRYPTO_UP_REF(&prov->refcnt, &ref, prov->refcnt_lock) <= 0) {
+ if (CRYPTO_UP_REF(&prov->refcnt, &ref) <= 0) {
CRYPTO_THREAD_unlock(prov->flag_lock);
goto err_unlock;
}
/*
* It's already activated, but we up the activated count to ensure
* it remains activated until after we've called the user callback.
- * We do this with no locking (because we already hold the locks)
- * and no upcalls (which must not be called when locks are held). In
- * theory this could mean the parent provider goes inactive, whilst
- * still activated in the child for a short period. That's ok.
+ * In theory this could mean the parent provider goes inactive,
+ * whilst still activated in the child for a short period. That's ok.
*/
- if (provider_activate(prov, 0, 0) < 0) {
- CRYPTO_DOWN_REF(&prov->refcnt, &ref, prov->refcnt_lock);
+ if (!CRYPTO_atomic_add(&prov->activatecnt, 1, &ref,
+ prov->activatecnt_lock)) {
+ CRYPTO_DOWN_REF(&prov->refcnt, &ref);
CRYPTO_THREAD_unlock(prov->flag_lock);
goto err_unlock;
}
for (curr = 0; curr < max; curr++) {
OSSL_PROVIDER *prov = sk_OSSL_PROVIDER_value(provs, curr);
- if (!cb(prov, cbdata))
+ if (!cb(prov, cbdata)) {
+ curr = -1;
goto finish;
+ }
}
curr = -1;
for (curr++; curr < max; curr++) {
OSSL_PROVIDER *prov = sk_OSSL_PROVIDER_value(provs, curr);
- provider_deactivate(prov, 0, 1);
+ if (!CRYPTO_atomic_add(&prov->activatecnt, -1, &ref,
+ prov->activatecnt_lock)) {
+ ret = 0;
+ continue;
+ }
+ if (ref < 1) {
+ /*
+ * Looks like we need to deactivate properly. We could just have
+ * done this originally, but it involves taking a write lock so
+ * we avoid it. We up the count again and do a full deactivation
+ */
+ if (CRYPTO_atomic_add(&prov->activatecnt, 1, &ref,
+ prov->activatecnt_lock))
+ provider_deactivate(prov, 0, 1);
+ else
+ ret = 0;
+ }
/*
* As above where we did the up-ref, we don't call ossl_provider_free
* to avoid making upcalls. There should always be at least one ref
* to the provider in the store, so this should never drop to 0.
*/
- CRYPTO_DOWN_REF(&prov->refcnt, &ref, prov->refcnt_lock);
+ if (!CRYPTO_DOWN_REF(&prov->refcnt, &ref)) {
+ ret = 0;
+ continue;
+ }
/*
* Not much we can do if this assert ever fails. So we don't use
* ossl_assert here.
return 1;
ret = prov->self_test(prov->provctx);
if (ret == 0)
- (void)provider_flush_store_cache(prov);
+ (void)provider_remove_store_methods((OSSL_PROVIDER *)prov);
return ret;
}
prov->unquery_operation(prov->provctx, operation_id, algs);
}
-int ossl_provider_clear_all_operation_bits(OSSL_LIB_CTX *libctx)
-{
- struct provider_store_st *store;
- OSSL_PROVIDER *provider;
- int i, num, res = 1;
-
- if ((store = get_provider_store(libctx)) != NULL) {
- if (!CRYPTO_THREAD_read_lock(store->lock))
- return 0;
- num = sk_OSSL_PROVIDER_num(store->providers);
- for (i = 0; i < num; i++) {
- provider = sk_OSSL_PROVIDER_value(store->providers, i);
- if (!CRYPTO_THREAD_write_lock(provider->opbits_lock)) {
- res = 0;
- continue;
- }
- if (provider->operation_bits != NULL)
- memset(provider->operation_bits, 0,
- provider->operation_bits_sz);
- CRYPTO_THREAD_unlock(provider->opbits_lock);
- }
- CRYPTO_THREAD_unlock(store->lock);
- return res;
- }
- return 0;
-}
-
int ossl_provider_set_operation_bit(OSSL_PROVIDER *provider, size_t bitnum)
{
size_t byte = bitnum / 8;
if (tmp == NULL) {
CRYPTO_THREAD_unlock(provider->opbits_lock);
- ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
return 0;
}
provider->operation_bits = tmp;
*/
static OSSL_FUNC_core_gettable_params_fn core_gettable_params;
static OSSL_FUNC_core_get_params_fn core_get_params;
-static OSSL_FUNC_core_thread_start_fn core_thread_start;
static OSSL_FUNC_core_get_libctx_fn core_get_libctx;
+static OSSL_FUNC_core_thread_start_fn core_thread_start;
#ifndef FIPS_MODULE
static OSSL_FUNC_core_new_error_fn core_new_error;
static OSSL_FUNC_core_set_error_debug_fn core_set_error_debug;
static OSSL_FUNC_core_set_error_mark_fn core_set_error_mark;
static OSSL_FUNC_core_clear_last_error_mark_fn core_clear_last_error_mark;
static OSSL_FUNC_core_pop_error_to_mark_fn core_pop_error_to_mark;
+OSSL_FUNC_BIO_new_file_fn ossl_core_bio_new_file;
+OSSL_FUNC_BIO_new_membuf_fn ossl_core_bio_new_mem_buf;
+OSSL_FUNC_BIO_read_ex_fn ossl_core_bio_read_ex;
+OSSL_FUNC_BIO_write_ex_fn ossl_core_bio_write_ex;
+OSSL_FUNC_BIO_gets_fn ossl_core_bio_gets;
+OSSL_FUNC_BIO_puts_fn ossl_core_bio_puts;
+OSSL_FUNC_BIO_up_ref_fn ossl_core_bio_up_ref;
+OSSL_FUNC_BIO_free_fn ossl_core_bio_free;
+OSSL_FUNC_BIO_vprintf_fn ossl_core_bio_vprintf;
+OSSL_FUNC_BIO_vsnprintf_fn BIO_vsnprintf;
+static OSSL_FUNC_self_test_cb_fn core_self_test_get_callback;
+static OSSL_FUNC_get_entropy_fn rand_get_entropy;
+static OSSL_FUNC_get_user_entropy_fn rand_get_user_entropy;
+static OSSL_FUNC_cleanup_entropy_fn rand_cleanup_entropy;
+static OSSL_FUNC_cleanup_user_entropy_fn rand_cleanup_user_entropy;
+static OSSL_FUNC_get_nonce_fn rand_get_nonce;
+static OSSL_FUNC_get_user_nonce_fn rand_get_user_nonce;
+static OSSL_FUNC_cleanup_nonce_fn rand_cleanup_nonce;
+static OSSL_FUNC_cleanup_user_nonce_fn rand_cleanup_user_nonce;
+#endif
+OSSL_FUNC_CRYPTO_malloc_fn CRYPTO_malloc;
+OSSL_FUNC_CRYPTO_zalloc_fn CRYPTO_zalloc;
+OSSL_FUNC_CRYPTO_free_fn CRYPTO_free;
+OSSL_FUNC_CRYPTO_clear_free_fn CRYPTO_clear_free;
+OSSL_FUNC_CRYPTO_realloc_fn CRYPTO_realloc;
+OSSL_FUNC_CRYPTO_clear_realloc_fn CRYPTO_clear_realloc;
+OSSL_FUNC_CRYPTO_secure_malloc_fn CRYPTO_secure_malloc;
+OSSL_FUNC_CRYPTO_secure_zalloc_fn CRYPTO_secure_zalloc;
+OSSL_FUNC_CRYPTO_secure_free_fn CRYPTO_secure_free;
+OSSL_FUNC_CRYPTO_secure_clear_free_fn CRYPTO_secure_clear_free;
+OSSL_FUNC_CRYPTO_secure_allocated_fn CRYPTO_secure_allocated;
+OSSL_FUNC_OPENSSL_cleanse_fn OPENSSL_cleanse;
+#ifndef FIPS_MODULE
+OSSL_FUNC_provider_register_child_cb_fn ossl_provider_register_child_cb;
+OSSL_FUNC_provider_deregister_child_cb_fn ossl_provider_deregister_child_cb;
+static OSSL_FUNC_provider_name_fn core_provider_get0_name;
+static OSSL_FUNC_provider_get0_provider_ctx_fn core_provider_get0_provider_ctx;
+static OSSL_FUNC_provider_get0_dispatch_fn core_provider_get0_dispatch;
+static OSSL_FUNC_provider_up_ref_fn core_provider_up_ref_intern;
+static OSSL_FUNC_provider_free_fn core_provider_free_intern;
static OSSL_FUNC_core_obj_add_sigid_fn core_obj_add_sigid;
static OSSL_FUNC_core_obj_create_fn core_obj_create;
#endif
return ERR_pop_to_mark();
}
+static void core_self_test_get_callback(OPENSSL_CORE_CTX *libctx,
+ OSSL_CALLBACK **cb, void **cbarg)
+{
+ OSSL_SELF_TEST_get_callback((OSSL_LIB_CTX *)libctx, cb, cbarg);
+}
+
+static size_t rand_get_entropy(const OSSL_CORE_HANDLE *handle,
+ unsigned char **pout, int entropy,
+ size_t min_len, size_t max_len)
+{
+ return ossl_rand_get_entropy((OSSL_LIB_CTX *)core_get_libctx(handle),
+ pout, entropy, min_len, max_len);
+}
+
+static size_t rand_get_user_entropy(const OSSL_CORE_HANDLE *handle,
+ unsigned char **pout, int entropy,
+ size_t min_len, size_t max_len)
+{
+ return ossl_rand_get_user_entropy((OSSL_LIB_CTX *)core_get_libctx(handle),
+ pout, entropy, min_len, max_len);
+}
+
+static void rand_cleanup_entropy(const OSSL_CORE_HANDLE *handle,
+ unsigned char *buf, size_t len)
+{
+ ossl_rand_cleanup_entropy((OSSL_LIB_CTX *)core_get_libctx(handle),
+ buf, len);
+}
+
+static void rand_cleanup_user_entropy(const OSSL_CORE_HANDLE *handle,
+ unsigned char *buf, size_t len)
+{
+ ossl_rand_cleanup_user_entropy((OSSL_LIB_CTX *)core_get_libctx(handle),
+ buf, len);
+}
+
+static size_t rand_get_nonce(const OSSL_CORE_HANDLE *handle,
+ unsigned char **pout,
+ size_t min_len, size_t max_len,
+ const void *salt, size_t salt_len)
+{
+ return ossl_rand_get_nonce((OSSL_LIB_CTX *)core_get_libctx(handle),
+ pout, min_len, max_len, salt, salt_len);
+}
+
+static size_t rand_get_user_nonce(const OSSL_CORE_HANDLE *handle,
+ unsigned char **pout,
+ size_t min_len, size_t max_len,
+ const void *salt, size_t salt_len)
+{
+ return ossl_rand_get_user_nonce((OSSL_LIB_CTX *)core_get_libctx(handle),
+ pout, min_len, max_len, salt, salt_len);
+}
+
+static void rand_cleanup_nonce(const OSSL_CORE_HANDLE *handle,
+ unsigned char *buf, size_t len)
+{
+ ossl_rand_cleanup_nonce((OSSL_LIB_CTX *)core_get_libctx(handle),
+ buf, len);
+}
+
+static void rand_cleanup_user_nonce(const OSSL_CORE_HANDLE *handle,
+ unsigned char *buf, size_t len)
+{
+ ossl_rand_cleanup_user_nonce((OSSL_LIB_CTX *)core_get_libctx(handle),
+ buf, len);
+}
+
+static const char *core_provider_get0_name(const OSSL_CORE_HANDLE *prov)
+{
+ return OSSL_PROVIDER_get0_name((const OSSL_PROVIDER *)prov);
+}
+
+static void *core_provider_get0_provider_ctx(const OSSL_CORE_HANDLE *prov)
+{
+ return OSSL_PROVIDER_get0_provider_ctx((const OSSL_PROVIDER *)prov);
+}
+
+static const OSSL_DISPATCH *
+core_provider_get0_dispatch(const OSSL_CORE_HANDLE *prov)
+{
+ return OSSL_PROVIDER_get0_dispatch((const OSSL_PROVIDER *)prov);
+}
+
+static int core_provider_up_ref_intern(const OSSL_CORE_HANDLE *prov,
+ int activate)
+{
+ return provider_up_ref_intern((OSSL_PROVIDER *)prov, activate);
+}
+
+static int core_provider_free_intern(const OSSL_CORE_HANDLE *prov,
+ int deactivate)
+{
+ return provider_free_intern((OSSL_PROVIDER *)prov, deactivate);
+}
+
static int core_obj_add_sigid(const OSSL_CORE_HANDLE *prov,
const char *sign_name, const char *digest_name,
const char *pkey_name)
{ OSSL_FUNC_BIO_FREE, (void (*)(void))ossl_core_bio_free },
{ OSSL_FUNC_BIO_VPRINTF, (void (*)(void))ossl_core_bio_vprintf },
{ OSSL_FUNC_BIO_VSNPRINTF, (void (*)(void))BIO_vsnprintf },
- { OSSL_FUNC_SELF_TEST_CB, (void (*)(void))OSSL_SELF_TEST_get_callback },
- { OSSL_FUNC_GET_ENTROPY, (void (*)(void))ossl_rand_get_entropy },
- { OSSL_FUNC_CLEANUP_ENTROPY, (void (*)(void))ossl_rand_cleanup_entropy },
- { OSSL_FUNC_GET_NONCE, (void (*)(void))ossl_rand_get_nonce },
- { OSSL_FUNC_CLEANUP_NONCE, (void (*)(void))ossl_rand_cleanup_nonce },
+ { OSSL_FUNC_SELF_TEST_CB, (void (*)(void))core_self_test_get_callback },
+ { OSSL_FUNC_GET_ENTROPY, (void (*)(void))rand_get_entropy },
+ { OSSL_FUNC_GET_USER_ENTROPY, (void (*)(void))rand_get_user_entropy },
+ { OSSL_FUNC_CLEANUP_ENTROPY, (void (*)(void))rand_cleanup_entropy },
+ { OSSL_FUNC_CLEANUP_USER_ENTROPY, (void (*)(void))rand_cleanup_user_entropy },
+ { OSSL_FUNC_GET_NONCE, (void (*)(void))rand_get_nonce },
+ { OSSL_FUNC_GET_USER_NONCE, (void (*)(void))rand_get_user_nonce },
+ { OSSL_FUNC_CLEANUP_NONCE, (void (*)(void))rand_cleanup_nonce },
+ { OSSL_FUNC_CLEANUP_USER_NONCE, (void (*)(void))rand_cleanup_user_nonce },
#endif
{ OSSL_FUNC_CRYPTO_MALLOC, (void (*)(void))CRYPTO_malloc },
{ OSSL_FUNC_CRYPTO_ZALLOC, (void (*)(void))CRYPTO_zalloc },
{ OSSL_FUNC_PROVIDER_DEREGISTER_CHILD_CB,
(void (*)(void))ossl_provider_deregister_child_cb },
{ OSSL_FUNC_PROVIDER_NAME,
- (void (*)(void))OSSL_PROVIDER_get0_name },
+ (void (*)(void))core_provider_get0_name },
{ OSSL_FUNC_PROVIDER_GET0_PROVIDER_CTX,
- (void (*)(void))OSSL_PROVIDER_get0_provider_ctx },
+ (void (*)(void))core_provider_get0_provider_ctx },
{ OSSL_FUNC_PROVIDER_GET0_DISPATCH,
- (void (*)(void))OSSL_PROVIDER_get0_dispatch },
+ (void (*)(void))core_provider_get0_dispatch },
{ OSSL_FUNC_PROVIDER_UP_REF,
- (void (*)(void))provider_up_ref_intern },
+ (void (*)(void))core_provider_up_ref_intern },
{ OSSL_FUNC_PROVIDER_FREE,
- (void (*)(void))provider_free_intern },
+ (void (*)(void))core_provider_free_intern },
{ OSSL_FUNC_CORE_OBJ_ADD_SIGID, (void (*)(void))core_obj_add_sigid },
{ OSSL_FUNC_CORE_OBJ_CREATE, (void (*)(void))core_obj_create },
#endif
- { 0, NULL }
+ OSSL_DISPATCH_END
};
static const OSSL_DISPATCH *core_dispatch = core_dispatch_;