Documentation: add provider-base(7), describing the base functions
authorRichard Levitte <levitte@openssl.org>
Thu, 18 Jul 2019 13:07:13 +0000 (15:07 +0200)
committerRichard Levitte <levitte@openssl.org>
Mon, 22 Jul 2019 14:42:19 +0000 (16:42 +0200)
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 <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9409)

doc/man7/provider-base.pod [new file with mode: 0644]

diff --git a/doc/man7/provider-base.pod b/doc/man7/provider-base.pod
new file mode 100644 (file)
index 0000000..e8e5d28
--- /dev/null
@@ -0,0 +1,464 @@
+=pod
+
+=head1 NAME
+
+provider-base
+- The basic OpenSSL library E<lt>-E<gt> provider functions
+
+=head1 SYNOPSIS
+
+ #include <openssl/core_numbers.h>
+
+ /*
+  * 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<libcrypto> and the provider in B<OSSL_DISPATCH> arrays, in the call
+of the provider initialization function.  See L<provider(7)/Provider>
+for a description of the initialization function.
+
+All these "functions" have a corresponding function type definition
+named B<OSSL_{name}_fn>, and a helper function to retrieve the
+function pointer from a B<OSSL_DISPATCH> element named
+B<OSSL_get_{name}>.
+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<OSSL_DISPATCH> arrays are indexed by numbers that are provided as
+macros in L<openssl-core_numbers.h(7)>, as follows:
+
+For I<in> (the B<OSSL_DISPATCH> array passed from F<libcrypto> 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<OSSL_DISPATCH> array passed from the provider to
+F<libcrypto>):
+
+ 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<OSSL_PARAM>, for parameters that core_get_params() can handle.
+
+core_get_params() retrieves I<prov> parameters from the core.
+See L</Core parameters> 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<prov>.
+The I<reason> is a number defined by the provider and used to index
+the reason strings table that's returned by
+provider_get_reason_strings().
+I<file> and I<line> may also be passed to indicate exactly where the
+error occured or was reported.
+This corresponds to the OpenSSL function L<ERR_put_error(3)>.
+
+core_add_error_vdata() is used to add additional text data to an
+error already reported with core_put_error().
+It takes I<num> strings in a B<va_list> 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<OSSL_PROVIDER> object I<prov> 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<OSSL_DISPATCH> 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<provctx>.
+
+provider_get_param_types() should return a constant array of
+descriptor B<OSSL_PARAM>, for parameters that provider_get_params()
+can handle.
+
+provider_get_params() should process the B<OSSL_PARAM> array
+I<params>, setting the values of the parameters it understands.
+
+provider_query_operation() should return a constant B<OSSL_ALGORITHM>
+that corresponds to the given I<operation_id>.
+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<OSSL_ITEM>
+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<OSSL_PARAM_UTF8_PTR> type of parameter, pointing at the
+OpenSSL libraries' full version string, i.e. the string expanded from
+the macro B<OPENSSL_VERSION_STR>.
+
+=item "provider-name"
+
+This is a B<OSSL_PARAM_UTF8_PTR> 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<OSSL_PARAM(3)> as
+L<OSSL_PARAM_int(3)>.
+
+=head1 EXAMPLES
+
+This is an example of a simple provider made available as a
+dynamically loadable module.
+It implements the fictitious algorithm C<FOO> for the fictitious
+operation C<BAR>.
+
+ #include <malloc.h>
+ #include <openssl/core.h>
+ #include <openssl/core_numbers.h>
+
+ /* 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<openssl/core_numbers.h>:
+
+ #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<provider(7)>
+
+=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<https://www.openssl.org/source/license.html>.
+
+=cut