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 <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/9409)
This commit is contained in:
parent
2cafb1dff3
commit
d4c69c69d1
1 changed files with 464 additions and 0 deletions
464
doc/man7/provider-base.pod
Normal file
464
doc/man7/provider-base.pod
Normal file
|
@ -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
|
Loading…
Reference in a new issue