本文介绍 OpenSSL 3.x 中自定义 Engine 的开发方法,帮助你实现硬件安全模块(HSM)集成、国密算法扩展等需求。

什么是 OpenSSL Engine?

OpenSSL Engine 是 OpenSSL 密码学操作的可插拔后端实现。通过 Engine,你可以:

  • 集成硬件安全模块(HSM)
  • 使用国密算法(如 SM2/SM3/SM4)
  • 调用专用的加密加速卡
  • 实现自定义的密码学算法

查看可用 Engine

系统已内置多个 Engine,使用以下命令查看:

1
openssl engine -t

输出示例:

1
2
3
4
5
6
(dynamic) Dynamic engine loading support
     [ unavailable ]
(padlock) VIA PadLock (no-RNG, no-ACE)
     [ unavailable ]
(afalg) AFALG engine
     [ unavailable ]

[ unavailable ] 表示该 Engine 在当前系统上不可用,但可以加载。

使用动态 Engine 加载

OpenSSL 支持动态加载自定义 Engine。创建一个简单的配置文件进行测试:

1
2
3
4
5
# 创建 Engine 配置目录
mkdir -p ~/.openssl/engines

# 使用 dynamic engine 测试加载(无需真实 so 文件)
openssl genrsa -engine dynamic 2048 2>&1 | head -5

输出:

1
2
3
4
Engine "dynamic" set.
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQClGCZjhBh04Giv
...

Engine 配置文件

创建自定义 Engine 配置文件 openssl-engine.conf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# openssl-engine.conf
openssl_conf = openssl_init

[openssl_init]
engines = engine_section

[engine_section]
my_custom = my_custom_section

[my_custom_section]
default_algorithms = ALL
dynamic_path = /path/to/your/engine.so

使用自定义配置:

1
2
# 使用配置文件
OPENSSL_CONF=openssl-engine.conf openssl genrsa -engine my_custom 2048

编写自定义 Engine(C 语言示例)

以下是一个最小化的自定义 Engine 实现框架:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <openssl/engine.h>
#include <openssl/objects.h>

// 初始化函数
static int my_engine_init(ENGINE *e) {
    // 执行硬件初始化等操作
    return 1;
}

// 清理函数
static int my_engine_finish(ENGINE *e) {
    // 清理资源
    return 1;
}

// 定义支持的算法
static int my_engine_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void)) {
    switch (cmd) {
        // 处理控制命令
        default:
            return 0;
    }
    return 1;
}

// 绑定函数
static int bind_fn(ENGINE *e, const char *id) {
    if (!ENGINE_set_id(e, "my_custom") ||
        !ENGINE_set_destroy_function(e, ENGINE_destroy) ||
        !ENGINE_set_init_function(e, my_engine_init) ||
        !ENGINE_set_finish_function(e, my_engine_finish) ||
        !ENGINE_set_ctrl_function(e, my_engine_ctrl)) {
        return 0;
    }
    return 1;
}

IMPLEMENT_DYNAMIC_CHECK_FN()
IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)

编译为共享库:

1
2
gcc -shared -fPIC -o libmy_custom.so my_engine.c \
    -I/usr/include/openssl -lssl -lcrypto

国密 Engine 示例

国密算法通常通过GmSSL提供的 Engine 实现。安装后配置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 配置使用 gmssl engine
echo 'openssl_conf = openssl_init' > /etc/ssl/openssl.cnf
echo '[openssl_init]' >> /etc/ssl/openssl.cnf
echo 'engines = engine_section' >> /etc/ssl/openssl.cnf
echo '' >> /etc/ssl/openssl.cnf
echo '[engine_section]' >> /etc/ssl/openssl.cnf
echo 'gmssl = gmssl_section' >> /etc/ssl/openssl.cnf
echo '' >> /etc/ssl/openssl.cnf
echo '[gmssl_section]' >> /etc/ssl/openssl.cnf
echo 'default_algorithms = ALL' >> /etc/ssl/openssl.cnf

# 生成国密 SM2 密钥
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:sm2p256v1 -out sm2.key

Engine 开发最佳实践

  1. 实现完整的生命周期函数

    • ENGINE_init():初始化硬件连接
    • ENGINE_finish():清理资源
    • ENGINE_destroy():释放 Engine 内部结构
  2. 错误处理

    • 为所有可能失败的操作返回适当的错误码
    • 使用 ERR_put_error() 记录错误信息
  3. 线程安全

    • 如果使用硬件设备,确保多线程访问安全
    • 使用锁保护共享状态
  4. 性能优化

    • 批量处理操作减少通信开销
    • 异步操作避免阻塞主线程

调试技巧

启用 Engine 调试:

1
2
3
4
5
6
# 设置调试环境变量
export OPENSSL_DEBUG=1
export ENGINE_DEBUG=1

# 测试 Engine 加载
openssl genrsa -engine my_custom -vvv 2>&1

检查 Engine 日志:

1
openssl engine -t -vvv -c

总结

OpenSSL Engine 机制提供了灵活的密码学后端扩展能力。通过自定义 Engine,可以:

  • 集成各种硬件安全模块
  • 支持国密等国产算法
  • 实现特定的加密需求

开发时注意遵循 OpenSSL 的 Engine API 规范,并做好充分的错误处理和测试。


参考来源