OpenSSL

密码学和 SSL/TLS 工具包

provider-base

名称

provider-base - OpenSSL 库 <-> 提供程序函数的基本功能

概要

#include <openssl/core_dispatch.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_gettable_params(const OSSL_CORE_HANDLE *handle);
int core_get_params(const OSSL_CORE_HANDLE *handle, OSSL_PARAM params[]);

typedef void (*OSSL_thread_stop_handler_fn)(void *arg);
int core_thread_start(const OSSL_CORE_HANDLE *handle,
                      OSSL_thread_stop_handler_fn handfn,
                      void *arg);

OPENSSL_CORE_CTX *core_get_libctx(const OSSL_CORE_HANDLE *handle);
void core_new_error(const OSSL_CORE_HANDLE *handle);
void core_set_error_debug(const OSSL_CORE_HANDLE *handle,
                          const char *file, int line, const char *func);
void core_vset_error(const OSSL_CORE_HANDLE *handle,
                     uint32_t reason, const char *fmt, va_list args);

int core_obj_add_sigid(const OSSL_CORE_HANDLE *prov, const char  *sign_name,
                       const char *digest_name, const char *pkey_name);
int core_obj_create(const OSSL_CORE_HANDLE *handle, const char *oid,
                    const char *sn, const char *ln);

/*
 * 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_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 *buflen);

OSSL_CORE_BIO *BIO_new_file(const char *filename, const char *mode);
OSSL_CORE_BIO *BIO_new_membuf(const void *buf, int len);
int BIO_read_ex(OSSL_CORE_BIO *bio, void *data, size_t data_len,
                size_t *bytes_read);
int BIO_write_ex(OSSL_CORE_BIO *bio, const void *data, size_t data_len,
                 size_t *written);
int BIO_up_ref(OSSL_CORE_BIO *bio);
int BIO_free(OSSL_CORE_BIO *bio);
int BIO_vprintf(OSSL_CORE_BIO *bio, const char *format, va_list args);
int BIO_vsnprintf(char *buf, size_t n, const char *fmt, va_list args);

void OSSL_SELF_TEST_set_callback(OSSL_LIB_CTX *libctx, OSSL_CALLBACK *cb,
                                 void *cbarg);

size_t get_entropy(const OSSL_CORE_HANDLE *handle,
                   unsigned char **pout, int entropy,
                   size_t min_len, size_t max_len);
size_t get_user_entropy(const OSSL_CORE_HANDLE *handle,
                        unsigned char **pout, int entropy,
                        size_t min_len, size_t max_len);
void cleanup_entropy(const OSSL_CORE_HANDLE *handle,
                     unsigned char *buf, size_t len);
void cleanup_user_entropy(const OSSL_CORE_HANDLE *handle,
                          unsigned char *buf, size_t len);
size_t get_nonce(const OSSL_CORE_HANDLE *handle,
                 unsigned char **pout, size_t min_len, size_t max_len,
                 const void *salt, size_t salt_len);
size_t get_user_nonce(const OSSL_CORE_HANDLE *handle,
                      unsigned char **pout, size_t min_len, size_t max_len,
                      const void *salt, size_t salt_len);
void cleanup_nonce(const OSSL_CORE_HANDLE *handle,
                   unsigned char *buf, size_t len);
void cleanup_user_nonce(const OSSL_CORE_HANDLE *handle,
                        unsigned char *buf, size_t len);

/* Functions for querying the providers in the application library context */
int provider_register_child_cb(const OSSL_CORE_HANDLE *handle,
                    int (*create_cb)(const OSSL_CORE_HANDLE *provider,
                                     void *cbdata),
                    int (*remove_cb)(const OSSL_CORE_HANDLE *provider,
                                     void *cbdata),
                    int (*global_props_cb)(const char *props, void *cbdata),
                    void *cbdata);
void provider_deregister_child_cb(const OSSL_CORE_HANDLE *handle);
const char *provider_name(const OSSL_CORE_HANDLE *prov);
void *provider_get0_provider_ctx(const OSSL_CORE_HANDLE *prov);
const OSSL_DISPATCH *provider_get0_dispatch(const OSSL_CORE_HANDLE *prov);
int provider_up_ref(const OSSL_CORE_HANDLE *prov, int activate);
int provider_free(const OSSL_CORE_HANDLE *prov, int deactivate);

