当前位置: 首页 > news >正文

如何整合 openSSL custom provider (以 TRNG 舉例)

文章目录

    • 目標
    • Provider interface for RNG (Random Number Generator)
    • OSSL_DISPATCH to init provider
    • RNG 類型介紹
      • RNG algorithm life cycle
      • 随机数生成器(RNG)生命周期阶段
    • Dynamic loadable module and build-in module
      • Provider 如何使用 build-in module
      • Provider 如何使用 dynamic loadable module
    • Openssl RNG 入口函數
    • FAQ
    • Reference

目標

提供方法將 SE TRNG(安全元件真隨機數生成器) 集成到 OpenSSL 加密框架中,通過 Provider 或 Engine 接口,利用SE的TRNG能力,實現安全、高效能的隨機數生成。

Provider interface for RNG (Random Number Generator)

The concept of providers and everything surrounding them was introduced in OpenSSL 3.0.
Provider 可以提供例如加密與解密、密鑰衍生、MAC 計算、簽署與驗證、隨機數產生器(Random Number Generator, RNG)等的替換,下文僅描述provider 有關RNG的介面。

A provider offers an initialization function, as a set of base functions in the form of an OSSL_DISPATCH array, and by extension, a set of OSSL_ALGORITHMs

OSSL_LIB_CTX *ctx (libopenssl 上下文)裡面的組成

在这里插入图片描述

  • OSSL_DISPATCH 是一個用來描述特定功能實作的結構體,提供功能ID與對應的函數指針。
    提供者通過一組 OSSL_DISPATCH 來註冊它所實作的功能,每個功能對應於一個 function_id 和其具體的函數實作。
typedef struct ossl_dispatch_st OSSL_DISPATCH;
struct ossl_dispatch_st {int function_id;void (*function)(void);
};
  • OSSL_ALGORITHM 是一個用來描述提供者支持的演算法的結構體,它與 OSSL_DISPATCH 一起使用,將演算法名稱與功能對應。
    provider 宣告其支持的演算法名稱及對應的實作(由OSSL_DISPATCH array組成)。
#include <openssl/core.h>typedef struct ossl_algorithm_st OSSL_ALGORITHM;
struct ossl_algorithm_st {const char *algorithm_names;     /* key */const char *property_definition; /* openssl 定義一套搜尋方法property,當有多種演算法的時候可用於檢索 */const OSSL_DISPATCH *implementation;const char *algorithm_description; /* 簡短描述 */
};
MemberDescriptionMandatory/Optional
algorithm_nameThe name of the algorithm (e.g., “AES-128-CBC”, “SHA256”, “RAND”).Mandatory
property_definitionA property string used to describe the algorithm (e.g., “default=yes”, “fips=yes”).Optional
implementation_functionPointer to the implementation function for the algorithm (e.g., cipher, digest, RNG interface).Mandatory
extra_dataReserved for future use; typically set to NULL.Optional

OSSL_DISPATCH to init provider

Provider 的初始化需要實現 OSSL_provider_init 函數,這是每個 Provider 的入口點。

// Provider 的上下文結構
typedef struct {const OSSL_CORE_HANDLE *handle;  // 核心句柄
} CUSTOM_PROVIDER_CTX;// 初始化函數
int OSSL_provider_init(const OSSL_CORE_HANDLE *handle,const OSSL_DISPATCH *in,const OSSL_DISPATCH **out,void **provctx) {// 分配上下文CUSTOM_PROVIDER_CTX *ctx = OPENSSL_malloc(sizeof(CUSTOM_PROVIDER_CTX));if (ctx == NULL) {return 0;  // 初始化失敗}ctx->handle = handle;*provctx = ctx;// 將功能表導出給 OpenSSL*out = custom_provider_functions;return 1;  // 初始化成功
}

參數說明:

  1. handle (IN):由 OpenSSL 核心傳遞的句柄,用於與核心功能交互。
  2. in (IN):指向核心功能的 OSSL_DISPATCH 陣列,供 Provider 調用。
  3. out (OUT):指向 Provider 提供的 OSSL_DISPATCH 陣列,OpenSSL 通過它訪問 Provider 的功能。
  4. provctx (OUT):Provider 的上下文,用於維護 Provider 的狀態信息。
    每個 Provider 都需要提供一個 OSSL_DISPATCH 陣列,描述其支持的功能。
static const OSSL_DISPATCH custom_provider_functions[] = {{ OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, (void (*)(void))custom_gettable_params },{ OSSL_FUNC_PROVIDER_GET_PARAMS,      (void (*)(void))custom_get_params },{ OSSL_FUNC_PROVIDER_TEARDOWN,       (void (*)(void))custom_teardown },{ 0, NULL }
};

