From d4c69c69d171edb17b4d609c15891a9599809ed0 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Thu, 18 Jul 2019 15:07:13 +0200 Subject: [PATCH] Documentation: add provider-base(7), describing the base functions The base functions are the first tables of function pointers that libcrypto and the provider pass to each other, thereby providing a baseline with which they can communicate further with each other. This also contains an example for a ficticious provider, providing an implement of a fictitious algorithm for a fictitious operation. Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/9409) --- doc/man7/provider-base.pod | 464 +++++++++++++++++++++++++++++++++++++ 1 file changed, 464 insertions(+) create mode 100644 doc/man7/provider-base.pod diff --git a/doc/man7/provider-base.pod b/doc/man7/provider-base.pod new file mode 100644 index 0000000000..e8e5d28560 --- /dev/null +++ b/doc/man7/provider-base.pod @@ -0,0 +1,464 @@ +=pod + +=head1 NAME + +provider-base +- The basic OpenSSL library E-E provider functions + +=head1 SYNOPSIS + + #include + + /* + * None of these are actual functions, but are displayed like this for + * the function signatures for functions that are offered as function + * pointers in OSSL_DISPATCH arrays. + */ + + /* Functions offered by libcrypto to the providers */ + const OSSL_ITEM *core_get_param_types(const OSSL_PROVIDER *prov); + int core_get_params(const OSSL_PROVIDER *prov, OSSL_PARAM params[]); + int core_thread_start(const OSSL_PROVIDER *prov, + OSSL_thread_stop_handler_fn handfn); + void core_put_error(const OSSL_PROVIDER *prov, + uint32_t reason, const char *file, int line); + void core_add_error_vdata(const OSSL_PROVIDER *prov, + int num, va_list args); + OPENSSL_CTX *core_get_library_context(const OSSL_PROVIDER *prov); + + /* + * Some OpenSSL functionality is directly offered to providers via + * dispatch + */ + void *CRYPTO_malloc(size_t num, const char *file, int line); + void *CRYPTO_zalloc(size_t num, const char *file, int line); + void *CRYPTO_memdup(const void *str, size_t siz, + const char *file, int line); + char *CRYPTO_strdup(const char *str, const char *file, int line); + char *CRYPTO_strndup(const char *str, size_t s, + const char *file, int line); + void CRYPTO_free(void *ptr, const char *file, int line); + void CRYPTO_clear_free(void *ptr, size_t num, + const char *file, int line); + void *CRYPTO_realloc(void *addr, size_t num, + const char *file, int line); + void *CRYPTO_clear_realloc(void *addr, size_t old_num, size_t num, + const char *file, int line); + void *CRYPTO_secure_malloc(size_t num, const char *file, int line); + void *CRYPTO_secure_zalloc(size_t num, const char *file, int line); + void CRYPTO_secure_free(void *ptr, const char *file, int line); + void CRYPTO_secure_clear_free(void *ptr, size_t num, + const char *file, int line); + int CRYPTO_secure_allocated(const void *ptr); + void OPENSSL_cleanse(void *ptr, size_t len); + unsigned char *OPENSSL_hexstr2buf(const char *str, long *len); + + /* Functions offered by the provider to libcrypto */ + void provider_teardown(void *provctx); + const OSSL_ITEM *provider_get_param_types(void *provctx); + int provider_get_params(void *provctx, OSSL_PARAM params[]); + const OSSL_ALGORITHM *provider_query_operation(void *provctx, + int operation_id, + const int *no_store); + const OSSL_ITEM *provider_get_reason_strings(void *provctx); + +=head1 DESCRIPTION + +All "functions" mentioned here are passed as function pointers between +F and the provider in B arrays, in the call +of the provider initialization function. See L +for a description of the initialization function. + +All these "functions" have a corresponding function type definition +named B, and a helper function to retrieve the +function pointer from a B element named +B. +For example, the "function" core_get_param_types() has these: + + typedef OSSL_ITEM * + (OSSL_core_get_param_types_fn)(const OSSL_PROVIDER *prov); + static ossl_inline OSSL_NAME_core_get_param_types_fn + OSSL_get_core_get_param_types(const OSSL_DISPATCH *opf); + +B arrays are indexed by numbers that are provided as +macros in L, as follows: + +For I (the B array passed from F to the +provider): + + core_get_param_types OSSL_FUNC_CORE_GET_PARAM_TYPES + core_get_params OSSL_FUNC_CORE_GET_PARAMS + core_thread_start OSSL_FUNC_CORE_THREAD_START + core_put_error OSSL_FUNC_CORE_PUT_ERROR + core_add_error_vdata OSSL_FUNC_CORE_ADD_ERROR_VDATA + core_get_library_context OSSL_FUNC_CORE_GET_LIBRARY_CONTEXT + CRYPTO_malloc OSSL_FUNC_CRYPTO_MALLOC + CRYPTO_zalloc OSSL_FUNC_CRYPTO_ZALLOC + CRYPTO_memdup OSSL_FUNC_CRYPTO_MEMDUP + CRYPTO_strdup OSSL_FUNC_CRYPTO_STRDUP + CRYPTO_strndup OSSL_FUNC_CRYPTO_STRNDUP + CRYPTO_free OSSL_FUNC_CRYPTO_FREE + CRYPTO_clear_free OSSL_FUNC_CRYPTO_CLEAR_FREE + CRYPTO_realloc OSSL_FUNC_CRYPTO_REALLOC + CRYPTO_clear_realloc OSSL_FUNC_CRYPTO_CLEAR_REALLOC + CRYPTO_secure_malloc OSSL_FUNC_CRYPTO_SECURE_MALLOC + CRYPTO_secure_zalloc OSSL_FUNC_CRYPTO_SECURE_ZALLOC + CRYPTO_secure_free OSSL_FUNC_CRYPTO_SECURE_FREE + CRYPTO_secure_clear_free OSSL_FUNC_CRYPTO_SECURE_CLEAR_FREE + CRYPTO_secure_allocated OSSL_FUNC_CRYPTO_SECURE_ALLOCATED + OPENSSL_cleanse OSSL_FUNC_OPENSSL_CLEANSE + OPENSSL_hexstr2buf OSSL_FUNC_OPENSSL_HEXSTR2BUF + +For I<*out> (the B array passed from the provider to +F): + + provider_teardown OSSL_FUNC_PROVIDER_TEARDOWN + provider_get_param_types OSSL_FUNC_PROVIDER_GET_PARAM_TYPES + provider_get_params OSSL_FUNC_PROVIDER_GET_PARAMS + provider_query_operation OSSL_FUNC_PROVIDER_QUERY_OPERATION + provider_get_reason_strings OSSL_FUNC_PROVIDER_GET_REASON_STRINGS + +=head2 Core functions + +core_get_param_types() returns a constant array of descriptor +B, for parameters that core_get_params() can handle. + +core_get_params() retrieves I parameters from the core. +See L below for a description of currently known +parameters. + +=for comment core_thread_start() TBA + +core_put_error() is used to report an error back to the core, with +reference to the provider object I. +The I is a number defined by the provider and used to index +the reason strings table that's returned by +provider_get_reason_strings(). +I and I may also be passed to indicate exactly where the +error occured or was reported. +This corresponds to the OpenSSL function L. + +core_add_error_vdata() is used to add additional text data to an +error already reported with core_put_error(). +It takes I strings in a B and concatenates them. +Provider authors will have to write the corresponding variadic +argument function. + +core_get_library_context() retrieves the library context in which the +B object I is stored. +This may sometimes be useful if the provider wishes to store a +reference to its context in the same library context. + +CRYPTO_malloc(), CRYPTO_zalloc(), CRYPTO_memdup(), CRYPTO_strdup(), +CRYPTO_strndup(), CRYPTO_free(), CRYPTO_clear_free(), +CRYPTO_realloc(), CRYPTO_clear_realloc(), CRYPTO_secure_malloc(), +CRYPTO_secure_zalloc(), CRYPTO_secure_free(), +CRYPTO_secure_clear_free(), CRYPTO_secure_allocated(), +OPENSSL_cleanse(), and OPENSSL_hexstr2buf() correspond exactly to the +public functions with the same name. +As a matter of fact, the pointers in the B array are +direct pointers to those public functions. + +=head2 Provider functions + +provider_teardown() is called when a provider is shut down and removed +from the core's provider store. +It must free the passed I. + +provider_get_param_types() should return a constant array of +descriptor B, for parameters that provider_get_params() +can handle. + +provider_get_params() should process the B array +I, setting the values of the parameters it understands. + +provider_query_operation() should return a constant B +that corresponds to the given I. +It should indicate if the core may store a reference to this array by +setting I<*no_store> to 0 (core may store a reference) or 1 (core may +not store a reference). + +provider_get_reason_strings() should return a constant B +array that provides reason strings for reason codes the provider may +use when reporting errors using core_put_error(). + +None of these functions are mandatory, but a provider is fairly +useless without at least provider_query_operation(), and +provider_get_param_types() is fairly useless if not accompanied by +provider_get_params(). + +=head2 Core parameters + +core_get_params() understands the following known parameters: + +=over 4 + +=item "openssl-version" + +This is a B type of parameter, pointing at the +OpenSSL libraries' full version string, i.e. the string expanded from +the macro B. + +=item "provider-name" + +This is a B type of parameter, pointing at the +OpenSSL libraries' idea of what the calling provider is called. + +=back + +Additionally, provider specific configuration parameters from the +config file are available, in dotted name form. +The dotted name form is a concatenation of section names and final +config command name separated by periods. + +For example, let's say we have the following config example: + + openssl_conf = openssl_init + + [openssl_init] + providers = providers_sect + + [providers_sect] + foo = foo_sect + + [foo_sect] + activate = 1 + data1 = 2 + data2 = str + more = foo_more + + [foo_more] + data3 = foo,bar + +The provider will have these additional parameters available: + +=over 4 + +=item "activate" + +pointing at the string "1" + +=item "data1" + +pointing at the string "2" + +=item "data2" + +pointing at the string "str" + +=item "more.data3" + +pointing at the string "foo,bar" + +=back + +For more information on handling parameters, see L as +L. + +=head1 EXAMPLES + +This is an example of a simple provider made available as a +dynamically loadable module. +It implements the fictitious algorithm C for the fictitious +operation C. + + #include + #include + #include + + /* Errors used in this provider */ + #define E_MALLOC 1 + + static const OSSL_ITEM reasons[] = { + { E_MALLOC, "memory allocation failure" }. + { 0, NULL } /* Termination */ + }; + + /* + * To ensure we get the function signature right, forward declare + * them using function types provided by openssl/core_numbers.h + */ + OSSL_OP_bar_newctx_fn foo_newctx; + OSSL_OP_bar_freectx_fn foo_freectx; + OSSL_OP_bar_init_fn foo_init; + OSSL_OP_bar_update_fn foo_update; + OSSL_OP_bar_final_fn foo_final; + + OSSL_provider_query_operation_fn p_query; + OSSL_provider_get_reason_strings_fn p_reasons; + OSSL_provider_teardown_fn p_teardown; + + OSSL_provider_init_fn OSSL_provider_init; + + OSSL_core_put_error *c_put_error = NULL; + + /* Provider context */ + struct prov_ctx_st { + OSSL_PROVIDER *prov; + } + + /* operation context for the algorithm FOO */ + struct foo_ctx_st { + struct prov_ctx_st *provctx; + int b; + }; + + static void *foo_newctx(void *provctx) + { + struct foo_ctx_st *fooctx = malloc(sizeof(*fooctx)); + + if (fooctx != NULL) + fooctx->provctx = provctx; + else + c_put_error(provctx->prov, E_MALLOC, __FILE__, __LINE__); + return fooctx; + } + + static void foo_freectx(void *fooctx) + { + free(fooctx); + } + + static int foo_init(void *vfooctx) + { + struct foo_ctx_st *fooctx = vfooctx; + + fooctx->b = 0x33; + } + + static int foo_update(void *vfooctx, unsigned char *in, size_t inl) + { + struct foo_ctx_st *fooctx = vfooctx; + + /* did you expect something serious? */ + if (inl == 0) + return 1; + for (; inl-- > 0; in++) + *in ^= fooctx->b; + return 1; + } + + static int foo_final(void *vfooctx) + { + struct foo_ctx_st *fooctx = vfooctx; + + fooctx->b = 0x66; + } + + static const OSSL_DISPATCH foo_fns[] = { + { OSSL_FUNC_BAR_NEWCTX, (void (*)(void))foo_newctx }, + { OSSL_FUNC_BAR_FREECTX, (void (*)(void))foo_freectx }, + { OSSL_FUNC_BAR_INIT, (void (*)(void))foo_init }, + { OSSL_FUNC_BAR_UPDATE, (void (*)(void))foo_update }, + { OSSL_FUNC_BAR_FINAL, (void (*)(void))foo_final }, + { 0, NULL } + }; + + static const OSSL_ALGORITHM bars[] = { + { "FOO", "provider=chumbawamba", foo_fns }, + { NULL, NULL, NULL } + }; + + static const OSSL_ALGORITHM *p_query(void *provctx, int operation_id, + int *no_store) + { + switch (operation_id) { + case OSSL_OP_BAR: + return bars; + } + return NULL; + } + + static const OSSL_ITEM *p_reasons(void *provctx) + { + return reasons; + } + + static void p_teardown(void *provctx) + { + free(provctx); + } + + static const OSSL_DISPATCH prov_fns[] = { + { OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))p_teardown }, + { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))p_query }, + { OSSL_FUNC_PROVIDER_GET_REASON_STRINGS, (void (*)(void))p_reasons }, + { 0, NULL } + }; + + int OSSL_provider_init(const OSSL_PROVIDER *provider, + const OSSL_DISPATCH *in, + const OSSL_DISPATCH **out, + void **provctx) + { + struct prov_ctx_st *pctx = NULL; + + for (; in->function_id != 0; in++) + switch (in->function_id) { + case OSSL_FUNC_CORE_PUT_ERROR: + c_put_error = OSSL_get_core_put_error(in); + break; + } + + *out = prov_fns; + + if ((pctx = malloc(sizeof(*pctx))) == NULL) { + /* + * ALEA IACTA EST, if the core retrieves the reason table + * regardless, that string will be displayed, otherwise not. + */ + c_put_error(provider, E_MALLOC, __FILE__, __LINE__); + return 0; + } + return 1; + } + +This relies on a few things existing in F: + + #define OSSL_OP_BAR 4711 + + #define OSSL_FUNC_BAR_NEWCTX 1 + typedef void *(OSSL_OP_bar_newctx_fn)(void *provctx); + static ossl_inline OSSL_get_bar_newctx(const OSSL_DISPATCH *opf) + { return (OSSL_OP_bar_newctx_fn *)opf->function; } + + #define OSSL_FUNC_BAR_FREECTX 2 + typedef void (OSSL_OP_bar_freectx_fn)(void *ctx); + static ossl_inline OSSL_get_bar_newctx(const OSSL_DISPATCH *opf) + { return (OSSL_OP_bar_freectx_fn *)opf->function; } + + #define OSSL_FUNC_BAR_INIT 3 + typedef void *(OSSL_OP_bar_init_fn)(void *ctx); + static ossl_inline OSSL_get_bar_init(const OSSL_DISPATCH *opf) + { return (OSSL_OP_bar_init_fn *)opf->function; } + + #define OSSL_FUNC_BAR_UPDATE 4 + typedef void *(OSSL_OP_bar_update_fn)(void *ctx, + unsigned char *in, size_t inl); + static ossl_inline OSSL_get_bar_update(const OSSL_DISPATCH *opf) + { return (OSSL_OP_bar_update_fn *)opf->function; } + + #define OSSL_FUNC_BAR_FINAL 5 + typedef void *(OSSL_OP_bar_final_fn)(void *ctx); + static ossl_inline OSSL_get_bar_final(const OSSL_DISPATCH *opf) + { return (OSSL_OP_bar_final_fn *)opf->function; } + +=head1 SEE ALSO + +L + +=head1 HISTORY + +The concept of providers and everything surrounding them was +introduced in OpenSSL 3.0. + +=head1 COPYRIGHT + +Copyright 2019 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 +L. + +=cut -- 2.34.1