/* Functions offered by the provider to libcrypto */
void provider_teardown(void *provctx);
const OSSL_ITEM *provider_gettable_params(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);
void provider_unquery_operation(void *provctx, int operation_id,
                                const OSSL_ALGORITHM *algs);
const OSSL_ITEM *provider_get_reason_strings(void *provctx);
int provider_get_capabilities(void *provctx, const char *capability,
                              OSSL_CALLBACK *cb, void *arg);
int provider_self_test(void *provctx);

描述

此处提到的所有“函数”都作为函数指针在libcryptoOSSL_DISPATCH(3)数组中的提供程序之间传递,在提供程序初始化函数的调用中。有关初始化函数的说明,请参阅provider(7)中的“提供程序”。它们被称为“上行调用”。

所有这些“函数”都有一个对应的函数类型定义,名为OSSL_FUNC_{name}_fn,以及一个从名为OSSL_FUNC_{name}OSSL_DISPATCH(3)元素中检索函数指针的辅助函数。例如,“函数”core_gettable_params()具有以下内容

typedef OSSL_PARAM *
    (OSSL_FUNC_core_gettable_params_fn)(const OSSL_CORE_HANDLE *handle);
static ossl_inline OSSL_NAME_core_gettable_params_fn
    OSSL_FUNC_core_gettable_params(const OSSL_DISPATCH *opf);

OSSL_DISPATCH(3)数组由数字索引,这些数字作为宏在openssl-core_dispatch.h(7)中提供,如下所示

对于in(从libcrypto传递到提供程序的OSSL_DISPATCH(3)数组)

core_gettable_params           OSSL_FUNC_CORE_GETTABLE_PARAMS
core_get_params                OSSL_FUNC_CORE_GET_PARAMS
core_thread_start              OSSL_FUNC_CORE_THREAD_START
core_get_libctx                OSSL_FUNC_CORE_GET_LIBCTX
core_new_error                 OSSL_FUNC_CORE_NEW_ERROR
core_set_error_debug           OSSL_FUNC_CORE_SET_ERROR_DEBUG
core_vset_error                OSSL_FUNC_CORE_VSET_ERROR
core_obj_add_sigid             OSSL_FUNC_CORE_OBJ_ADD_SIGID
core_obj_create                OSSL_FUNC_CORE_OBJ_CREATE
CRYPTO_malloc                  OSSL_FUNC_CRYPTO_MALLOC
CRYPTO_zalloc                  OSSL_FUNC_CRYPTO_ZALLOC
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
BIO_new_file                   OSSL_FUNC_BIO_NEW_FILE
BIO_new_mem_buf                OSSL_FUNC_BIO_NEW_MEMBUF
BIO_read_ex                    OSSL_FUNC_BIO_READ_EX
BIO_write_ex                   OSSL_FUNC_BIO_WRITE_EX
BIO_up_ref                     OSSL_FUNC_BIO_UP_REF
BIO_free                       OSSL_FUNC_BIO_FREE
BIO_vprintf                    OSSL_FUNC_BIO_VPRINTF
BIO_vsnprintf                  OSSL_FUNC_BIO_VSNPRINTF
BIO_puts                       OSSL_FUNC_BIO_PUTS
BIO_gets                       OSSL_FUNC_BIO_GETS
BIO_ctrl                       OSSL_FUNC_BIO_CTRL
OPENSSL_cleanse                OSSL_FUNC_OPENSSL_CLEANSE
OSSL_SELF_TEST_set_callback    OSSL_FUNC_SELF_TEST_CB
ossl_rand_get_entropy          OSSL_FUNC_GET_ENTROPY
ossl_rand_get_user_entropy     OSSL_FUNC_GET_USER_ENTROPY
ossl_rand_cleanup_entropy      OSSL_FUNC_CLEANUP_ENTROPY
ossl_rand_cleanup_user_entropy OSSL_FUNC_CLEANUP_USER_ENTROPY
ossl_rand_get_nonce            OSSL_FUNC_GET_NONCE
ossl_rand_get_user_nonce       OSSL_FUNC_GET_USER_NONCE
ossl_rand_cleanup_nonce        OSSL_FUNC_CLEANUP_NONCE
ossl_rand_cleanup_user_nonce   OSSL_FUNC_CLEANUP_USER_NONCE
provider_register_child_cb     OSSL_FUNC_PROVIDER_REGISTER_CHILD_CB
provider_deregister_child_cb   OSSL_FUNC_PROVIDER_DEREGISTER_CHILD_CB
provider_name                  OSSL_FUNC_PROVIDER_NAME
provider_get0_provider_ctx     OSSL_FUNC_PROVIDER_GET0_PROVIDER_CTX
provider_get0_dispatch         OSSL_FUNC_PROVIDER_GET0_DISPATCH
provider_up_ref                OSSL_FUNC_PROVIDER_UP_REF
provider_free                  OSSL_FUNC_PROVIDER_FREE