以下是按照要求生成的表格,包含功能ID、说明、必填/选填状态及对应的libopenssl API:

功能 ID说明必填或选填libopenssl 会使用到的API
OSSL_FUNC_PROVIDER_GETTABLE_PARAMS返回该 Provider 支持的参数名称列表,通常用于查询 Provider 的静态属性,例如名称或版本信息。选填(Optional)OSSL_PROVIDER_gettable_params()
OSSL_FUNC_PROVIDER_GET_PARAMS提供具体的参数值,例如返回 Provider 的名称或版本信息,与 GETTABLE_PARAMS 配合使用。选填(Optional)OSSL_PROVIDER_get_params()
OSSL_FUNC_PROVIDER_QUERY_OPERATION用于查询 Provider 支持的特定算法实现。这是 OpenSSL 与 Provider 交互的核心功能。必填(Required)OSSL_PROVIDER_query_operation()
OSSL_FUNC_PROVIDER_TEARDOWN用于释放 Provider 的资源,当 Provider 被卸载时调用。选填(Optional)OSSL_PROVIDER_unload()
---OSSL_PROVIDER_free()

RNG 類型介紹

libssl 提供的RNG 根據使用場景不同,需要分別註冊不同的 OSSL_ALGORITHM。
硬體 TRNG 在實際應用中,主要作為種子源,提供高熵輸入以提升整體隨機數的不可預測性與安全性。

  • 完全適合使用硬體 TRNG:CTR-DRBG、HASH-DRBG、HMAC-DRBG、SEED-SRC、通用 RNG。
  • 不適合使用硬體 TRNG:TEST-RAND(僅用於測試環境)。

RNG algorithm life cycle

libssl 使用EVP_RAND_來呼叫RNG provider 提供的OSSL_DISPATCH ID 對應的函數指針
请添加图片描述

随机数生成器(RNG)生命周期阶段

阶段(Stage)说明OSSL_DISPATCH ID分类
start表示 RNG 尚未被分配,是任何生命周期过渡的起始状态。--
newed表示 RNG 已经分配完成,但尚无法生成任何输出。OSSL_FUNC_RAND_NEWCTXContext Management Functions
instantiated表示 RNG 已完成设置,能够生成输出。OSSL_FUNC_RAND_INSTANTIATERandom Number Generator Functions: NIST
uninstantiated表示 RNG 已被关闭,无法再生成输出。OSSL_FUNC_RAND_UNINSTANTIATERandom Number Generator Functions: NIST
freed表示 RNG 已被释放,为所有生命周期过渡的终止状态。OSSL_FUNC_RAND_FREECTXContext Management Functions

除了生命週期的函數指針以外,RNG 完成設置以後可呼叫EVP_RAND_,會呼叫到OSSL_DISPATCH OSSL_FUNC_RAND_,
但不同的RNG依照其特性,不一定包含所有ID
(舉例 EVP_RAND_get_params 呼叫到函數指針OSSL_FUNC_RAND_GET_PARAMS)

以下是基于提供内容生成的表格:

ID說明
OSSL_FUNC_RAND_NONCE生成指定強度的隨機數字元(nonce),長度介於 min_noncelen 到 max_noncelen 之間。若輸出緩衝區 out 為 NULL,則返回隨機數字元長度。
OSSL_FUNC_RAND_GET_SEED確定性生成器從父生成器獲取種子材料。生成的種子字節數符合安全熵位數,總字節數介於 min_len 到 max_len 之間。種子材料指針存儲於 *buffer,需後續用 OSSL_FUNC_RAND_CLEAR_SEED 釋放。
OSSL_FUNC_RAND_CLEAR_SEED釋放由 OSSL_FUNC_RAND_GET_SEED 分配的長度為 b_len 的種子緩衝區。
OSSL_FUNC_RAND_VERIFY_ZEROIZATION檢查 RNG 內部狀態是否已歸零。此功能為 NIST 自測的一部分,其他情況下用途較少。
OSSL_FUNC_RAND_ENABLE_LOCKING為 RNG 及其所有父 RNG 啟用鎖定。此後 RNG 可線程安全使用。
OSSL_FUNC_RAND_LOCK鎖定 RNG,確保獨占訪問。
OSSL_FUNC_RAND_UNLOCK解鎖 RNG。

Dynamic loadable module and build-in module

Provider 如何使用 build-in module

  1. 完成下列實作 OSSL_provider_init , OSSL_DISPATCH 與宣告OSSL_ALGORITHM的.c
  2. 修改 crypto/provider 路徑,加入第一步的.c
  3. 撰寫build.info
