openssl:基于 FFI 的 OpenSSL 绑定,用于 nginx-module-lua
安装
如果您尚未设置 RPM 仓库订阅,请注册。然后您可以按照以下步骤进行操作。
CentOS/RHEL 7 或 Amazon Linux 2
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-openssl
CentOS/RHEL 8+、Fedora Linux、Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-openssl
要将此 Lua 库与 NGINX 一起使用,请确保已安装 nginx-module-lua。
本文档描述了 lua-resty-openssl v1.9.0, 该版本于 2026 年 8 月 14 日发布。
基于 FFI 的 OpenSSL 绑定,适用于 LuaJIT,支持 OpenSSL 3、4 以及 1.1.1 系列。
对 OpenSSL 1.1.0、1.0.2 和 BoringSSL 的支持已被移除,但仍可在 0.x 分支 中找到。
描述
lua-resty-openssl 是一个基于 FFI 的 OpenSSL 绑定库,目前支持 OpenSSL 3.x、4.x 以及 1.1.1 系列。
概要
该库深受 luaossl 的启发,并采用了更接近原始 OpenSSL API 的命名转换方式。
例如,OpenSSL C API 中名为 X509_set_pubkey 的函数被暴露为 resty.openssl.x509:set_pubkey。
CamelCase 命名被替换为 下划线命名,例如 X509_set_serialNumber 变为
resty.openssl.x509:set_serial_number。与 luaossl 的另一个区别是,错误不会使用 error() 抛出,而是作为最后一个参数返回。
每个由 new() 返回的 Lua 表都包含一个 cdata 对象 ctx。用户不应手动设置 ffi.gc 或调用 ctx 结构体对应的析构函数(如 *_free 函数)。
resty.openssl
这个元模块提供了针对所链接的 OpenSSL 库的版本健全性检查。
openssl.load_library
语法: name, err = openssl.load_library()
尝试加载 OpenSSL 共享库。此函数会尝试几种已知的库名称模式,并在成功加载时返回 crypto 库的名称,否则返回错误。
当在 resty CLI 或启用了 SSL 的 OpenResty 中运行时,无需调用此函数。
openssl.load_modules
语法: openssl.load_modules()
将所有可用的子模块加载到当前模块中:
bn = require("resty.openssl.bn"),
cipher = require("resty.openssl.cipher"),
digest = require("resty.openssl.digest"),
hmac = require("resty.openssl.hmac"),
kdf = require("resty.openssl.kdf"),
pkey = require("resty.openssl.pkey"),
objects = require("resty.openssl.objects"),
rand = require("resty.openssl.rand"),
version = require("resty.openssl.version"),
x509 = require("resty.openssl.x509"),
altname = require("resty.openssl.x509.altname"),
chain = require("resty.openssl.x509.chain"),
csr = require("resty.openssl.x509.csr"),
crl = require("resty.openssl.x509.crl"),
extension = require("resty.openssl.x509.extension"),
extensions = require("resty.openssl.x509.extensions"),
name = require("resty.openssl.x509.name"),
store = require("resty.openssl.x509.store"),
ssl = require("resty.openssl.ssl"),
ssl_ctx = require("resty.openssl.ssl_ctx"),
从 OpenSSL 3.0 开始,provider、
mac 和 ctx 也可用。
openssl.luaossl_compat
语法: openssl.luaossl_compat()
提供使用 camelCase 命名的 luaossl 风格 API;用户可以期望直接替换。
例如,pkey:get_parameters 映射到 pkey:getParameters。
请注意,并非所有 luaossl API 都已实现,请查看 readme 以获取权威信息。
openssl.get_fips_mode
语法: enabled = openssl.get_fips_mode()
返回一个布尔值,指示 FIPS 模式是否已启用。
openssl.set_fips_mode
语法: ok, err = openssl.set_fips_mode(enabled)
切换 FIPS 模式的开启或关闭。
lua-resty-openssl 支持以下模式:
带有 fips 2.0 模块的 OpenSSL 1.0.2 系列
根据安全策略编译模块,
OpenSSL 3 FIPS provider
参考 https://wiki.openssl.org/index.php/OpenSSL_3.0 第 7 节 根据指南编译 provider,安装与 FIPS provider fips.so 哈希匹配的 fipsmodule.cnf。
从 OpenSSL 3.0 开始,此函数还会开启和关闭 EVP 函数的默认属性。当开启时,所有使用 EVP_* API 的应用程序将被重定向到符合 FIPS 标准的实现,并且无法访问不符合 FIPS 标准的算法。
调用此函数等同于加载 fips provider 并调用 openssl.set_default_properties("fips=yes")。
如果 FIPS provider 已加载但未设置默认属性,请使用以下方法显式获取 FIPS 实现。
local provider = require "resty.openssl.provider"
assert(provider.load("fips"))
local cipher = require "resty.openssl.cipher"
local c = assert(cipher.new("aes256"))
print(c:get_provider_name()) -- 打印 "default"
local c = assert(cipher.new("aes256", "fips=yes"))
print(c:get_provider_name()) -- 打印 "fips"
openssl.get_fips_version_text
语法: text, err = openssl.get_fips_version_text()
返回 FIPS 模块的版本文本,适用于 OpenSSL 3.0 或更高版本。
openssl.set_default_properties
语法: ok, err = openssl.set_default_properties(props)
为所有未来的 EVP 算法获取(隐式和显式)设置默认属性。有关隐式和显式获取的信息,请参阅 crypto(7) 中的 "ALGORITHM FETCHING"。
openssl.list_cipher_algorithms
语法: ret = openssl.list_cipher_algorithms(hide_provider?)
以数组形式返回可用的密码算法。设置 hide_provider 为 true 以从结果中隐藏 provider 名称。
openssl.list_digest_algorithms
语法: ret = openssl.list_digest_algorithms(hide_provider?)
以数组形式返回可用的摘要算法。设置 hide_provider 为 true 以从结果中隐藏 provider 名称。
openssl.list_mac_algorithms
语法: ret = openssl.list_mac_algorithms(hide_provider?)
以数组形式返回可用的 MAC 算法。设置 hide_provider 为 true 以从结果中隐藏 provider 名称。
openssl.list_kdf_algorithms
语法: ret = openssl.list_kdf_algorithms(hide_provider?)
以数组形式返回可用的 KDF 算法。设置 hide_provider 为 true 以从结果中隐藏 provider 名称。
openssl.list_ssl_ciphers
语法: cipher_string, err = openssl.list_ssl_ciphers(cipher_list?, ciphersuites?, protocol?)
以字符串形式返回默认的 SSL 密码套件。cipher_list(TLSv1.3 之前)和 ciphersuites(TLSv1.3)可用于扩展与 protocol 匹配的密码设置。OpenSSL 4.x 拒绝 "SSLv3",因为 SSLv3 支持已被移除。
openssl.list_ssl_ciphers()
openssl.list_ssl_ciphers("ECDHE-ECDSA-AES128-SHA")
openssl.list_ssl_ciphers("ECDHE-ECDSA-AES128-SHA", nil, "TLSv1.2")
openssl.list_ssl_ciphers("ECDHE-ECDSA-AES128-SHA", "TLS_CHACHA20_POLY1305_SHA256", "TLSv1.3")
resty.openssl.ctx
提供 OSSL_LIB_CTX 上下文切换的模块。
OSSL_LIB_CTX 是 OpenSSL 内部库上下文类型。应用程序可以自行分配,但也可以使用 NULL 来使用带有 OSSL_LIB_CTX 参数的函数的默认上下文。
有关更深入的阅读,请参阅 OSSL_LIB_CTX.3。
当前上下文对以下模块有效:
此模块适用于 OpenSSL 3.0 或更高版本。
ctx.new
语法: ok, err = ctx.new(request_context_only?, conf_file?)
创建一个新的上下文,并将其用作此模块的默认上下文。当 request_context_only 设置为 true 时,该上下文仅在当前请求的上下文中使用。conf_file 可选地指定用于创建上下文的 OpenSSL conf 文件。
创建的上下文会随着其给定的生命周期自动释放。
-- 仅为当前请求从给定的 provider 实现初始化一个 AES 密码实例,
-- 不干扰其他代码部分或未来请求使用相同的算法。
assert(require("resty.openssl.ctx").new(true))
local p = assert(require("resty.openssl.provider").load("myprovider"))
local c = require("resty.openssl.cipher").new("aes256")
print(c:encrypt(string.rep("0", 32), string.rep("0", 16), "🦢"))
-- 无需释放 provider 和 ctx,它们会被自动 GC
ctx.free
语法: ctx.free(request_context_only?)
释放先前由 ctx.new 创建的上下文。
resty.openssl.err
提供错误消息的模块。
err.format_error
语法: msg = err.format_error(ctx_msg?, return_code?, all_errors?)
语法: msg = err.format_all_errors(ctx_msg?, return_code?)
返回最后一个错误码的最新错误消息。错误格式如下:
[ctx_msg]: https://github.com/fffonion/lua-resty-openssl/blob/1.9.0/code: [return_code]: error:[error code]:[library name]:[func name]:[reason string]:[file name]:[line number]:
对于早于 3.0 的 OpenSSL 版本,错误格式如下:
[ctx_msg]: https://github.com/fffonion/lua-resty-openssl/blob/1.9.0/code: [return_code]: [file name]:[line number]:error:[error code]:[library name]:[func name]:[reason string]:
如果 all_errors 设置为 true,则所有错误(不仅仅是最后一个)将以单个字符串形式返回。此库内部抛出的所有错误仅抛出最新错误。
例如:
local f = io.open("t/fixtures/ec_key_encrypted.pem"):read("*a")
local privkey, err = require("resty.openssl.pkey").new(f, {
format = "PEM",
type = "pr",
passphrase = "wrongpasswrod",
})
ngx.say(err)
-- pkey.new:load_key: error:4800065:PEM routines:PEM_do_header:bad decrypt:crypto/pem/pem_lib.c:467:
err.get_last_error_code
语法: code = err.get_last_error_code()
返回最后一个错误码。
err.get_lib_error_string
语法: lib_error_message = err.get_lib_error_string(code?)
以字符串形式返回最后一个错误码的库名称。如果设置了 code,则返回与提供的错误码对应的库名称。
err.get_reason_error_string
语法: reason_error_message = err.get_reason_error_string(code?)
以字符串形式返回最后一个错误码的原因。如果设置了 code,则返回与提供的错误码对应的原因。
resty.openssl.version
提供版本信息的模块。
resty.openssl.provider
与 providers 交互的模块。此模块仅适用于 OpenSSL 3.0 或更高版本。
provider.load
语法: pro, err = provider.load(name, try?)
加载名为 name 的 provider。如果 try 设置为 true,则当 provider 无法加载和初始化时,OpenSSL 不会禁用后备 providers。但是,如果 provider 加载成功,后备 providers 将被禁用。
默认情况下,此函数将 provider 加载到默认上下文中,这意味着它会影响同一进程中使用默认上下文的其他应用程序。如果不需要这种行为,请考虑使用 ctx 将 provider 仅加载到有限范围内。
provider.istype
语法: ok = pkey.provider(table)
如果 table 是 provider 的实例,则返回 true。否则返回 false。
provider.is_available
语法: ok, err = provider.is_available(name)
检查指定名称的 provider 是否可用于使用。
provider.set_default_search_path
语法: ok, err = provider.set_default_search_path(name)
指定用于查找 providers 的默认搜索路径。
provider:unload
语法: ok, err = pro:unload(name)
卸载先前由 provider.load 加载的 provider。
provider:self_test
语法: ok, err = pro:self_test(name)
按需运行 provider 的自检。如果自检失败,则 provider 将无法提供任何进一步的服务和算法。
provider:get_params
语法: ok, err = pro:get_params(key1, key2?...)
返回一个或多个 provider 参数值。
local pro = require "resty.openssl.provider"
local p = pro.load("default")
local name = assert(p:get_params("name"))
print(name)
-- 输出 "OpenSSL Default Provider"
local result = assert(p:get_params("name", "version", "buildinfo", "status"))
print(require("cjson").encode(result))
-- 输出 provider 元数据;version 和 buildinfo 因 OpenSSL 版本而异
resty.openssl.pkey
与私钥和公钥(EVP_PKEY)交互的模块。
每种密钥类型可能仅支持部分操作:
| 密钥类型 | 加载现有密钥 | 密钥生成 | 加密/解密 | 签名/验证 | 密钥交换 | 封装/解封装 |
|---|---|---|---|---|---|---|
| RSA | 是 | 是 | 是 | 是 | 是 (RSASVE, OpenSSL 3.5+) | |
| DH | 是 | 是 | 是 | |||
| EC | 是 | 是 | 是 (ECDSA) | 是 (ECDH) | 是 (DHKEM, OpenSSL 3.5+) | |
| Ed25519 | 是 | 是 | 是 (PureEdDSA) | |||
| X25519 | 是 | 是 | 是 (ECDH) | 是 (DHKEM, OpenSSL 3.5+) | ||
| Ed448 | 是 | 是 | 是 (PureEdDSA) | |||
| X448 | 是 | 是 | 是 (ECDH) | 是 (DHKEM, OpenSSL 3.5+) | ||
| ML-DSA (OpenSSL 3.5+) | 是 | 是 | 是 | |||
| SLH-DSA (OpenSSL 3.5+) | 是 | 是 | 是 | |||
| ML-KEM (OpenSSL 3.5+) | 是 | 是 | 是 | |||
| ML-KEM TLS hybrid (OpenSSL 3.5+) | 取决于 Provider | 是 | 是 |
EC 和 ECX 密钥不直接支持加密和解密,但可以通过 pkey:derive、 kdf 和 cipher 实现 ECIES 等过程。
pkey.new
加载现有密钥
语法: pk, err = pkey.new(string, opts?)
支持加载以 PEM、DER 或 JWK 格式作为第一个参数 string 传入的私钥或公钥。
第二个参数 opts 接受一个可选的表来约束密钥加载行为。
opts.format:显式设置为"PEM"、"DER"、"JWK"以加载特定格式,或设置为"*"以自动检测opts.type:显式设置为"pr"表示私钥,"pu"表示公钥;设置为"*"以自动检测
加载 PEM 编码的 RSA 密钥时,它可以是 PKCS#8 编码的 SubjectPublicKeyInfo/PrivateKeyInfo,也可以是 PKCS#1 编码的 RSAPublicKey/RSAPrivateKey。
加载加密的 PEM 编码密钥时,用于解密的 passphrase 可以设置在 opts.passphrase 或 opts.passphrase_cb 中:
pkey.new(pem_or_der_text, {
format = "*", -- 选择 "PEM"、"DER"、"JWK" 或 "*" 以自动检测
type = "*", -- 选择 "pr" 表示私钥,"pu" 表示公钥,"*" 表示自动检测
passphrase = "secret password", -- PEM 加密口令
passphrase_cb = function()
return "secret password"
end, -- PEM 加密口令回调函数
}
加载 JWK 时,有几点需要注意:
- 确保传入的是编码后的 JSON 文本,它必须已经过 base64 解码。
- 约束 opts.type 用于 JWK 密钥需要 OpenSSL 3.0 或更高版本以及 lua-resty-openssl 1.6.0 或更高版本。对于 OpenSSL 1.1.1 或更旧的 lua-resty-openssl 版本,提供的 JSON 中的参数将决定加载的是私钥还是公钥,指定 type 将导致错误;此外,OKP 密钥的公钥部分(x 参数)不被识别,如果指定了私钥部分(d 参数),则会从中派生。
- 仅支持 RSA、P-256、P-384 和 P-512 EC、Ed25519、X25519、Ed448 和 X448 OKP 密钥类型。
- 对于 EC 密钥,签名和验证必须使用 ecdsa_use_raw 选项才能与 JWS 标准兼容。有关详细信息,请参阅 pkey:sign 和 pkey.verify。
- 在 OpenResty 之外运行时,需要安装 JSON 库(cjson 或 dkjson)和 basexx。
密钥生成
语法: pk, err = pkey.new(config?)
生成新的公钥或私钥。
要生成 RSA 密钥,config 表可以包含 bits 和 exp 字段来控制密钥生成。当省略 config 时,此函数生成一个 exponent 为 65537 的 2048 位 RSA 密钥,等效于:
local key, err = pkey.new({
type = 'RSA',
bits = 2048,
exp = 65537
})
要生成 EC 或 DH 密钥,请参阅 pkey.paramgen 了解 config 表的可能值。例如:
local key, err = pkey.new({
type = 'EC',
curve = 'prime256v1',
})
在 OpenSSL 3.0 或更高版本上,可以通过名称请求由已加载 provider 实现的任何密钥类型。例如,OpenSSL 3.5 或更高版本提供了后量子密钥类型,包括:
local ml_dsa = assert(pkey.new({ type = "ML-DSA-44" }))
local ml_kem = assert(pkey.new({ type = "ML-KEM-768" }))
local slh_dsa = assert(pkey.new({ type = "SLH-DSA-SHA2-128s" }))
config.properties 可用于为这些 provider 原生密钥类型选择 provider 实现。
也可以将 PEM 编码的 EC 或 DH 参数传递给 config.param 以进行密钥生成:
local dhparam = pkey.paramgen({
type = 'DH',
group = 'dh_1024_160'
})
-- 或者
-- local dhparam = io.read("dhparams.pem"):read("*a")
local key, err = pkey.new({
type = 'DH',
param = dhparam,
})
也可以在 config 表中传递原始 pkeyopt 控制字符串,如 genpkey CLI 程序中所用。
有关选项列表,请参阅 openssl-genpkey(1)。
例如:
pkey.new({
type = 'RSA',
bits = 2048,
exp = 65537,
})
-- 等同于
pkey.new({
type = 'RSA',
exp = 65537,
"rsa_keygen_bits:4096",
})
密钥组合
语法: pk, err = pkey.new(config?)
使用现有参数组合公钥或私钥。要查看每种密钥的参数列表,请参阅 pkey:set_parameters。
config 表中应仅包含 type 和 params,所有其他键将被忽略。
local private_bn = require "resty.openssl.bn".new("7F48282CCA4C1A65D589C06DBE9C42AE50FBFFDF3A18CBB48498E1DE47F11BE1A3486CD8FA950D68F111970F922279D8", 16)
local p_384, err = assert(require("resty.openssl.pkey").new({
type = "EC",
params = {
private = private_bn,
group = "secp384r1",
}
}))
pkey.istype
语法: ok = pkey.istype(table)
如果 table 是 pkey 的实例,则返回 true。否则返回 false。
pkey.paramgen
语法: pem_txt, err = pk.paramgen(config)
为 EC 或 DH 密钥生成参数,并输出为 PEM 编码文本。
对于 EC 密钥:
| 参数 | 描述 |
|---|---|
| type | "EC" |
| curve | EC 曲线。如果省略,默认为 "prime192v1"。要查看支持的 EC 曲线列表,请使用 openssl ecparam -list_curves。 |
对于 DH 密钥:
| 参数 | 描述 |
|---|---|
| type | "DH" |
| bits | 生成一个具有 bits 长素数的新 DH 参数。如果省略,默认为 2048。从 OpenSSL 3.0 开始,仅允许 bits 等于 2048。 |
| group | 使用预定义组而不是生成新组。如果设置了 group,bit 将被忽略。 |
group 的可能值为:
- RFC7919 "ffdhe2048"、"ffdhe3072"、
"ffdhe4096"、"ffdhe6144"、"ffdhe8192"
- RFC5114 "dh_1024_160"、"dh_2048_224"、"dh_2048_256"
- RFC3526 "modp_1536"、"modp_2048"、
"modp_3072"、"modp_4096"、"modp_6144"、"modp_8192"
local pem, err = pkey.paramgen({
type = 'EC',
curve = 'prime192v1',
})
local pem, err = pkey.paramgen({
type = 'DH',
group = 'ffdhe4096',
})
也可以在 config 表中传递原始 pkeyopt 控制字符串,如 genpkey CLI 程序中所用。
有关选项列表,请参阅 openssl-genpkey(1)。
pkey:get_provider_name
语法: name = pkey:get_provider_name()
返回 pkey 的 provider 名称。
此函数适用于 OpenSSL 3.0 或更高版本。
pkey:gettable_params、pkey:settable_params、pkey:get_param、pkey:set_params
查询可设置或可获取的参数,并设置或获取参数。 请参阅 通用 EVP 参数获取器/设置器。
pkey:get_parameters
语法: parameters, err = pk:get_parameters()
返回包含 pkey 实例 parameters 的表。
对于 ECX 密钥以及 OpenSSL 3 provider 原生密钥(如 ML-KEM、ML-DSA、SLH-DSA 和 ML-KEM TLS hybrid 密钥),当 provider 允许导出这些组件时,该表会暴露二进制的 public 和 private 字段。某些 provider 有意不导出私钥组件。
pkey:set_parameters
语法: ok, err = pk:set_parameters(params)
从表 params 设置 pkey 的参数。如果 params 表中未设置该参数,则 pkey 实例中的该参数保持不变。
对于 ECX 密钥以及 OpenSSL 3 provider 原生密钥,public 和 private 包含原始二进制密钥组件。设置任一组件都会替换底层不可变的 provider 密钥,同时保留 pkey 对象。
local pk, err = require("resty.openssl.pkey").new()
local parameters, err = pk:get_parameters()
local e = parameters.e
ngx.say(e:to_number())
-- 输出 65537
local ok, err = pk:set_parameters({
e = require("resty.openssl.bn").from_hex("100001")
})
local ok, err = pk:set_parameters(parameters)
RSA 密钥的参数:
| 参数 | 描述 | 类型 |
|---|---|---|
| n | 公钥和私钥共有的模数 | bn |
| e | 公开指数 | bn |
| d | 私有指数 | bn |
| p | n 的第一个因子 | bn |
| q | n 的第二个因子 | bn |
| dmp1 | d mod (p - 1),指数1 |
bn |
| dmq1 | d mod (q - 1),指数2 |
bn |
| iqmp | (InverseQ)(q) = 1 mod p,系数 |
bn |
EC 密钥的参数:
| 参数 | 描述 | 类型 |
|---|---|---|
| private | 私钥 | bn |
| public | 公钥 | bn |
| x | 公钥的 x 坐标 | bn |
| y | 公钥的 y 坐标 | bn |
| group | 命名曲线组 | [NID] 作为数字,当作为 set_parameters() 传入时,也可以使用文本表示。这与 luaossl 不同,后者返回 EC_GROUP 实例。 |
不能同时设置 x、y 和 public,因为 x 和 y 基本上是 public 的另一种表示形式。此外,目前只能同时设置 x 和 y。
DH 密钥的参数:
| 参数 | 描述 | 类型 |
|---|---|---|
| private | 私钥 | bn |
| public | 公钥 | bn |
| p | 素数模数 | bn |
| q | 参考位置 | bn |
| g | 基础生成器 | bn |
Curve25519 和 Curve448 密钥的参数:
| 参数 | 描述 | 类型 |
|---|---|---|
| private | 以字节表示的原始私钥 | string |
| public | 以字节表示的原始公钥 | string |
pkey:is_private
语法: ok = pk:is_private()
检查 pk 是否为私钥。如果是私钥则返回 true,如果是公钥则返回 false。
pkey:get_key_type
语法: obj, err = pk:get_key_type(nid_only?)
以表的形式返回私钥密钥类型的 ASN1_OBJECT。
从 lua-resty-openssl 1.6.0 开始,可以设置可选参数 nid_only 为 true,仅返回密钥的数字 NID。
在 OpenSSL 3.0 或更高版本上,此方法为现有密钥类型保留历史 NID 和 ASN.1 表。具有指定 OID 的标准化后量子密钥类型(如 ML-KEM、ML-DSA 和 SLH-DSA)使用其 OID NID 返回相同的表结构。没有指定 OID 的仅 provider 密钥类型返回 nil 和错误,而不是合成 NID。
local pkey, err = require("resty.openssl.pkey").new({type="X448"})
ngx.say(require("cjson").encode(pkey:get_key_type()))
-- 输出 '{"ln":"X448","nid":1035,"sn":"X448","id":"1.3.101.111"}'
ngx.say(pkey:get_key_type(true))
-- 输出 1035
pkey:get_size
语法: size, err = pk:get_size()
返回几乎所有可以使用 pkey 完成的操作的输出缓冲区的最大合适大小。
对于 RSA 密钥,这是模数的大小。 对于 EC、Ed25519 和 Ed448 密钥,这是私钥的大小。 对于 DH 密钥,这是素数模数的大小。
pkey:get_default_digest_type
语法: obj, err = pk:get_default_digest_type()
以表的形式返回私钥密钥类型的 ASN1_OBJECT。表中还会返回一个额外的字段 mandatory,如果 mandatory 为 true,则不能使用其他摘要。
local pkey, err = require("resty.openssl.pkey").new()
ngx.say(require("cjson").encode(pkey:get_default_digest_type()))
-- 输出 '{"ln":"sha256","nid":672,"id":"2.16.840.1.101.3.4.2.1","mandatory":false,"sn":"SHA256"}'
pkey:sign
语法: signature, err = pk:sign(digest)
语法: signature, err = pk:sign(message, md_alg?, padding?, opts?)
使用 pkey 实例中定义的私钥执行摘要签名。第一个参数必须是 resty.openssl.digest 实例或字符串。返回签名文本和错误(如果有)。
当第一个参数传递 digest 实例时,不应已调用 final();用户应仅使用 update()。此模式仅支持 RSA 和 EC 密钥。
当第一个参数传递字符串时,md_alg 参数将指定签名时要使用的名称。当 md_alg 未定义时,对于 RSA 和 EC 密钥,此函数默认执行 SHA256。对于 Ed25519 或 Ed448 密钥,此函数执行 PureEdDSA 签名,不应指定消息摘要,也不会使用。
对于 RSA 密钥,还可以使用以下选项指定 padding 方案:
pkey.PADDINGS = {
RSA_PKCS1_PADDING = 1,
RSA_SSLV23_PADDING = 2,
RSA_NO_PADDING = 3,
RSA_PKCS1_OAEP_PADDING = 4,
RSA_X931_PADDING = 5, -- 仅签名
RSA_PKCS1_PSS_PADDING = 6, -- 仅签名和验证
}
当 padding 为 RSA_PKCS1_PSS_PADDING 时,可以通过设置 opts.pss_saltlen 来指定 PSS 盐长度。
对于 EC 密钥,此函数执行 ECDSA 签名。 请注意,OpenSSL 不支持使用