#include <openssl/core.h>
#include <openssl/core_numbers.h>
+#include <openssl/params.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
* =========================
*/
+typedef struct {
+ char *name;
+ char *value;
+} INFOPAIR;
+DEFINE_STACK_OF(INFOPAIR)
+
struct provider_store_st; /* Forward declaration */
struct ossl_provider_st {
CRYPTO_REF_COUNT refcnt;
CRYPTO_RWLOCK *refcnt_lock; /* For the ref counter */
char *name;
+ char *path;
DSO *module;
OSSL_provider_init_fn *init_function;
+ STACK_OF(INFOPAIR) *parameters;
struct provider_store_st *store; /* The store this instance belongs to */
/* Provider side functions */
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
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;
}
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;
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)
{
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 */
return prov;
}
+static void free_infopair(INFOPAIR *pair)
+{
+ OPENSSL_free(pair->name);
+ OPENSSL_free(pair->value);
+ OPENSSL_free(pair);
+}
+
void ossl_provider_free(OSSL_PROVIDER *prov)
{
if (prov != NULL) {
if (ref == 0) {
DSO_free(prov->module);
OPENSSL_free(prov->name);
+ OPENSSL_free(prov->path);
+ sk_INFOPAIR_pop_free(prov->parameters, free_infopair);
#ifndef HAVE_ATOMICS
CRYPTO_THREAD_lock_free(prov->refcnt_lock);
#endif
}
}
+/* Setters */
+int ossl_provider_set_module_path(OSSL_PROVIDER *prov, const char *module_path)
+{
+ OPENSSL_free(prov->path);
+ if (module_path == NULL)
+ return 1;
+ if ((prov->path = OPENSSL_strdup(module_path)) != NULL)
+ return 1;
+ CRYPTOerr(CRYPTO_F_OSSL_PROVIDER_SET_MODULE_PATH, ERR_R_MALLOC_FAILURE);
+ return 0;
+}
+
+int ossl_provider_add_parameter(OSSL_PROVIDER *prov,
+ const char *name, const char *value)
+{
+ INFOPAIR *pair = NULL;
+
+ if ((pair = OPENSSL_zalloc(sizeof(*pair))) != NULL
+ && (prov->parameters != NULL
+ || (prov->parameters = sk_INFOPAIR_new_null()) != NULL)
+ && (pair->name = OPENSSL_strdup(name)) != NULL
+ && (pair->value = OPENSSL_strdup(value)) != NULL
+ && sk_INFOPAIR_push(prov->parameters, pair) > 0)
+ return 1;
+
+ if (pair != NULL) {
+ OPENSSL_free(pair->name);
+ OPENSSL_free(pair->value);
+ OPENSSL_free(pair);
+ }
+ CRYPTOerr(CRYPTO_F_OSSL_PROVIDER_ADD_PARAMETER, ERR_R_MALLOC_FAILURE);
+ return 0;
+}
+
/*
* Provider activation.
*
*/
if (prov->init_function == NULL) {
if (prov->module == NULL) {
- char *platform_module_name = NULL;
- char *module_path = NULL;
+ char *allocated_path = NULL;
+ const char *module_path = NULL;
+ char *merged_path = NULL;
const char *load_dir = ossl_safe_getenv("OPENSSL_MODULES");
if ((prov->module = DSO_new()) == NULL) {
DSO_ctrl(prov->module, DSO_CTRL_SET_FLAGS,
DSO_FLAG_NAME_TRANSLATION_EXT_ONLY, NULL);
- if ((platform_module_name =
- DSO_convert_filename(prov->module, prov->name)) == NULL
- || (module_path =
- DSO_merge(prov->module, platform_module_name,
- load_dir)) == NULL
- || DSO_load(prov->module, module_path, NULL,
- DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == NULL) {
+
+ module_path = prov->path;
+ if (module_path == NULL)
+ module_path = allocated_path =
+ DSO_convert_filename(prov->module, prov->name);
+ if (module_path != NULL)
+ merged_path = DSO_merge(prov->module, module_path, load_dir);
+
+ if (merged_path == NULL
+ || (DSO_load(prov->module, merged_path, NULL, 0)) == NULL) {
DSO_free(prov->module);
prov->module = NULL;
}
- OPENSSL_free(platform_module_name);
- OPENSSL_free(module_path);
+ OPENSSL_free(merged_path);
+ OPENSSL_free(allocated_path);
}
if (prov->module != NULL)
static int core_get_params(const OSSL_PROVIDER *prov, const OSSL_PARAM params[])
{
int i;
+ const OSSL_PARAM *p;
- for (i = 0; params[i].key != NULL; i++) {
- if (strcmp(params[i].key, "openssl-version") == 0) {
- *(void **)params[i].data = OPENSSL_VERSION_STR;
- if (params[i].return_size)
- *params[i].return_size = sizeof(OPENSSL_VERSION_STR);
- } else if (strcmp(params[i].key, "provider-name") == 0) {
- *(void **)params[i].data = prov->name;
- if (params[i].return_size)
- *params[i].return_size = strlen(prov->name) + 1;
- }
+ if ((p = OSSL_PARAM_locate(params, "openssl-version")) != NULL)
+ OSSL_PARAM_set_utf8_ptr(p, OPENSSL_VERSION_STR);
+ if ((p = OSSL_PARAM_locate(params, "provider-name")) != NULL)
+ OSSL_PARAM_set_utf8_ptr(p, prov->name);
+
+ if (prov->parameters == NULL)
+ return 1;
+
+ for (i = 0; i < sk_INFOPAIR_num(prov->parameters); i++) {
+ INFOPAIR *pair = sk_INFOPAIR_value(prov->parameters, i);
+
+ if ((p = OSSL_PARAM_locate(params, pair->name)) != NULL)
+ OSSL_PARAM_set_utf8_ptr(p, pair->value);
}
return 1;