SOURCE[../libcustom.a]=custom.c # It is necessary to have an explicit entry point
SOURCE[../custom]=custom_entry.c
  1. openssl (或其他使用此module的application) 使用custom build-in module,需要使用下列API
    以下是整理后的 OpenSSL Provider API 功能表格:
API 名稱用途參數說明
OSSL_PROVIDER_add_builtin()註冊內建或自訂 Providerctx: OpenSSL 上下文(NULL 表示全局)
name: 模組名稱
init_fn: 初始化函數指標
OSSL_PROVIDER_try_load()嘗試加載已註冊模組(未加載時才執行)ctx: OpenSSL 上下文
name: 模組名稱
retain_fallbacks: 是否保留回退選項(1=是)
OSSL_PROVIDER_load()強制加載指定模組(無論當前狀態)ctx: OpenSSL 上下文
name: 模組名稱
OSSL_PROVIDER_unload()卸載模組並釋放資源prov: 已加載模組的對象指針
OSSL_PROVIDER_available()檢查模組是否已加載且可用ctx: OpenSSL 上下文
name: 模組名稱

結合上文Provider 初始化的段落舉例如何指定初始化OSSL_DISPATCH並加入OSSL_ALGORITHM

static const OSSL_DISPATCH custom_rand_functions[] = {{ OSSL_FUNC_RAND_NEWCTX, (void (*)(void))custom_rand_newctx },{ OSSL_FUNC_RAND_FREECTX, (void (*)(void))custom_rand_freectx },{ OSSL_FUNC_RAND_INSTANTIATE, (void (*)(void))custom_rand_instantiate },{ OSSL_FUNC_RAND_UNINSTANTIATE, (void (*)(void))custom_rand_uninstantiate },{ OSSL_FUNC_RAND_GENERATE, (void (*)(void))custom_rand_generate },{ OSSL_FUNC_RAND_ENABLE_LOCKING, (void (*)(void))custom_rand_enable_locking },{ OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS, (void (*)(void))custom_rand_gettable_ctx_params },{ OSSL_FUNC_RAND_GET_CTX_PARAMS, (void (*)(void))custom_rand_get_ctx_params },{ 0, NULL }
};static const OSSL_ALGORITHM custom_rand_algs[] = { { "CUSTOM", "provider=custom", custom_rand_functions },{ NULL, NULL, NULL } };static const OSSL_ALGORITHM *custom_query(void *provctx, int operation_id, int *no_cache)
{*no_cache = 0;switch (operation_id) {case OSSL_OP_RAND:return custom_rand_algs;default:return NULL;}
}
static const OSSL_DISPATCH custom_dispatch[] = { { OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))OSSL_LIB_CTX_free },{ OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))custom_query },{ 0, NULL } };static int custom_provider_init(const OSSL_CORE_HANDLE *handle, const OSSL_DISPATCH *in, const OSSL_DISPATCH **out,void **provctx)
{OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();if (libctx == NULL) {return 0;}*provctx = libctx;*out = custom_dispatch;return 1;
}

Provider 如何使用 dynamic loadable module

  1. 將帶有 OSSL_provider_init 以及 OSSL_DISPATCH 與宣告OSSL_ALGORITHM的.c 檔案,編譯為.so
  2. 配置 OpenSSL 確保可以找到動態模組的位置
export OPENSSL_MODULES=/path/to/modules

Dynamic loadable module 配置文件 openssl.cnf

# 全局 OpenSSL 初始化配置
openssl_conf = openssl_init# 初始化設置
[openssl_init]
providers = provider_section# 提供者加載區域
[provider_section]
custom = custom_provider   # 加載自訂提供者
default = default_provider # 同時保留默認提供者,除非我已經實現了所有必需的加密、密鑰衍生、MAC 計算、簽署與驗證演算法,否則不能刪除# 自訂提供者配置
[custom_provider]
module = $ENV::OPENSSL_MODULES/custom_provider.so
activate = 1  # 1 表示啟用 custom_provider
  1. 動態模組的初始化邏輯由 OSSL_provider_init 驅動

Openssl RNG 入口函數

實現provider 並正確加載以後,使用libssl 的application 調用 RAND_bytes 產生RNG,詳細 API 呼叫流程:

  1. 應用層調用 RAND_bytes,用於生成隨機數。RAND_bytes 定義在 crypto/rand/rand_lib.c,它是一個封裝函數,用於調用 RAND 方法
