From 1d74203cf5d8542d349fbb2d5f35ad40994dec9f Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 18 Jun 2021 12:28:40 +0100 Subject: [PATCH] Instantiate user-added builtin providers when we need them Previously we created the provider object for builtin providers at the point that OPENSSL_add_builtin() was called. Instead we delay that until the provider is actually loaded. Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/15854) --- crypto/provider.c | 23 ---------- crypto/provider_core.c | 84 ++++++++++++++++++++++++++++++++++-- crypto/provider_local.h | 6 +-- crypto/provider_predefined.c | 2 +- 4 files changed, 85 insertions(+), 30 deletions(-) diff --git a/crypto/provider.c b/crypto/provider.c index 60664e9e24e..5aec157c1f1 100644 --- a/crypto/provider.c +++ b/crypto/provider.c @@ -94,29 +94,6 @@ int OSSL_PROVIDER_get_capabilities(const OSSL_PROVIDER *prov, return ossl_provider_get_capabilities(prov, capability, cb, arg); } -int OSSL_PROVIDER_add_builtin(OSSL_LIB_CTX *libctx, const char *name, - OSSL_provider_init_fn *init_fn) -{ - OSSL_PROVIDER *prov = NULL; - - if (name == NULL || init_fn == NULL) { - ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER); - return 0; - } - - /* Create it */ - if ((prov = ossl_provider_new(libctx, name, init_fn, 0)) == NULL) - return 0; - - /* - * It's safely stored in the internal store at this point, - * free the returned extra reference - */ - ossl_provider_free(prov); - - return 1; -} - const char *OSSL_PROVIDER_get0_name(const OSSL_PROVIDER *prov) { return ossl_provider_name(prov); diff --git a/crypto/provider_core.c b/crypto/provider_core.c index 24c88e431d8..2503bf4af05 100644 --- a/crypto/provider_core.c +++ b/crypto/provider_core.c @@ -139,6 +139,9 @@ struct provider_store_st { CRYPTO_RWLOCK *default_path_lock; CRYPTO_RWLOCK *lock; char *default_path; + struct provider_info_st *provinfo; + size_t numprovinfo; + size_t provinfosz; unsigned int use_fallbacks:1; unsigned int freeing:1; }; @@ -166,6 +169,7 @@ static void ossl_provider_child_cb_free(OSSL_PROVIDER_CHILD_CB *cb) static void provider_store_free(void *vstore) { struct provider_store_st *store = vstore; + size_t i; if (store == NULL) return; @@ -178,6 +182,9 @@ static void provider_store_free(void *vstore) #endif CRYPTO_THREAD_lock_free(store->default_path_lock); CRYPTO_THREAD_lock_free(store->lock); + for (i = 0; i < store->numprovinfo; i++) + OPENSSL_free(store->provinfo[i].name); + OPENSSL_free(store->provinfo); OPENSSL_free(store); } @@ -233,6 +240,62 @@ int ossl_provider_disable_fallback_loading(OSSL_LIB_CTX *libctx) return 0; } +#define BUILTINS_BLOCK_SIZE 10 + +int OSSL_PROVIDER_add_builtin(OSSL_LIB_CTX *libctx, const char *name, + OSSL_provider_init_fn *init_fn) +{ + struct provider_store_st *store = get_provider_store(libctx); + int ret = 0; + + if (name == NULL || init_fn == NULL) { + ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (store == NULL) { + ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (!CRYPTO_THREAD_write_lock(store->lock)) + return 0; + 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); + goto err; + } + store->provinfosz = BUILTINS_BLOCK_SIZE; + } else if (store->numprovinfo == store->provinfosz) { + struct provider_info_st *tmpbuiltins; + size_t newsz = store->provinfosz + BUILTINS_BLOCK_SIZE; + + tmpbuiltins = OPENSSL_realloc(store->provinfo, + sizeof(*store->provinfo) * newsz); + if (tmpbuiltins == NULL) { + ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); + goto err; + } + store->provinfo = tmpbuiltins; + store->provinfosz = newsz; + } + store->provinfo[store->numprovinfo].name = OPENSSL_strdup(name); + if (store->provinfo[store->numprovinfo].name == NULL) { + ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); + goto err; + } + store->provinfo[store->numprovinfo].init = init_fn; + store->provinfo[store->numprovinfo].is_fallback = 0; + store->numprovinfo++; + + ret = 1; + err: + CRYPTO_THREAD_unlock(store->lock); + return ret; +} + OSSL_PROVIDER *ossl_provider_find(OSSL_LIB_CTX *libctx, const char *name, int noconfig) { @@ -354,15 +417,30 @@ OSSL_PROVIDER *ossl_provider_new(OSSL_LIB_CTX *libctx, const char *name, } if (init_function == NULL) { - const struct predefined_providers_st *p; + const struct provider_info_st *p; + size_t i; - /* Check if this is a built-in provider */ + /* Check if this is a predefined builtin provider */ for (p = ossl_predefined_providers; p->name != NULL; p++) { if (strcmp(p->name, name) == 0) { init_function = p->init; break; } } + if (p->name == NULL) { + /* Check if this is a user added builtin provider */ + if (!CRYPTO_THREAD_read_lock(store->lock)) + return NULL; + for (i = 0, p = store->provinfo; i < store->numprovinfo; p++, i++) { + if (strcmp(p->name, name) == 0) { + init_function = p->init; + break; + } + } + CRYPTO_THREAD_unlock(store->lock); + } + } else { + template.init = init_function; } /* provider_new() generates an error, so no need here */ @@ -930,7 +1008,7 @@ static int provider_activate_fallbacks(struct provider_store_st *store) int use_fallbacks; int activated_fallback_count = 0; int ret = 0; - const struct predefined_providers_st *p; + const struct provider_info_st *p; if (!CRYPTO_THREAD_read_lock(store->lock)) return 0; diff --git a/crypto/provider_local.h b/crypto/provider_local.h index 12baf032f1d..8ac692130fc 100644 --- a/crypto/provider_local.h +++ b/crypto/provider_local.h @@ -9,10 +9,10 @@ #include -struct predefined_providers_st { - const char *name; +struct provider_info_st { + char *name; OSSL_provider_init_fn *init; unsigned int is_fallback:1; }; -extern const struct predefined_providers_st ossl_predefined_providers[]; +extern const struct provider_info_st ossl_predefined_providers[]; diff --git a/crypto/provider_predefined.c b/crypto/provider_predefined.c index 142a6d97d1c..0ef569c06ac 100644 --- a/crypto/provider_predefined.c +++ b/crypto/provider_predefined.c @@ -17,7 +17,7 @@ OSSL_provider_init_fn ossl_fips_intern_provider_init; #ifdef STATIC_LEGACY OSSL_provider_init_fn ossl_legacy_provider_init; #endif -const struct predefined_providers_st ossl_predefined_providers[] = { +const struct provider_info_st ossl_predefined_providers[] = { #ifdef FIPS_MODULE { "fips", ossl_fips_intern_provider_init, 1 }, #else -- 2.47.2