对于*out(从提供程序传递到libcryptoOSSL_DISPATCH(3)数组)

provider_teardown              OSSL_FUNC_PROVIDER_TEARDOWN
provider_gettable_params       OSSL_FUNC_PROVIDER_GETTABLE_PARAMS
provider_get_params            OSSL_FUNC_PROVIDER_GET_PARAMS
provider_query_operation       OSSL_FUNC_PROVIDER_QUERY_OPERATION
provider_unquery_operation     OSSL_FUNC_PROVIDER_UNQUERY_OPERATION
provider_get_reason_strings    OSSL_FUNC_PROVIDER_GET_REASON_STRINGS
provider_get_capabilities      OSSL_FUNC_PROVIDER_GET_CAPABILITIES
provider_self_test             OSSL_FUNC_PROVIDER_SELF_TEST

核心函数

core_gettable_params()返回一个描述符OSSL_PARAM(3)的常量数组,用于core_get_params()可以处理的参数。

core_get_params()从核心为给定的handle检索参数。有关当前已知参数的说明,请参阅下面的“核心参数”

core_thread_start()函数通知核心,提供程序已表示对当前线程感兴趣。核心将在线程最终停止时通知提供程序。它必须传递此提供程序的handle,以及一个回调handfn,该回调将在线程停止时被调用。随后将使用提供的参数arg从停止的线程调用回调,并将提供程序上下文作为参数传递。这可能有助于执行线程特定的清理,例如释放线程局部变量。

core_get_libctx()检索存储当前提供程序库对象的核心的上下文,可以通过handle访问。此函数仅对内置提供程序(如默认提供程序)有用。永远不要将其转换为非内置提供程序中的OSSL_LIB_CTX,因为加载提供程序的库的OSSL_LIB_CTX可能与提供程序链接到的库的OSSL_LIB_CTX完全不同的结构。请改用OSSL_LIB_CTX_new_child(3)获取与应用程序库上下文链接的正确库上下文。

core_new_error()、core_set_error_debug()和core_vset_error()是将错误报告回核心的构建块,并参考handle

core_new_error()

分配一个新的线程特定错误记录。

这对应于OpenSSL函数ERR_new(3)

core_set_error_debug()

在当前线程特定的错误记录中设置调试信息。调试信息包括发生错误的文件file、行line和函数名func

这对应于OpenSSL函数ERR_set_debug(3)

core_vset_error()

设置错误的reason以及任何附加数据。reason是由提供程序定义的数字,用于索引由provider_get_reason_strings()返回的reason字符串表。附加数据作为格式字符串fmt和一组参数args给出,这些参数的处理方式与BIO_vsnprintf()相同。还可以传递fileline以指示错误发生或报告的确切位置。

这对应于OpenSSL函数ERR_vset_error(3)

core_obj_create()函数为给定的handle注册一个新的OID以及关联的短名称sn和长名称ln。它类似于OpenSSL函数OBJ_create(3),不同之处在于它在成功时返回1,在失败时返回0。它将OID已存在的情况视为成功(即使作为参数提供的短名称sn或长名称ln与现有OID关联的名称不同,在这种情况下,新的名称不会关联)。

core_obj_add_sigid()函数为给定的handle注册一个新的复合签名算法(sign_name),该算法由一个底层签名算法(pkey_name)和摘要算法(digest_name)组成。它假设复合签名算法以及底层签名和摘要算法的OID要么已为OpenSSL所知,要么已通过调用core_obj_create()注册。它对应于OpenSSL函数OBJ_add_sigid(3),不同之处在于对象是通过名称而不是数字NID识别的。任何名称(OID、短名称或长名称)都可以用来识别对象。它将复合签名算法已存在的情况视为成功(即使针对不同的底层签名或摘要算法注册)。对于digest_name,对于不需要摘要才能正确运行的签名算法,允许使用NULL或空字符串。该函数在成功时返回1,在失败时返回0。

CRYPTO_malloc()、CRYPTO_zalloc()、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()、BIO_new_file()、BIO_new_mem_buf()、BIO_read_ex()、BIO_write_ex()、BIO_up_ref()、BIO_free()、BIO_vprintf()、BIO_vsnprintf()、BIO_gets()、BIO_puts()、BIO_ctrl()、OPENSSL_cleanse()和OPENSSL_hexstr2buf()完全对应于具有相同名称的公共函数。事实上,OSSL_DISPATCH(3)数组中的指针通常是这些公共函数的直接指针。请注意,BIO函数采用OSSL_CORE_BIO类型而不是标准BIO类型。这是为了确保提供程序不会混合核心中的BIO与提供程序端使用的BIO(两者不兼容)。OSSL_SELF_TEST_set_callback()用于设置可选的回调,该回调可以传递到提供程序中。提供程序可能会忽略此回调。

get_entropy()从操作系统检索种子材料。种子材料将至少具有entropy字节的随机性,输出将至少具有min_len字节,最多具有max_len字节。缓冲区地址存储在*pout中,缓冲区长度返回给调用方。发生错误时,将返回零。

get_user_entropy()与get_entropy()相同,不同之处在于它将尝试通过对RAND_set_seed_source_type(3)的调用或通过config(5)中的“随机配置”指定的种子源收集种子材料。

cleanup_entropy()用于清理和释放get_entropy()返回的缓冲区。get_entropy()返回的熵指针在buf中传递,其长度在len中传递。

cleanup_user_entropy()用于清理和释放get_user_entropy()返回的缓冲区。get_user_entropy()返回的熵指针在buf中传递,其长度在len中传递。

get_nonce()使用传递的长度为salt_lensalt参数和操作系统特定的信息检索nonce。salt应包含唯一标识信息,并且以未指定的方式包含在输出中。输出存储在缓冲区中,该缓冲区至少包含min_len字节,最多包含max_len字节。缓冲区地址存储在*pout中,缓冲区长度返回给调用方。发生错误时,将返回零。

get_user_nonce()与get_nonce()相同,不同之处在于它将尝试通过对RAND_set_seed_source_type(3)的调用或通过config(5)中的“随机配置”指定的种子源收集种子材料。

cleanup_nonce()用于清理和释放get_nonce()返回的缓冲区。get_nonce()返回的nonce指针在buf中传递,其长度在len中传递。

cleanup_user_nonce()用于清理和释放get_user_nonce()返回的缓冲区。get_user_nonce()返回的nonce指针在buf中传递,其长度在len中传递。

provider_register_child_cb()注册回调,以便在应用程序的库上下文中加载和卸载提供程序时获得通知。handle是此提供程序的句柄,cbdata是此提供程序的数据,将传递回回调。它在成功时返回1,否则返回0。这些回调可能在持有libcrypto中的锁时被调用。为了避免死锁,回调实现不能长时间运行,并且不能调用其他OpenSSL API函数或上行调用。

create_cb是在将新的提供程序加载到应用程序的库上下文时将调用的回调。对于在此回调注册时已加载的任何提供程序,也会调用它。回调将传递用于正在加载的新提供程序的句柄,以及此提供程序在cbdata中的数据。它应该在成功时返回1,在失败时返回0。

remove_cb是在从应用程序的库上下文中卸载新的提供程序时将调用的回调。它将传递用于正在卸载的提供程序的句柄,以及此提供程序在cbdata中的数据。它应该在成功时返回1,在失败时返回0。

global_props_cb是在父库上下文中的全局属性更改时将调用的回调。它应该在成功时返回1,在失败时返回0。

provider_deregister_child_cb()取消注册之前通过provider_register_child_cb()注册的回调。如果已调用provider_register_child_cb(),则应在或在此提供程序的拆卸函数被调用之前调用provider_deregister_child_cb()。

provider_name()返回一个字符串,该字符串提供由handle标识的提供程序的名称。

provider_get0_provider_ctx()返回与由prov标识的提供程序关联的提供程序上下文。

provider_get0_dispatch()获取由prov标识的提供程序在初始化时注册的分派表。

provider_up_ref()增加提供程序prov的引用计数。如果activate非零,则如果提供程序尚未加载,则也会加载它。它在成功时返回1,在失败时返回0。

provider_free()减少提供程序prov的引用计数。如果deactivate非零,则如果提供程序尚未卸载,则也会卸载它。它在成功时返回1,在失败时返回0。

提供程序函数

provider_teardown()在提供程序关闭并从核心的提供程序存储中删除时被调用。它必须释放传递的provctx

provider_gettable_params()应返回一个描述符OSSL_PARAM(3)的常量数组,用于provider_get_params()可以处理的参数。

provider_get_params()应处理OSSL_PARAM(3)数组params,设置其理解的参数的值。

provider_query_operation()应返回一个对应于给定operation_id的常量OSSL_ALGORITHM(3)。它应指示核心是否可以通过将*no_store设置为0(核心可以存储引用)或1(核心不能存储引用)来存储对该数组的引用。

provider_unquery_operation()通知提供程序不再直接需要provider_query_operation()的结果,并且已复制函数指针。operation_id应与传递给provider_query_operation()的匹配,algs应为其返回值。

provider_get_reason_strings()应返回一个常量OSSL_ITEM(3)数组,该数组提供提供程序在使用core_put_error()报告错误时可能使用的reason代码的reason字符串。

provider_get_capabilities() 函数应该调用回调函数 cb,并将一组 OSSL_PARAM(3) 和调用者提供的参数 arg 传递给它。这些 OSSL_PARAM(3) 应该提供与 capability 参数中给定的名称相关的功能详细信息,这些详细信息与提供程序上下文 provctx 相关。如果提供程序支持多个具有给定名称的功能,则它可以多次调用回调函数(每个功能一次)。功能可用于描述提供程序可以提供的服务。有关更多详细信息,请参阅下面的 “功能” 部分。成功时应返回 1,错误时应返回 0。

provider_self_test() 函数应在其使用的一部分算法上执行已知答案测试,并且还可以验证提供程序模块的完整性。成功时应返回 1,错误时应返回 0。如果未使用此函数,它将返回 1。

这些函数都不是强制性的,但如果没有至少 provider_query_operation(),提供程序几乎毫无用处,如果没有 provider_get_params() 则 provider_gettable_params() 几乎毫无用处。

提供程序参数

provider_get_params() 可以将以下提供程序参数返回给核心

“name”(OSSL_PROV_PARAM_NAME)<UTF8 指针>

这指向一个字符串,该字符串应为提供程序提供唯一名称。

“version”(OSSL_PROV_PARAM_VERSION)<UTF8 指针>

这指向一个字符串,该字符串是与此提供程序关联的版本号。OpenSSL 内置提供程序使用 OPENSSL_VERSION_STR,但对于任何第三方提供程序,这可能会有所不同。此字符串仅供参考。

“buildinfo”(OSSL_PROV_PARAM_BUILDINFO)<UTF8 指针>

这指向一个字符串,该字符串是与此提供程序关联的构建信息。OpenSSL 内置提供程序使用 OPENSSL_FULL_VERSION_STR,但对于任何第三方提供程序,这可能会有所不同。

“status”(OSSL_PROV_PARAM_STATUS)<无符号整数>

如果提供程序已进入错误状态,则返回 0,否则返回 1。

provider_gettable_params() 应返回上述参数。

核心参数

core_get_params() 可以为每个提供程序检索以下核心参数

“openssl-version”(OSSL_PROV_PARAM_CORE_VERSION)<UTF8 字符串指针>

这指向 OpenSSL 库的完整版本字符串,即从宏 OPENSSL_VERSION_STR 展开的字符串。

“provider-name”(OSSL_PROV_PARAM_CORE_PROV_NAME)<UTF8 字符串指针>

这指向 OpenSSL 库对调用提供程序名称的理解。

“module-filename”(OSSL_PROV_PARAM_CORE_MODULE_FILENAME)<UTF8 字符串指针>

这指向一个包含提供程序模块文件完整文件名的字符串。

此外,配置文件中的提供程序特定配置参数以点分名称形式可用。点分名称形式是由点分隔的节名称和最终配置命令名称的串联。

例如,假设我们有以下配置示例

config_diagnostics = 1
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

提供程序将有以下其他参数可用

“activate”

指向字符串“1”

“data1”

指向字符串“2”

“data2”

指向字符串“str”

“more.data3”

指向字符串“foo,bar”

有关处理参数的更多信息,请参阅 OSSL_PARAM(3)OSSL_PARAM_int(3)

功能

功能描述了提供程序可以提供的一些服务。应用程序可以查询功能以发现这些服务。

“TLS-GROUP”功能

libssl 可以查询“TLS-GROUP”功能以发现提供程序可以支持的 TLS 组列表。在 TLS 握手期间,每个支持的组都可以用于密钥交换(KEX)或密钥封装方法(KEM)。TLS 客户端可以在 supported_groups 扩展中宣传他们支持的 TLS 组列表,而 TLS 服务器可以从提供的列表中选择他们也支持的组。通过这种方式,提供程序可以将 libssl 已支持的组列表添加到其他组中。

提供程序支持的每个 TLS 组都应通过 provider_get_capabilities 函数传递的回调函数进行描述。每个组都应提供以下详细信息(除了OSSL_CAPABILITY_TLS_GROUP_IS_KEM之外,所有都是强制性的)

“tls-group-name”(OSSL_CAPABILITY_TLS_GROUP_NAME)<UTF8 字符串>

IANA TLS 支持组注册表中给出的组名称 https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8

“tls-group-name-internal”(OSSL_CAPABILITY_TLS_GROUP_NAME_INTERNAL)<UTF8 字符串>

提供程序已知的组名称。这可能与“tls-group-name”相同,但不必相同。

“tls-group-id”(OSSL_CAPABILITY_TLS_GROUP_ID)<无符号整数>

IANA TLS 支持组注册表中给出的 TLS 组 ID 值。

“tls-group-alg”(OSSL_CAPABILITY_TLS_GROUP_ALG)<UTF8 字符串>

提供程序提供的密钥管理算法的名称,应与此组一起使用。创建的密钥应能够支持密钥交换密钥封装方法(KEM),如可选的OSSL_CAPABILITY_TLS_GROUP_IS_KEM标志所示。该算法必须支持密钥和参数生成以及密钥/参数生成参数OSSL_PKEY_PARAM_GROUP_NAME。上面通过“tls-group-name-internal”给出的组名称将在 libssl 希望生成密钥/参数时通过OSSL_PKEY_PARAM_GROUP_NAME传递。

“tls-group-sec-bits”(OSSL_CAPABILITY_TLS_GROUP_SECURITY_BITS)<无符号整数>

此组中密钥提供的安全位数。位数应与 NIST SP800-57 文档的表 2 和 3 中给出的位数相当。

“tls-group-is-kem”(OSSL_CAPABILITY_TLS_GROUP_IS_KEM)<无符号整数>

布尔标志,用于描述是否应在密钥交换(KEX)模式(0,默认)或密钥封装方法(KEM)模式(1)下使用该组。

此参数是可选的:如果未指定,则假设 KEX 模式为该组的默认模式。

在 KEX 模式下,以典型的 Diffie-Hellman 方式,双方都执行keygen然后对对等方公钥执行derive。要在 KEX 模式下运行,组实现必须支持 provider-keyexch(7) 中描述的提供程序功能。

在 KEM 模式下,客户端执行keygen并发送其公钥,服务器使用客户端的公钥执行encapsulate并发送回生成的密文,最后客户端执行decapsulate以检索服务器的encapsulate生成的相同共享密钥。要在 KEM 模式下运行,组实现必须支持 provider-kem(7) 中描述的提供程序功能。

在 KEX 和 KEM 模式下,生成的共享密钥然后根据协议规范使用。

“tls-min-tls”(OSSL_CAPABILITY_TLS_GROUP_MIN_TLS)<整数>
“tls-max-tls”(OSSL_CAPABILITY_TLS_GROUP_MAX_TLS)<整数>
“tls-min-dtls”(OSSL_CAPABILITY_TLS_GROUP_MIN_DTLS)<整数>
“tls-max-dtls”(OSSL_CAPABILITY_TLS_GROUP_MAX_DTLS)<整数>

这些参数可用于描述组支持的最小和最大 TLS 和 DTLS 版本。这些值等同于各种 TLS 版本的线路上编码。例如,TLSv1.3 为 0x0304(十进制 772),TLSv1.2 为 0x0303(十进制 771)。0 表示没有定义的最小值或最大值。-1 表示不应在该协议中使用该组。

“TLS-SIGALG”功能

libssl 可以查询“TLS-SIGALG”功能以发现提供程序可以支持的 TLS 签名算法列表。除了内置的签名算法之外,每个支持的签名都可以用于客户端或服务器身份验证。TLS1.3 客户端可以在 signature_algorithms 扩展中宣传他们支持的 TLS 签名算法列表,而 TLS 服务器可以从提供的列表中选择他们也支持的算法。通过这种方式,提供程序可以将 libssl 已支持的签名算法列表添加到其他算法中。

提供程序支持的每个 TLS 签名算法都应通过 provider_get_capabilities 函数传递的回调函数进行描述。每个算法都可以提供以下详细信息

“iana-name”(OSSL_CAPABILITY_TLS_SIGALG_IANA_NAME)<UTF8 字符串>

IANA TLS 签名方案注册表中给出的签名算法名称,作为“Description”:https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-signaturescheme。必须提供此值。

“iana-code-point”(OSSL_CAPABILITY_TLS_SIGALG_CODE_POINT)<无符号整数>

IANA TLS SignatureScheme 注册表中给出的 TLS 算法 ID 值。必须提供此值。

“sigalg-name”(OSSL_CAPABILITY_TLS_SIGALG_NAME)<UTF8 字符串>

完整(可能是复合哈希和签名)签名算法的名称。提供程序可以(但没有义务)为此名称提供签名实现;如果没有,则假定这是纯签名算法和哈希算法的组合,必须使用参数“sig-name”和“hash-name”给出。必须提供此值。

“sigalg-oid”(OSSL_CAPABILITY_TLS_SIGALG_OID)<UTF8 字符串>

“sigalg-name”算法的 OID,采用规范数字文本形式。如果给出此参数,则将使用 OBJ_create() 为此 OID 创建 OBJ 和 NID,使用“sigalg-name”参数作为其(短)名称。否则,假定它已存在于对象数据库中,可能是提供程序使用 core_obj_create() 上行调用完成的。此值是可选的。

“sig-name”(OSSL_CAPABILITY_TLS_SIGALG_SIG_NAME)<UTF8 字符串>

构成复合“sigalg-name”的纯签名算法的名称。如果提供程序实现了“sigalg-name”,则此参数是冗余的,不得给出。此值是可选的。

“sig-oid”(OSSL_CAPABILITY_TLS_SIGALG_SIG_OID)<UTF8 字符串>

“sig-name”算法的 OID,采用规范数字文本形式。如果给出此参数,则将使用 OBJ_create() 为此 OID 创建 OBJ 和 NID,使用“sig-name”参数作为其(短)名称。否则,假定它已存在于对象数据库中。这可以通过提供程序使用 core_obj_create() 上行调用来完成。此值是可选的。

“hash-name”(OSSL_CAPABILITY_TLS_SIGALG_HASH_NAME)<UTF8 字符串>

构成复合“sigalg-name”的哈希算法的名称。如果提供程序实现了“sigalg-name”,则此参数是冗余的,不得给出。此值是可选的。

“hash-oid”(OSSL_CAPABILITY_TLS_SIGALG_HASH_OID)<UTF8 字符串>

“hash-name”算法的 OID,采用规范数字文本形式。如果给出此参数,则将使用 OBJ_create() 为此 OID 创建 OBJ 和 NID,使用“hash-name”参数作为其(短)名称。否则,假定它已存在于对象数据库中,可能是提供程序使用 core_obj_create() 上行调用完成的。此值是可选的。

“key-type”(OSSL_CAPABILITY_TLS_SIGALG_KEYTYPE)<UTF8 字符串>

适用证书的公钥的密钥类型。如果此参数不存在,则假定它与“sig-name”(如果存在)相同,否则为“sigalg-name”。此值是可选的。

“key-type-oid”(OSSL_CAPABILITY_TLS_SIGALG_KEYTYPE_OID)<UTF8 字符串>

“key-type” 的 OID,以规范数字文本形式表示。如果提供了此参数,则将使用 OBJ_create() 创建一个 OBJ 和一个 NID 用于此 OID,并使用“key-type”参数作为其(短)名称。否则,假设它已存在于对象数据库中,可能是由提供程序使用 core_obj_create() 上行调用完成的。此值是可选的。

“sec-bits”(OSSL_CAPABILITY_TLS_SIGALG_SECURITY_BITS)<无符号整数>

此算法密钥提供的安全位数。位数应与 NIST SP800-57 文档表 2 和表 3 中给出的位数相当。如果没有注册其他定义安全强度的摘要算法,则此数字用于确定算法的安全强度。如果签名算法在内部实现了自己的摘要,则需要将此值设置为正确反映整体安全强度。必须提供此值。

“tls-min-tls”(OSSL_CAPABILITY_TLS_SIGALG_MIN_TLS)<整数>
“tls-max-tls”(OSSL_CAPABILITY_TLS_SIGALG_MAX_TLS)<整数>

这些参数可用于描述签名算法支持的最小和最大 TLS 版本。这些值等同于各种 TLS 版本的网络编码。例如,TLSv1.3 是 0x0304(十进制 772),TLSv1.2 是 0x0303(十进制 771)。0 表示没有定义最小值或最大值。-1 表示签名算法不应在该协议中使用。目前,表示 TLS1.3 以外的任何内容的值意味着整个算法将被忽略。

注释

在 OpenSSL 3.0 中,core_obj_create() 和 core_obj_add_sigid() 函数不是线程安全的。

示例

这是一个作为动态加载模块提供的简单提供程序的示例。它为虚拟操作 BAR 实现虚拟算法 FOO

#include <malloc.h>
#include <openssl/core.h>
#include <openssl/core_dispatch.h>

/* Errors used in this provider */
#define E_MALLOC       1

static const OSSL_ITEM reasons[] = {
    { E_MALLOC, "memory allocation failure" }.
    OSSL_DISPATCH_END
};

/*
 * To ensure we get the function signature right, forward declare
 * them using function types provided by openssl/core_dispatch.h
 */
OSSL_FUNC_bar_newctx_fn foo_newctx;
OSSL_FUNC_bar_freectx_fn foo_freectx;
OSSL_FUNC_bar_init_fn foo_init;
OSSL_FUNC_bar_update_fn foo_update;
OSSL_FUNC_bar_final_fn foo_final;

OSSL_FUNC_provider_query_operation_fn p_query;
OSSL_FUNC_provider_get_reason_strings_fn p_reasons;
OSSL_FUNC_provider_teardown_fn p_teardown;

OSSL_provider_init_fn OSSL_provider_init;

OSSL_FUNC_core_put_error *c_put_error = NULL;

/* Provider context */
struct prov_ctx_st {
    OSSL_CORE_HANDLE *handle;
}

/* 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->handle, 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 },
    OSSL_DISPATCH_END
};

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 },
    OSSL_DISPATCH_END
};

int OSSL_provider_init(const OSSL_CORE_HANDLE *handle,
                       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_FUNC_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(handle, E_MALLOC, __FILE__, __LINE__);
        return 0;
    }
    pctx->handle = handle;
    return 1;
}

这依赖于 openssl/core_dispatch.h 中存在的一些内容

#define OSSL_OP_BAR            4711

#define OSSL_FUNC_BAR_NEWCTX      1
typedef void *(OSSL_FUNC_bar_newctx_fn)(void *provctx);
static ossl_inline OSSL_FUNC_bar_newctx(const OSSL_DISPATCH *opf)
{ return (OSSL_FUNC_bar_newctx_fn *)opf->function; }

#define OSSL_FUNC_BAR_FREECTX     2
typedef void (OSSL_FUNC_bar_freectx_fn)(void *ctx);
static ossl_inline OSSL_FUNC_bar_freectx(const OSSL_DISPATCH *opf)
{ return (OSSL_FUNC_bar_freectx_fn *)opf->function; }

#define OSSL_FUNC_BAR_INIT        3
typedef void *(OSSL_FUNC_bar_init_fn)(void *ctx);
static ossl_inline OSSL_FUNC_bar_init(const OSSL_DISPATCH *opf)
{ return (OSSL_FUNC_bar_init_fn *)opf->function; }

#define OSSL_FUNC_BAR_UPDATE      4
typedef void *(OSSL_FUNC_bar_update_fn)(void *ctx,
                                      unsigned char *in, size_t inl);
static ossl_inline OSSL_FUNC_bar_update(const OSSL_DISPATCH *opf)
{ return (OSSL_FUNC_bar_update_fn *)opf->function; }

#define OSSL_FUNC_BAR_FINAL       5
typedef void *(OSSL_FUNC_bar_final_fn)(void *ctx);
static ossl_inline OSSL_FUNC_bar_final(const OSSL_DISPATCH *opf)
{ return (OSSL_FUNC_bar_final_fn *)opf->function; }

另请参阅

provider(7)

历史

提供程序的概念及其周围的一切都在 OpenSSL 3.0 中引入。

版权所有 2019-2023 OpenSSL 项目作者。保留所有权利。

根据 Apache 许可证 2.0(“许可证”)获得许可。除非符合许可证,否则您不得使用此文件。您可以在源代码分发中的 LICENSE 文件或 https://www.openssl.org/source/license.html 中获取副本。