int RAND_bytes(unsigned char *buf, int num) {return RAND_bytes_ex(NULL, buf, num, 0);
}
  1. RAND_bytes_ex 會從當前的 OpenSSL 全局上下文中獲取活躍的 Provider,並調用相應的 RAND 接口。
    通過 RAND_bytes_ex 調用隨機數生成 RAND_bytes_ex 會檢查 RAND 方法是否正確加載,然後調用 EVP_RAND_generate。
int RAND_bytes_ex(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t num, unsigned int strength) {// 查詢 RAND ProviderEVP_RAND_CTX *rand = EVP_RAND_fetch(ctx, "default", NULL);if (!rand)return 0;// 使用 RAND Provider 的生成方法return EVP_RAND_generate(rand, buf, num, strength, 0, NULL, 0);
}
  1. EVP_RAND_generate 會通過 RAND Provider 的 OSSL_DISPATCH 表,調用 OSSL_FUNC_RAND_GENERATE。
int EVP_RAND_generate(EVP_RAND_CTX *ctx, unsigned char *out, size_t outlen,unsigned int strength, int prediction_resistance,const unsigned char *addin, size_t addinlen) {const EVP_RAND *rand = ctx->rand;if (rand->generate)return rand->generate(ctx->provctx, out, outlen, strength,prediction_resistance, addin, addinlen);return 0;
}

FAQ

  1. 已經使用openssl.cnf 指定某個custom provider(dynamic loadable module), application openssl 還需要使用OSSL_PROVIDER_load(顯式調用) 嗎?
    不需要顯式調用的情況:
    默認情況下自動加載所有配置的 Provider,當 OpenSSL 啟動時,會自動解析 openssl.cnf 中定義的所有 Provider,無需手動干預。如果在配置文件中通過 module 和 activate 配置了目標 Provider,OpenSSL 在啟動時會自動加載,應用程序可以直接使用。
  2. 需要顯式調用的情況
    1. 需要動態調整 Provider 行為:
      如果應用程序需要在運行期間動態切換或加載新的 Provider,而不是依賴啟動時的自動加載,就需要調用 OSSL_PROVIDER_load()。
    2. 需要在多上下文中使用不同的 Provider:
      如果應用程序使用了多個 OpenSSL 上下文(OSSL_LIB_CTX),且不同上下文需要不同的 Provider 配置,應用程序需要使用 OSSL_PROVIDER_load() 為每個上下文顯式加載 Provider。
    3. 需要加載未在配置文件中定義的 Provider:
      如果某個 Provider 未在 openssl.cnf 中配置,但需要在運行期間使用,應用程序可以通過顯式調用 OSSL_PROVIDER_load() 來加載它。

Reference

https://docs.openssl.org/master/man7/provider-rand/
https://docs.openssl.org/master/man7/life_cycle-rand/
https://docs.openssl.org/master/man3/OSSL_PROVIDER
https://docs.openssl.org/master/man3/EVP_RAND

http://www.dtcms.com/a/399030.html

相关文章:

  • 做电影网站一年赚多少钱wordpress 二级页面菜单 404
  • JAVA学习笔记——判断和循环的概念和一些习题
  • Java `synchronized` 关键字高频面试题(原理+场景+底层实现)
  • 微信企业号可以做微网站吗查看wordpress访问记录
  • 企业建站程序哪个好asp简单网站开发
  • 法术光环释义
  • todesk远程到被控Mac后不显示画面
  • 上网行为安全(2)
  • 网站颜色搭配技巧网站建设征税标准
  • 虚拟主机建网站网站建设技术主管
  • Transformer原理学习(4)注意力机制
  • Linux epoll 事件机制深度解析
  • 仿制网站软件王烨名字含义
  • 网站建设教程 乐视网冠辰网站建设
  • 网站建设方案说明微信里的小程序怎么删除
  • vue <img 图片标签 图片引入
  • 防伪网站怎么做为什么打开网址都是seo综合查询
  • 做极速赛车网站怎么做网站视频
  • DP4363远程无钥匙进入(PKE)技术:便利与安全的完美融合
  • 手机网站页面长沙网页设计培训班哪家好
  • 用 Codebuddy Code CLI 快速开发中小学数学测试系统
  • 开源 java android app 开发(十四)绘图定义控件--波形显示器
  • seo网站设计费用网站过期会怎样解决
  • 网站机房建设目的温州机械网站建设
  • WLB公司内推|招联金融2026届校招|18薪
  • 平安产险深圳分公司在深圳莲花山公园 参与2025年金融教育宣传周启动仪式活动
  • 从root用户切换到某个普通用户突然报错“su: failed to execute /bin/bash: 资源暂时不可用”
  • 沧州网站建设制作设计优化浏览器提醒 WordPress
  • 网站风格什么意思快速优化系统
  • 陕西创程教育:点亮职业人生的明灯