diff options
author | Richard Levitte <levitte@openssl.org> | 2020-07-22 22:54:54 +0200 |
---|---|---|
committer | Richard Levitte <levitte@openssl.org> | 2020-08-24 10:02:25 +0200 |
commit | c4fc564d48456be622509886d3ea5618fce2a02e (patch) | |
tree | 0394f0e2a9712e6042ea816304b37e9cbf44b5ec /crypto/store | |
parent | 8704b6bf32ccc24570b57fbdfef685fbd3572635 (diff) |
STORE: Add the base functions to support provider based loaders
This includes fixing a bug that could only be discovered when no
loaders were registered.
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/12512)
Diffstat (limited to 'crypto/store')
-rw-r--r-- | crypto/store/build.info | 2 | ||||
-rw-r--r-- | crypto/store/store_local.h | 39 | ||||
-rw-r--r-- | crypto/store/store_meth.c | 425 | ||||
-rw-r--r-- | crypto/store/store_register.c | 40 |
4 files changed, 486 insertions, 20 deletions
diff --git a/crypto/store/build.info b/crypto/store/build.info index 7d882f313e..338c40efcc 100644 --- a/crypto/store/build.info +++ b/crypto/store/build.info @@ -1,4 +1,4 @@ LIBS=../../libcrypto SOURCE[../../libcrypto]=\ store_err.c store_init.c store_lib.c store_register.c store_strings.c \ - loader_file.c + store_meth.c loader_file.c diff --git a/crypto/store/store_local.h b/crypto/store/store_local.h index 47cba87f86..15d4022856 100644 --- a/crypto/store/store_local.h +++ b/crypto/store/store_local.h @@ -7,7 +7,9 @@ * https://www.openssl.org/source/license.html */ +#include <openssl/core_dispatch.h> #include "internal/thread_once.h" +#include "internal/refcount.h" #include <openssl/dsa.h> #include <openssl/engine.h> #include <openssl/evp.h> @@ -100,6 +102,7 @@ OSSL_STORE_LOADER *ossl_store_unregister_loader_int(const char *scheme); /* loader stuff */ struct ossl_store_loader_st { + /* Legacy stuff */ const char *scheme; ENGINE *engine; OSSL_STORE_open_fn open; @@ -112,6 +115,23 @@ struct ossl_store_loader_st { OSSL_STORE_error_fn error; OSSL_STORE_close_fn close; OSSL_STORE_open_with_libctx_fn open_with_libctx; + + /* Provider stuff */ + OSSL_PROVIDER *prov; + int scheme_id; + const char *propdef; + + CRYPTO_REF_COUNT refcnt; + CRYPTO_RWLOCK *lock; + + OSSL_FUNC_store_open_fn *p_open; + OSSL_FUNC_store_attach_fn *p_attach; + OSSL_FUNC_store_settable_ctx_params_fn *p_settable_ctx_params; + OSSL_FUNC_store_set_ctx_params_fn *p_set_ctx_params; + OSSL_FUNC_store_load_fn *p_load; + OSSL_FUNC_store_eof_fn *p_eof; + OSSL_FUNC_store_close_fn *p_close; + OSSL_FUNC_store_export_object_fn *p_export_object; }; DEFINE_LHASH_OF(OSSL_STORE_LOADER); @@ -125,3 +145,22 @@ void ossl_store_destroy_loaders_int(void); int ossl_store_init_once(void); int ossl_store_file_loader_init(void); + +/*- + * 'file' scheme stuff + * ------------------- + */ + +OSSL_STORE_LOADER_CTX *ossl_store_file_attach_pem_bio_int(BIO *bp); +int ossl_store_file_detach_pem_bio_int(OSSL_STORE_LOADER_CTX *ctx); + +/*- + * Provider stuff + * ------------------- + */ +OSSL_STORE_LOADER *ossl_store_loader_fetch(OPENSSL_CTX *libctx, + const char *scheme, + const char *properties); +OSSL_STORE_LOADER *ossl_store_loader_fetch_by_number(OPENSSL_CTX *libctx, + int scheme_id, + const char *properties); diff --git a/crypto/store/store_meth.c b/crypto/store/store_meth.c new file mode 100644 index 0000000000..6af5ec14f2 --- /dev/null +++ b/crypto/store/store_meth.c @@ -0,0 +1,425 @@ +/* + * Copyright 2020 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/store.h> +#include <openssl/crypto.h> +#include "internal/core.h" +#include "internal/namemap.h" +#include "internal/property.h" +#include "internal/provider.h" +#include "store_local.h" + +int OSSL_STORE_LOADER_up_ref(OSSL_STORE_LOADER *loader) +{ + int ref = 0; + + if (loader->prov != NULL) + CRYPTO_UP_REF(&loader->refcnt, &ref, loader->lock); + return 1; +} + +void OSSL_STORE_LOADER_free(OSSL_STORE_LOADER *loader) +{ + if (loader != NULL && loader->prov != NULL) { + int i; + + CRYPTO_DOWN_REF(&loader->refcnt, &i, loader->lock); + if (i > 0) + return; + ossl_provider_free(loader->prov); + CRYPTO_THREAD_lock_free(loader->lock); + } + OPENSSL_free(loader); +} + +/* + * OSSL_STORE_LOADER_new() expects the scheme as a constant string, + * which we currently don't have, so we need an alternative allocator. + */ +static OSSL_STORE_LOADER *new_loader(OSSL_PROVIDER *prov) +{ + OSSL_STORE_LOADER *loader; + + if ((loader = OPENSSL_zalloc(sizeof(*loader))) == NULL + || (loader->lock = CRYPTO_THREAD_lock_new()) == NULL) { + OPENSSL_free(loader); + return NULL; + } + loader->prov = prov; + ossl_provider_up_ref(prov); + loader->refcnt = 1; + + return loader; +} + +static int up_ref_loader(void *method) +{ + return OSSL_STORE_LOADER_up_ref(method); +} + +static void free_loader(void *method) +{ + OSSL_STORE_LOADER_free(method); +} + +/* Permanent loader method store, constructor and destructor */ +static void loader_store_free(void *vstore) +{ + ossl_method_store_free(vstore); +} + +static void *loader_store_new(OPENSSL_CTX *ctx) +{ + return ossl_method_store_new(ctx); +} + + +static const OPENSSL_CTX_METHOD loader_store_method = { + loader_store_new, + loader_store_free, +}; + +/* Data to be passed through ossl_method_construct() */ +struct loader_data_st { + OPENSSL_CTX *libctx; + OSSL_METHOD_CONSTRUCT_METHOD *mcm; + int scheme_id; /* For get_loader_from_store() */ + const char *scheme; /* For get_loader_from_store() */ + const char *propquery; /* For get_loader_from_store() */ +}; + +/* + * Generic routines to fetch / create OSSL_STORE methods with + * ossl_method_construct() + */ + +/* Temporary loader method store, constructor and destructor */ +static void *alloc_tmp_loader_store(OPENSSL_CTX *ctx) +{ + return ossl_method_store_new(ctx); +} + + static void dealloc_tmp_loader_store(void *store) +{ + if (store != NULL) + ossl_method_store_free(store); +} + +/* Get the permanent loader store */ +static OSSL_METHOD_STORE *get_loader_store(OPENSSL_CTX *libctx) +{ + return openssl_ctx_get_data(libctx, OPENSSL_CTX_STORE_LOADER_STORE_INDEX, + &loader_store_method); +} + +/* Get loader methods from a store, or put one in */ +static void *get_loader_from_store(OPENSSL_CTX *libctx, void *store, + void *data) +{ + struct loader_data_st *methdata = data; + void *method = NULL; + int id; + + if ((id = methdata->scheme_id) == 0) { + OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); + + id = ossl_namemap_name2num(namemap, methdata->scheme); + } + + if (store == NULL + && (store = get_loader_store(libctx)) == NULL) + return NULL; + + if (!ossl_method_store_fetch(store, id, methdata->propquery, &method)) + return NULL; + return method; +} + +static int put_loader_in_store(OPENSSL_CTX *libctx, void *store, + void *method, const OSSL_PROVIDER *prov, + int operation_id, const char *scheme, + const char *propdef, void *unused) +{ + OSSL_NAMEMAP *namemap; + int id; + + if ((namemap = ossl_namemap_stored(libctx)) == NULL + || (id = ossl_namemap_name2num(namemap, scheme)) == 0) + return 0; + + if (store == NULL && (store = get_loader_store(libctx)) == NULL) + return 0; + + return ossl_method_store_add(store, prov, id, propdef, method, + up_ref_loader, free_loader); +} + +static void *loader_from_dispatch(int scheme_id, const OSSL_ALGORITHM *algodef, + OSSL_PROVIDER *prov) +{ + OSSL_STORE_LOADER *loader = NULL; + const OSSL_DISPATCH *fns = algodef->implementation; + + if ((loader = new_loader(prov)) == NULL) + return NULL; + loader->scheme_id = scheme_id; + loader->propdef = algodef->property_definition; + + for (; fns->function_id != 0; fns++) { + switch (fns->function_id) { + case OSSL_FUNC_STORE_OPEN: + if (loader->p_open == NULL) + loader->p_open = OSSL_FUNC_store_open(fns); + break; + case OSSL_FUNC_STORE_ATTACH: + if (loader->p_attach == NULL) + loader->p_attach = OSSL_FUNC_store_attach(fns); + break; + case OSSL_FUNC_STORE_SETTABLE_CTX_PARAMS: + if (loader->p_settable_ctx_params == NULL) + loader->p_settable_ctx_params = + OSSL_FUNC_store_settable_ctx_params(fns); + break; + case OSSL_FUNC_STORE_SET_CTX_PARAMS: + if (loader->p_set_ctx_params == NULL) + loader->p_set_ctx_params = OSSL_FUNC_store_set_ctx_params(fns); + break; + case OSSL_FUNC_STORE_LOAD: + if (loader->p_load == NULL) + loader->p_load = OSSL_FUNC_store_load(fns); + break; + case OSSL_FUNC_STORE_EOF: + if (loader->p_eof == NULL) + loader->p_eof = OSSL_FUNC_store_eof(fns); + break; + case OSSL_FUNC_STORE_CLOSE: + if (loader->p_close == NULL) + loader->p_close = OSSL_FUNC_store_close(fns); + break; + case OSSL_FUNC_STORE_EXPORT_OBJECT: + if (loader->p_export_object == NULL) + loader->p_export_object = OSSL_FUNC_store_export_object(fns); + break; + } + } + + if ((loader->p_open == NULL && loader->p_attach == NULL) + || loader->p_load == NULL + || loader->p_eof == NULL + || loader->p_close == NULL) { + /* Only set_ctx_params is optionaal */ + OSSL_STORE_LOADER_free(loader); + ERR_raise(ERR_LIB_OSSL_STORE, OSSL_STORE_R_LOADER_INCOMPLETE); + return NULL; + } + return loader; +} + +/* + * The core fetching functionality passes the scheme of the implementation. + * This function is responsible to getting an identity number for them, + * then call loader_from_dispatch() with that identity number. + */ +static void *construct_loader(const OSSL_ALGORITHM *algodef, + OSSL_PROVIDER *prov, void *unused) +{ + /* + * This function is only called if get_loader_from_store() returned + * NULL, so it's safe to say that of all the spots to create a new + * namemap entry, this is it. Should the scheme already exist there, we + * know that ossl_namemap_add() will return its corresponding number. + */ + OPENSSL_CTX *libctx = ossl_provider_library_context(prov); + OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); + const char *scheme = algodef->algorithm_names; + int id = ossl_namemap_add_name(namemap, 0, scheme); + void *method = NULL; + + if (id != 0) + method = loader_from_dispatch(id, algodef, prov); + + return method; +} + +/* Intermediary function to avoid ugly casts, used below */ +static void destruct_loader(void *method, void *data) +{ + OSSL_STORE_LOADER_free(method); +} + +/* Fetching support. Can fetch by numeric identity or by scheme */ +static OSSL_STORE_LOADER *inner_loader_fetch(OPENSSL_CTX *libctx, + int id, const char *scheme, + const char *properties) +{ + OSSL_METHOD_STORE *store = get_loader_store(libctx); + OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); + void *method = NULL; + + if (store == NULL || namemap == NULL) + return NULL; + + /* + * If we have been passed neither a scheme_id or a scheme, we have an + * internal programming error. + */ + if (!ossl_assert(id != 0 || scheme != NULL)) + return NULL; + + if (id == 0) + id = ossl_namemap_name2num(namemap, scheme); + + if (id == 0 + || !ossl_method_store_cache_get(store, id, properties, &method)) { + OSSL_METHOD_CONSTRUCT_METHOD mcm = { + alloc_tmp_loader_store, + dealloc_tmp_loader_store, + get_loader_from_store, + put_loader_in_store, + construct_loader, + destruct_loader + }; + struct loader_data_st mcmdata; + + mcmdata.libctx = libctx; + mcmdata.mcm = &mcm; + mcmdata.scheme_id = id; + mcmdata.scheme = scheme; + mcmdata.propquery = properties; + if ((method = ossl_method_construct(libctx, OSSL_OP_STORE, + 0 /* !force_cache */, + &mcm, &mcmdata)) != NULL) { + /* + * If construction did create a method for us, we know that there + * is a correct scheme_id, since those have already been calculated + * in get_loader_from_store() and put_loader_in_store() above. + */ + if (id == 0) + id = ossl_namemap_name2num(namemap, scheme); + ossl_method_store_cache_set(store, id, properties, method, + up_ref_loader, free_loader); + } + } + + return method; +} + +OSSL_STORE_LOADER *OSSL_STORE_LOADER_fetch(const char *scheme, + OPENSSL_CTX *libctx, + const char *properties) +{ + return inner_loader_fetch(libctx, 0, scheme, properties); +} + +OSSL_STORE_LOADER *ossl_store_loader_fetch_by_number(OPENSSL_CTX *libctx, + int scheme_id, + const char *properties) +{ + return inner_loader_fetch(libctx, scheme_id, NULL, properties); +} + +/* + * Library of basic method functions + */ + +const OSSL_PROVIDER *OSSL_STORE_LOADER_provider(const OSSL_STORE_LOADER *loader) +{ + if (!ossl_assert(loader != NULL)) { + ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + return loader->prov; +} + +const char *OSSL_STORE_LOADER_properties(const OSSL_STORE_LOADER *loader) +{ + if (!ossl_assert(loader != NULL)) { + ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + return loader->propdef; +} + +int OSSL_STORE_LOADER_number(const OSSL_STORE_LOADER *loader) +{ + if (!ossl_assert(loader != NULL)) { + ERR_raise(ERR_LIB_OSSL_STORE, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + return loader->scheme_id; +} + +int OSSL_STORE_LOADER_is_a(const OSSL_STORE_LOADER *loader, const char *name) +{ + if (loader->prov != NULL) { + OPENSSL_CTX *libctx = ossl_provider_library_context(loader->prov); + OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); + + return ossl_namemap_name2num(namemap, name) == loader->scheme_id; + } + return 0; +} + +struct loader_do_all_data_st { + void (*user_fn)(void *method, void *arg); + void *user_arg; +}; + +static void loader_do_one(OSSL_PROVIDER *provider, + const OSSL_ALGORITHM *algodef, + int no_store, void *vdata) +{ + struct loader_do_all_data_st *data = vdata; + OPENSSL_CTX *libctx = ossl_provider_library_context(provider); + OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); + const char *name = algodef->algorithm_names; + int id = ossl_namemap_add_name(namemap, 0, name); + void *method = NULL; + + if (id != 0) + method = + loader_from_dispatch(id, algodef, provider); + + if (method != NULL) { + data->user_fn(method, data->user_arg); + OSSL_STORE_LOADER_free(method); + } +} + +void OSSL_STORE_LOADER_do_all_provided(OPENSSL_CTX *libctx, + void (*fn)(OSSL_STORE_LOADER *loader, + void *arg), + void *arg) +{ + struct loader_do_all_data_st data; + + data.user_fn = (void (*)(void *, void *))fn; + data.user_arg = arg; + ossl_algorithm_do_all(libctx, OSSL_OP_STORE, NULL, + NULL, loader_do_one, NULL, + &data); +} + +void OSSL_STORE_LOADER_names_do_all(const OSSL_STORE_LOADER *loader, + void (*fn)(const char *name, void *data), + void *data) +{ + if (loader == NULL) + return; + + if (loader->prov != NULL) { + OPENSSL_CTX *libctx = ossl_provider_library_context(loader->prov); + OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); + + ossl_namemap_doall_names(namemap, loader->scheme_id, fn, data); + } +} diff --git a/crypto/store/store_register.c b/crypto/store/store_register.c index f5106f0077..94865ee9e0 100644 --- a/crypto/store/store_register.c +++ b/crypto/store/store_register.c @@ -135,11 +135,6 @@ int OSSL_STORE_LOADER_set_close(OSSL_STORE_LOADER *loader, return 1; } -void OSSL_STORE_LOADER_free(OSSL_STORE_LOADER *loader) -{ - OPENSSL_free(loader); -} - /* * Functions for registering OSSL_STORE_LOADERs */ @@ -157,6 +152,14 @@ static int store_loader_cmp(const OSSL_STORE_LOADER *a, } static LHASH_OF(OSSL_STORE_LOADER) *loader_register = NULL; +static int ossl_store_register_init(void) +{ + if (loader_register == NULL) { + loader_register = lh_OSSL_STORE_LOADER_new(store_loader_hash, + store_loader_cmp); + } + return loader_register != NULL; +} int ossl_store_register_loader_int(OSSL_STORE_LOADER *loader) { @@ -197,12 +200,7 @@ int ossl_store_register_loader_int(OSSL_STORE_LOADER *loader) } CRYPTO_THREAD_write_lock(registry_lock); - if (loader_register == NULL) { - loader_register = lh_OSSL_STORE_LOADER_new(store_loader_hash, - store_loader_cmp); - } - - if (loader_register != NULL + if (ossl_store_register_init() && (lh_OSSL_STORE_LOADER_insert(loader_register, loader) != NULL || lh_OSSL_STORE_LOADER_error(loader_register) == 0)) ok = 1; @@ -240,9 +238,11 @@ const OSSL_STORE_LOADER *ossl_store_get0_loader_int(const char *scheme) } CRYPTO_THREAD_write_lock(registry_lock); - loader = lh_OSSL_STORE_LOADER_retrieve(loader_register, &template); - - if (loader == NULL) { + if (!ossl_store_register_init()) { + OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT, + ERR_R_INTERNAL_ERROR); + } else if ((loader = lh_OSSL_STORE_LOADER_retrieve(loader_register, + &template)) == NULL) { OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_GET0_LOADER_INT, OSSL_STORE_R_UNREGISTERED_SCHEME); ERR_add_error_data(2, "scheme=", scheme); @@ -271,9 +271,11 @@ OSSL_STORE_LOADER *ossl_store_unregister_loader_int(const char *scheme) } CRYPTO_THREAD_write_lock(registry_lock); - loader = lh_OSSL_STORE_LOADER_delete(loader_register, &template); - - if (loader == NULL) { + if (!ossl_store_register_init()) { + OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_UNREGISTER_LOADER_INT, + ERR_R_INTERNAL_ERROR); + } else if ((loader = lh_OSSL_STORE_LOADER_delete(loader_register, + &template)) == NULL) { OSSL_STOREerr(OSSL_STORE_F_OSSL_STORE_UNREGISTER_LOADER_INT, OSSL_STORE_R_UNREGISTERED_SCHEME); ERR_add_error_data(2, "scheme=", scheme); @@ -292,7 +294,6 @@ OSSL_STORE_LOADER *OSSL_STORE_unregister_loader(const char *scheme) void ossl_store_destroy_loaders_int(void) { - assert(lh_OSSL_STORE_LOADER_num_items(loader_register) == 0); lh_OSSL_STORE_LOADER_free(loader_register); loader_register = NULL; CRYPTO_THREAD_lock_free(registry_lock); @@ -308,6 +309,7 @@ int OSSL_STORE_do_all_loaders(void (*do_function) (const OSSL_STORE_LOADER *loader, void *do_arg), void *do_arg) { - lh_OSSL_STORE_LOADER_doall_void(loader_register, do_function, do_arg); + if (ossl_store_register_init()) + lh_OSSL_STORE_LOADER_doall_void(loader_register, do_function, do_arg); return 1; } |