SOURCE[../libcrypto]=$UTIL_COMMON \
mem.c mem_sec.c \
cversion.c info.c cpt_err.c ebcdic.c uid.c o_time.c o_dir.c \
- o_fopen.c getenv.c o_init.c init.c trace.c provider.c \
+ o_fopen.c getenv.c o_init.c init.c trace.c provider.c provider_child.c \
punycode.c
SOURCE[../providers/libfips.a]=$UTIL_COMMON
#include "internal/property.h"
#include "internal/core.h"
#include "internal/bio.h"
+#include "internal/provider.h"
struct ossl_lib_ctx_onfree_list_st {
ossl_lib_ctx_onfree_fn *fn;
int run_once_done[OSSL_LIB_CTX_MAX_RUN_ONCE];
int run_once_ret[OSSL_LIB_CTX_MAX_RUN_ONCE];
struct ossl_lib_ctx_onfree_list_st *onfreelist;
+ unsigned int ischild:1;
};
int ossl_lib_ctx_write_lock(OSSL_LIB_CTX *ctx)
return CRYPTO_THREAD_unlock(ossl_lib_ctx_get_concrete(ctx)->lock);
}
+int ossl_lib_ctx_is_child(OSSL_LIB_CTX *ctx)
+{
+ ctx = ossl_lib_ctx_get_concrete(ctx);
+
+ if (ctx == NULL)
+ return 0;
+ return ctx->ischild;
+}
+
static int context_init(OSSL_LIB_CTX *ctx)
{
size_t i;
}
#ifndef FIPS_MODULE
-OSSL_LIB_CTX *OSSL_LIB_CTX_new_from_dispatch(const OSSL_DISPATCH *in)
+OSSL_LIB_CTX *OSSL_LIB_CTX_new_from_dispatch(const OSSL_CORE_HANDLE *handle,
+ const OSSL_DISPATCH *in)
{
OSSL_LIB_CTX *ctx = OSSL_LIB_CTX_new();
return ctx;
}
+OSSL_LIB_CTX *OSSL_LIB_CTX_new_child(const OSSL_CORE_HANDLE *handle,
+ const OSSL_DISPATCH *in)
+{
+ OSSL_LIB_CTX *ctx = OSSL_LIB_CTX_new_from_dispatch(handle, in);
+
+ if (ctx == NULL)
+ return NULL;
+
+ if (!ossl_provider_init_as_child(ctx, handle, in)) {
+ OSSL_LIB_CTX_free(ctx);
+ return NULL;
+ }
+ ctx->ischild = 1;
+
+ return ctx;
+}
+
int OSSL_LIB_CTX_load_config(OSSL_LIB_CTX *ctx, const char *config_file)
{
return CONF_modules_load_file_ex(ctx, config_file, NULL, 0) > 0;
return ossl_provider_prov_ctx(prov);
}
+const OSSL_DISPATCH *OSSL_PROVIDER_get0_dispatch(const OSSL_PROVIDER *prov)
+{
+ return ossl_provider_get0_dispatch(prov);
+}
+
int OSSL_PROVIDER_self_test(const OSSL_PROVIDER *prov)
{
return ossl_provider_self_test(prov);
--- /dev/null
+/*
+ * Copyright 2019-2021 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/crypto.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/provider.h>
+#include "internal/provider.h"
+#include "internal/cryptlib.h"
+
+DEFINE_STACK_OF(OSSL_PROVIDER)
+
+struct child_prov_globals {
+ const OSSL_CORE_HANDLE *handle;
+ OSSL_CORE_PROVIDER *curr_prov;
+ STACK_OF(OSSL_PROVIDER) *childprovs;
+ unsigned int isinited:1;
+ CRYPTO_RWLOCK *lock;
+ OSSL_FUNC_core_get_libctx_fn *c_get_libctx;
+ OSSL_FUNC_core_provider_do_all_fn *c_prov_do_all;
+ OSSL_FUNC_core_provider_name_fn *c_prov_name;
+ OSSL_FUNC_core_provider_get0_provider_ctx_fn *c_prov_get0_provider_ctx;
+ OSSL_FUNC_core_provider_get0_dispatch_fn *c_prov_get0_dispatch;
+};
+
+static void *child_prov_ossl_ctx_new(OSSL_LIB_CTX *libctx)
+{
+ return OPENSSL_zalloc(sizeof(struct child_prov_globals));
+}
+
+/* Wrapper with a void return type for use with sk_OSSL_PROVIDER_pop_free */
+static void ossl_prov_free(OSSL_PROVIDER *prov)
+{
+ OSSL_PROVIDER_unload(prov);
+}
+
+static void child_prov_ossl_ctx_free(void *vgbl)
+{
+ struct child_prov_globals *gbl = vgbl;
+
+ sk_OSSL_PROVIDER_pop_free(gbl->childprovs, ossl_prov_free);
+ CRYPTO_THREAD_lock_free(gbl->lock);
+ OPENSSL_free(gbl);
+}
+
+static const OSSL_LIB_CTX_METHOD child_prov_ossl_ctx_method = {
+ OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
+ child_prov_ossl_ctx_new,
+ child_prov_ossl_ctx_free,
+};
+
+static OSSL_provider_init_fn ossl_child_provider_init;
+
+static int ossl_child_provider_init(const OSSL_CORE_HANDLE *handle,
+ const OSSL_DISPATCH *in,
+ const OSSL_DISPATCH **out,
+ void **provctx)
+{
+ OSSL_FUNC_core_get_libctx_fn *c_get_libctx = NULL;
+ OSSL_LIB_CTX *ctx;
+ struct child_prov_globals *gbl;
+
+ for (; in->function_id != 0; in++) {
+ switch (in->function_id) {
+ case OSSL_FUNC_CORE_GET_LIBCTX:
+ c_get_libctx = OSSL_FUNC_core_get_libctx(in);
+ break;
+ default:
+ /* Just ignore anything we don't understand */
+ break;
+ }
+ }
+
+ if (c_get_libctx == NULL)
+ return 0;
+
+ /*
+ * We need an OSSL_LIB_CTX but c_get_libctx returns OPENSSL_CORE_CTX. We are
+ * a built-in provider and so we can get away with this cast. Normal
+ * providers can't do this.
+ */
+ ctx = (OSSL_LIB_CTX *)c_get_libctx(handle);
+
+ gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX,
+ &child_prov_ossl_ctx_method);
+ if (gbl == NULL)
+ return 0;
+
+ *provctx = gbl->c_prov_get0_provider_ctx(gbl->curr_prov);
+ *out = gbl->c_prov_get0_dispatch(gbl->curr_prov);
+
+ return 1;
+}
+
+static int provider_create_child_cb(OSSL_CORE_PROVIDER *prov, void *cbdata)
+{
+ OSSL_LIB_CTX *ctx = cbdata;
+ struct child_prov_globals *gbl;
+ const char *provname;
+ OSSL_PROVIDER *cprov;
+
+ gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX,
+ &child_prov_ossl_ctx_method);
+ if (gbl == NULL)
+ return 0;
+
+ provname = gbl->c_prov_name(prov);
+
+ /*
+ * We're operating under a lock so we can store the "current" provider in
+ * the global data.
+ */
+ gbl->curr_prov = prov;
+
+ /*
+ * Create it - passing 1 as final param so we don't try and recursively init
+ * children
+ */
+ if ((cprov = ossl_provider_new(ctx, provname, ossl_child_provider_init,
+ 1)) == NULL)
+ return 0;
+
+ if (!ossl_provider_activate(cprov, 0)) {
+ ossl_provider_free(cprov);
+ return 0;
+ }
+ ossl_provider_set_child(cprov);
+
+ if (!sk_OSSL_PROVIDER_push(gbl->childprovs, cprov)) {
+ OSSL_PROVIDER_unload(cprov);
+ return 0;
+ }
+
+ return 1;
+}
+
+int ossl_provider_init_child_providers(OSSL_LIB_CTX *ctx)
+{
+ struct child_prov_globals *gbl;
+
+ /* Should never happen */
+ if (ctx == NULL)
+ return 0;
+
+ gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX,
+ &child_prov_ossl_ctx_method);
+ if (gbl == NULL)
+ return 0;
+
+ if (!CRYPTO_THREAD_read_lock(gbl->lock))
+ return 0;
+ if (gbl->isinited) {
+ CRYPTO_THREAD_unlock(gbl->lock);
+ return 1;
+ }
+ CRYPTO_THREAD_unlock(gbl->lock);
+
+ if (!CRYPTO_THREAD_write_lock(gbl->lock))
+ return 0;
+ if (!gbl->isinited) {
+ if (!gbl->c_prov_do_all(gbl->c_get_libctx(gbl->handle),
+ provider_create_child_cb, ctx)) {
+ CRYPTO_THREAD_unlock(gbl->lock);
+ return 0;
+ }
+ gbl->isinited = 1;
+ }
+ CRYPTO_THREAD_unlock(gbl->lock);
+
+ return 1;
+}
+
+int ossl_provider_init_as_child(OSSL_LIB_CTX *ctx,
+ const OSSL_CORE_HANDLE *handle,
+ const OSSL_DISPATCH *in)
+{
+ struct child_prov_globals *gbl;
+
+ if (ctx == NULL)
+ return 0;
+
+ gbl = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_CHILD_PROVIDER_INDEX,
+ &child_prov_ossl_ctx_method);
+ if (gbl == NULL)
+ return 0;
+
+ gbl->handle = handle;
+ for (; in->function_id != 0; in++) {
+ switch (in->function_id) {
+ case OSSL_FUNC_CORE_GET_LIBCTX:
+ gbl->c_get_libctx = OSSL_FUNC_core_get_libctx(in);
+ break;
+ case OSSL_FUNC_CORE_PROVIDER_DO_ALL:
+ gbl->c_prov_do_all = OSSL_FUNC_core_provider_do_all(in);
+ break;
+ case OSSL_FUNC_CORE_PROVIDER_NAME:
+ gbl->c_prov_name = OSSL_FUNC_core_provider_name(in);
+ break;
+ case OSSL_FUNC_CORE_PROVIDER_GET0_PROVIDER_CTX:
+ gbl->c_prov_get0_provider_ctx
+ = OSSL_FUNC_core_provider_get0_provider_ctx(in);
+ break;
+ case OSSL_FUNC_CORE_PROVIDER_GET0_DISPATCH:
+ gbl->c_prov_get0_dispatch = OSSL_FUNC_core_provider_get0_dispatch(in);
+ break;
+ default:
+ /* Just ignore anything we don't understand */
+ break;
+ }
+ }
+
+ if (gbl->c_prov_do_all == NULL
+ || gbl->c_prov_name == NULL
+ || gbl->c_prov_get0_provider_ctx == NULL
+ || gbl->c_prov_get0_dispatch == NULL)
+ return 0;
+
+ gbl->childprovs = sk_OSSL_PROVIDER_new_null();
+ if (gbl->childprovs == NULL)
+ return 0;
+ gbl->lock = CRYPTO_THREAD_lock_new();
+ if (gbl->lock == NULL)
+ return 0;
+
+ return 1;
+}
#include "internal/provider.h"
#include "internal/refcount.h"
#include "internal/bio.h"
+#include "internal/core.h"
#include "provider_local.h"
#ifndef FIPS_MODULE
# include <openssl/self_test.h>
size_t operation_bits_sz;
CRYPTO_RWLOCK *opbits_lock;
+ /* Whether this provider is the child of some other provider */
+ unsigned int ischild:1;
+
/* Provider side data */
void *provctx;
+ const OSSL_DISPATCH *dispatch;
};
DEFINE_STACK_OF(OSSL_PROVIDER)
* Make sure any providers are loaded from config before we try to find
* them.
*/
- if (!noconfig && ossl_lib_ctx_is_default(libctx))
- OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
+ if (!noconfig) {
+ if (ossl_lib_ctx_is_default(libctx))
+ OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
+ if (ossl_lib_ctx_is_child(libctx)
+ && !ossl_provider_init_child_providers(libctx))
+ return NULL;
+ }
#endif
tmpl.name = (char *)name;
*/
if (ref == 0) {
if (prov->flag_initialized) {
- if (prov->teardown != NULL)
- prov->teardown(prov->provctx);
+ ossl_provider_teardown(prov);
#ifndef OPENSSL_NO_ERR
# ifndef FIPS_MODULE
if (prov->error_strings != NULL) {
goto end;
}
prov->provctx = tmp_provctx;
+ prov->dispatch = provider_dispatch;
for (; provider_dispatch->function_id != 0; provider_dispatch++) {
switch (provider_dispatch->function_id) {
*/
if (ossl_lib_ctx_is_default(ctx))
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
+ if (ossl_lib_ctx_is_child(ctx)
+ && !ossl_provider_init_child_providers(ctx))
+ return 0;
#endif
if (store == NULL)
return NULL;
}
+const OSSL_DISPATCH *ossl_provider_get0_dispatch(const OSSL_PROVIDER *prov)
+{
+ if (prov != NULL)
+ return prov->dispatch;
+
+ return NULL;
+}
+
OSSL_LIB_CTX *ossl_provider_libctx(const OSSL_PROVIDER *prov)
{
return prov != NULL ? prov->libctx : NULL;
/* Wrappers around calls to the provider */
void ossl_provider_teardown(const OSSL_PROVIDER *prov)
{
- if (prov->teardown != NULL)
+ if (prov->teardown != NULL && !prov->ischild)
prov->teardown(prov->provctx);
}
return 1;
}
+void ossl_provider_set_child(OSSL_PROVIDER *prov)
+{
+ prov->ischild = 1;
+}
+
/*-
* Core functions for the provider
* ===============================
{ OSSL_FUNC_CRYPTO_SECURE_ALLOCATED,
(void (*)(void))CRYPTO_secure_allocated },
{ OSSL_FUNC_OPENSSL_CLEANSE, (void (*)(void))OPENSSL_cleanse },
-
+#ifndef FIPS_MODULE
+ { OSSL_FUNC_CORE_PROVIDER_DO_ALL, (void (*)(void))OSSL_PROVIDER_do_all },
+ { OSSL_FUNC_CORE_PROVIDER_NAME,
+ (void (*)(void))OSSL_PROVIDER_name },
+ { OSSL_FUNC_CORE_PROVIDER_GET0_PROVIDER_CTX,
+ (void (*)(void))OSSL_PROVIDER_get0_provider_ctx },
+ { OSSL_FUNC_CORE_PROVIDER_GET0_DISPATCH,
+ (void (*)(void))OSSL_PROVIDER_get0_dispatch },
+#endif
{ 0, NULL }
};
static const OSSL_DISPATCH *core_dispatch = core_dispatch_;
typedef struct ossl_lib_ctx_st OSSL_LIB_CTX;
OSSL_LIB_CTX *OSSL_LIB_CTX_new(void);
- OSSL_LIB_CTX *OSSL_LIB_CTX_new_from_dispatch(const OSSL_DISPATCH *in);
+ OSSL_LIB_CTX *OSSL_LIB_CTX_new_from_dispatch(const OSSL_CORE_HANDLE *handle,
+ const OSSL_DISPATCH *in);
int OSSL_LIB_CTX_load_config(OSSL_LIB_CTX *ctx, const char *config_file);
void OSSL_LIB_CTX_free(OSSL_LIB_CTX *ctx);
OSSL_LIB_CTX *OSSL_LIB_CTX_get0_global_default(void);
OSSL_LIB_CTX_new_from_dispatch() creates a new OpenSSL library context
initialised to use callbacks from the OSSL_DISPATCH structure. This is primarily
-useful for provider authors. The dispatch structure passed should be the same
-one as passed to a provider's OSSL_provider_init function in the I<in> argument.
-Some OpenSSL functions, such as L<BIO_new_from_core_bio(3)>, require the library
-context to be created in this way in order to work.
+useful for provider authors. The I<handle> and dispatch structure arguments
+passed should be the same ones as passed to a provider's
+OSSL_provider_init function. Some OpenSSL functions, such as
+L<BIO_new_from_core_bio(3)>, require the library context to be created in this
+way in order to work.
OSSL_LIB_CTX_load_config() loads a configuration file using the given C<ctx>.
This can be used to associate a library context with providers that are loaded
__owur int ossl_lib_ctx_write_lock(OSSL_LIB_CTX *ctx);
__owur int ossl_lib_ctx_read_lock(OSSL_LIB_CTX *ctx);
int ossl_lib_ctx_unlock(OSSL_LIB_CTX *ctx);
+int ossl_lib_ctx_is_child(OSSL_LIB_CTX *ctx);
#endif
# define OSSL_LIB_CTX_STORE_LOADER_STORE_INDEX 15
# define OSSL_LIB_CTX_PROVIDER_CONF_INDEX 16
# define OSSL_LIB_CTX_BIO_CORE_INDEX 17
-# define OSSL_LIB_CTX_MAX_INDEXES 18
+# define OSSL_LIB_CTX_CHILD_PROVIDER_INDEX 18
+# define OSSL_LIB_CTX_MAX_INDEXES 19
# define OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY 0
# define OSSL_LIB_CTX_METHOD_HIGH_PRIORITY 1
int ossl_provider_set_module_path(OSSL_PROVIDER *prov, const char *module_path);
int ossl_provider_add_parameter(OSSL_PROVIDER *prov, const char *name,
const char *value);
+void ossl_provider_set_child(OSSL_PROVIDER *prov);
/* Disable fallback loading */
int ossl_provider_disable_fallback_loading(OSSL_LIB_CTX *libctx);
const char *ossl_provider_module_name(const OSSL_PROVIDER *prov);
const char *ossl_provider_module_path(const OSSL_PROVIDER *prov);
void *ossl_provider_prov_ctx(const OSSL_PROVIDER *prov);
+const OSSL_DISPATCH *ossl_provider_get0_dispatch(const OSSL_PROVIDER *prov);
OSSL_LIB_CTX *ossl_provider_libctx(const OSSL_PROVIDER *prov);
/* Thin wrappers around calls to the provider */
/* Configuration */
void ossl_provider_add_conf_module(void);
+/* Child providers */
+int ossl_provider_init_child_providers(OSSL_LIB_CTX *ctx);
+int ossl_provider_init_as_child(OSSL_LIB_CTX *ctx,
+ const OSSL_CORE_HANDLE *handle,
+ const OSSL_DISPATCH *in);
+
# ifdef __cplusplus
}
# endif
typedef struct ossl_core_handle_st OSSL_CORE_HANDLE;
typedef struct openssl_core_ctx_st OPENSSL_CORE_CTX;
typedef struct ossl_core_bio_st OSSL_CORE_BIO;
+typedef struct ossl_core_provider_st OSSL_CORE_PROVIDER;
/*
* Dispatch table element. function_id numbers and the functions are defined
OSSL_CORE_MAKE_FUNC(void, cleanup_nonce, (const OSSL_CORE_HANDLE *handle,
unsigned char *buf, size_t len))
+/* Functions to access the core's providers */
+#define OSSL_FUNC_CORE_PROVIDER_DO_ALL 105
+#define OSSL_FUNC_CORE_PROVIDER_NAME 106
+#define OSSL_FUNC_CORE_PROVIDER_GET0_PROVIDER_CTX 107
+#define OSSL_FUNC_CORE_PROVIDER_GET0_DISPATCH 108
+
+OSSL_CORE_MAKE_FUNC(int, core_provider_do_all, (const OPENSSL_CORE_CTX *ctx,
+ int (*cb)(OSSL_CORE_PROVIDER *provider,
+ void *cbdata),
+ void *cbdata))
+OSSL_CORE_MAKE_FUNC(const char *, core_provider_name,
+ (const OSSL_CORE_PROVIDER *prov))
+OSSL_CORE_MAKE_FUNC(void *, core_provider_get0_provider_ctx,
+ (const OSSL_CORE_PROVIDER *prov))
+OSSL_CORE_MAKE_FUNC(const OSSL_DISPATCH *, core_provider_get0_dispatch,
+ (const OSSL_CORE_PROVIDER *prov))
+
/* Functions provided by the provider to the Core, reserved numbers 1024-1535 */
# define OSSL_FUNC_PROVIDER_TEARDOWN 1024
OSSL_CORE_MAKE_FUNC(void,provider_teardown,(void *provctx))
# include <openssl/types.h>
# include <openssl/opensslconf.h>
# include <openssl/cryptoerr.h>
+# include <openssl/core.h>
# ifdef CHARSET_EBCDIC
# include <openssl/ebcdic.h>
int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b);
OSSL_LIB_CTX *OSSL_LIB_CTX_new(void);
-OSSL_LIB_CTX *OSSL_LIB_CTX_new_from_dispatch(const OSSL_DISPATCH *in);
+OSSL_LIB_CTX *OSSL_LIB_CTX_new_from_dispatch(const OSSL_CORE_HANDLE *handle,
+ const OSSL_DISPATCH *in);
+OSSL_LIB_CTX *OSSL_LIB_CTX_new_child(const OSSL_CORE_HANDLE *handle,
+ const OSSL_DISPATCH *in);
int OSSL_LIB_CTX_load_config(OSSL_LIB_CTX *ctx, const char *config_file);
void OSSL_LIB_CTX_free(OSSL_LIB_CTX *);
OSSL_LIB_CTX *OSSL_LIB_CTX_get0_global_default(void);
void OSSL_PROVIDER_unquery_operation(const OSSL_PROVIDER *prov,
int operation_id, const OSSL_ALGORITHM *algs);
void *OSSL_PROVIDER_get0_provider_ctx(const OSSL_PROVIDER *prov);
+const OSSL_DISPATCH *OSSL_PROVIDER_get0_dispatch(const OSSL_PROVIDER *prov);
/* Add a built in providers */
int OSSL_PROVIDER_add_builtin(OSSL_LIB_CTX *, const char *name,
static int test_bio_core(void)
{
BIO *cbio = NULL, *cbiobad = NULL;
- OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new_from_dispatch(biocbs);
+ OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new_from_dispatch(NULL, biocbs);
int testresult = 0;
OSSL_CORE_BIO corebio;
const char *msg = "Hello world";
BIO_new_ex ? 3_0_0 EXIST::FUNCTION:
BIO_s_core ? 3_0_0 EXIST::FUNCTION:
OSSL_LIB_CTX_new_from_dispatch ? 3_0_0 EXIST::FUNCTION:
+OSSL_LIB_CTX_new_child ? 3_0_0 EXIST::FUNCTION:
+OSSL_PROVIDER_get0_dispatch ? 3_0_0 EXIST::FUNCTION: