開放SSL

密碼學和 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);

說明

在此提到的所有「函式」都以函式指標在 OSSL_DISPATCH(3) 陣列中,傳遞於 libcrypto 和提供者之間,在提供者初始化函式的呼叫中。請參閱 provider(7) 中的「提供者」,以取得初始化函式的說明。它們稱為「上呼叫」。

所有這些「函式」都有對應的函式類型定義,稱為 OSSL_FUNC_{name}_fn,以及一個輔助函式,用於從 OSSL_DISPATCH(3) 元素中擷取函式指標,稱為 OSSL_FUNC_{name}。例如,「函式」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()

設定錯誤的原因,以及任何附加資料。原因是由提供者定義的數字,用於索引由 provider_get_reason_strings() 回傳的錯誤字串表格。附加資料以格式字串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) 中的 "Random Configuration" 指定的種子來源收集種子素材。

cleanup_entropy() 用於清理並釋放 get_entropy() 傳回的緩衝區。get_entropy() 傳回的 entropy 指標傳遞到 buf 中,其長度傳遞到 len 中。

cleanup_user_entropy() 用於清理並釋放 get_user_entropy() 傳回的緩衝區。get_user_entropy() 傳回的 entropy 指標傳遞到 buf 中,其長度傳遞到 len 中。

get_nonce() 使用傳遞的長度為 salt_lensalt 參數和作業系統特定資訊擷取一次性密碼。salt 應包含唯一識別資訊,且此資訊會以未指定的方式包含在輸出中。輸出儲存在一個緩衝區中,該緩衝區至少包含 min_len 位元組,最多包含 max_len 位元組。緩衝區位址儲存在 *pout 中,緩衝區長度傳回給呼叫者。發生錯誤時,傳回零。

get_user_nonce() 與 get_nonce() 相同,但它會嘗試透過呼叫 RAND_set_seed_source_type(3) 或透過 config(5) 中的 "Random Configuration" 指定的種子來源收集種子素材。

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 識別的提供者在初始化時註冊的 dispatch 表格。

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() 應傳回常數 OSSL_ALGORITHM(3),對應於給定的 operation_id。它應透過將 *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() 報告錯誤時,原因代碼的原因字串。

provider_get_capabilities() 函數應呼叫回呼 cb,傳遞給它一組 OSSL_PARAM(3) 和呼叫者提供的引數 argOSSL_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 ptr>

這指向一個字串,提供者應給予一個獨特的名稱。

"version" (OSSL_PROV_PARAM_VERSION) <UTF8 ptr>

這指向一個字串,是與此提供者相關的版本號。OpenSSL 內建提供者使用 OPENSSL_VERSION_STR,但任何第三方提供者可能不同。此字串僅供資訊用途。

"buildinfo" (OSSL_PROV_PARAM_BUILDINFO) <UTF8 ptr>

這指向一個字串,是與此提供者相關的建置資訊。OpenSSL 內建提供者使用 OPENSSL_FULL_VERSION_STR,但任何第三方提供者可能不同。

"status" (OSSL_PROV_PARAM_STATUS) <unsigned integer>

如果提供者已進入錯誤狀態,這會傳回 0,否則傳回 1。

provider_gettable_params() 應傳回上述參數。

核心參數

core_get_params() 可擷取每個提供者的下列核心參數

"openssl-version" (OSSL_PROV_PARAM_CORE_VERSION) <UTF8 string ptr>

這指向 OpenSSL 函式庫的完整版本字串,亦即從巨集 OPENSSL_VERSION_STR 展開的字串。

"provider-name" (OSSL_PROV_PARAM_CORE_PROV_NAME) <UTF8 string ptr>

這指向 OpenSSL 函式庫對呼叫提供者名稱的看法。

"module-filename" (OSSL_PROV_PARAM_CORE_MODULE_FILENAME) <UTF8 string ptr>

這指向一個字串,包含提供者模組檔案的完整檔名。

此外,設定檔中的特定提供者組態參數可用,以點分名稱格式表示。點分名稱格式是區段名稱和最後組態指令名稱的串接,以句點分隔。

例如,假設我們有下列組態範例

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 伺服器可以在受支援群組延伸模組中宣告其支援的 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。當 libssl 希望產生金鑰/參數時,會透過 OSSL_PKEY_PARAM_GROUP_NAME 傳遞上面透過「tls-group-name-internal」提供的群組名稱。

「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 方式,雙方執行金鑰產生,然後針對對等公開金鑰衍生。若要以 KEX 模式操作,群組實作必須支援 provider-keyexch(7) 中所述的提供者函數。

在 KEM 模式中,用戶端執行金鑰產生並傳送其公開金鑰,伺服器使用用戶端的公開金鑰執行封裝並傳回產生的密文,最後用戶端執行解封以擷取伺服器的封裝所產生的相同共用密碼。若要以 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 簽章方案註冊表中 "說明" 所示:https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-signaturescheme。必須提供此值。

"iana-code-point" (OSSL_CAPABILITY_TLS_SIGALG_CODE_POINT) <unsigned integer>

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() 將用於使用 "sigalg-name" 參數作為其 (簡短) 名稱,為此 OID 建立 OBJ 和 NID。否則,假設它已存在於物件資料庫中,可能是由供應商使用 core_obj_create() upcall 完成的。此值是選用的。

"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() 將用於使用 "sig-name" 參數作為其 (簡短) 名稱,為此 OID 建立 OBJ 和 NID。否則,假設它已存在於物件資料庫中。供應商可以使用 core_obj_create() upcall 完成此動作。此值是選用的。

"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() 將用於使用 "hash-name" 參數作為其 (簡短) 名稱,為此 OID 建立 OBJ 和 NID。否則,假設它已存在於物件資料庫中,可能是由供應商使用 core_obj_create() upcall 完成的。此值是選用的。

"key-type" (OSSL_CAPABILITY_TLS_SIGALG_KEYTYPE) <UTF8 字串>

適用的憑證公鑰的類型。如果未提供此參數,則假設它與 "sig-name" 相同 (如果存在),否則為 "sigalg-name"。此值是選用的。

"key-type-oid" (OSSL_CAPABILITY_TLS_SIGALG_KEYTYPE_OID) <UTF8 字串>

以標準數字文字格式顯示「金鑰類型」的 OID。如果提供此參數,OBJ_create() 將用於建立 OBJ 和此 OID 的 NID,並使用「金鑰類型」參數作為其(簡短)名稱。否則,假設它已存在於物件資料庫中,可能是由提供者透過 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 The OpenSSL Project Authors。保留所有權利。

在 Apache 授權 2.0(「授權」)下授權。您不得在不遵守授權的情況下使用此檔案。您可以在原始程式碼散佈中的 LICENSE 檔案或 https://www.openssl.org/source/license.html 取得副本。