MongoDB 内嵌 RNP 0.18.1:解读 OpenPGP 库 CHANGELOG 的版本演进、安全修复与 FFI 演进
【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo
本文以 MongoDB 仓库中内嵌的 RNP 第三方库变更日志 src/third_party/rnp/dist/CHANGELOG.md 为主体,完整梳理 RNP(一个高性能 C++ OpenPGP 实现)从 0.9.0 首个正式版本到 0.18.1 的演进脉络:每个版本的 General/FFI/CLI/Security 四类变更、被撤回的 0.18.0 安全事件、可定制安全规则与签名验证语义变化等。读完本文,你将了解 RNP 各版本的能力边界与破坏性变更,以及 MongoDB 是如何把 RNP 0.18.1(OpenSSL 后端)集成进 Bazel 构建、用于扩展(Extension)签名验证的。
一、RNP 在 MongoDB 仓库中的角色:先明确“这份 CHANGELOG 是谁的”
RNP 是 Ribose 出品的 OpenPGP 实现库,提供 CLI 工具(rnp/rnpkeys)、C FFI(librnp)和 C++ 内部库(librepgp/librekey)。在 MongoDB 仓库中,它以 vendor 源码树的形式位于 src/third_party/rnp/,仓库中 BUILD.bazel 的注释写明其定位:
# RNP - A high performance C++ OpenPGP library # License: BSD-2-Clause # NOTE: RNP is only supported on Linux platforms with OpenSSL.也就是说,MongoDB 只在内嵌 RNP 的Linux + OpenSSL 后端子集上构建它,并按 CMake 产物拆成了若干 Bazel target:sexpp(S-表达式解析子库)、rnp_common、rnp_librepgp(PGP 包处理)、rnp_librekey(密钥环处理)、rnp_generated_headers(CMake configure 生成的config.h/version.h)以及主库rnp(其中显式列出了全部 OpenSSL 后端源文件,如rsa_ossl.cpp、hash_ossl.cpp、cipher_ossl.cpp,并链接-lcrypto)。
MongoDB 使用 RNP 的实际场景是扩展签名验证:src/mongo/db/extension/host/rnp/rnp.h 对 RNP FFI 做了 C++ 封装(RnpInput、RnpContext等 RAII 包装类,注释说明“extensions are only expected to be signed with a single key”),再由 src/mongo/db/extension/host/signature_validator.cpp 用于校验从 mongod 宿主加载的扩展模块的 OpenPGP 签名。因此,本 CHANGELOG 中所有 FFI(尤其rnp_op_verify_*系列)与 Security 章节的语义变化,都直接关系到这条签名验证链路的正确性与安全性。
二、当前版本:0.18.1 是安全修复版,0.18.0 已被撤回
CHANGELOG 最新两条记录构成了当前版本最重要的事实:
0.18.0 [2025-05-24] —— RETRACTED, DON'T USE
CHANGELOG 在 0.18.0 标题上直接标注“RETRACTED, DON'T USE”,并给出安全警告:该版本存在严重漏洞——公钥加密消息使用全零会话密钥(all-zero session keys),所有用户必须立即升级到 0.18.1 或更高版本。
0.18.1 [2025-11-21]
0.18.1 的 Security 章节修复的正是上述问题:
Fixed critical issue where PKESK (public-key encrypted) session keys were generated as all-zero, allowing trivial decryption of messages encrypted with public keys only (CVE-PENDING).
即 PKESK(公钥加密会话密钥)包被生成为全零,导致仅用公钥加密的消息可以被平凡地解密。这属于加密路径上的严重正确性缺陷,MongoDB 仓库通过 scripts/import.sh 中的VERSION=0.18.1钉住该版本,与 CHANGELOG 的修复结论一致。
0.18.0/0.18.1 的 General 章节还包含一批有实际影响的能力变更(这些是 0.18 系列相对 0.17.x 的主要差异):
- 默认生成 RSA 3072 位密钥(不再使用更小的默认位长);
- 不再默认允许 64 位密码算法用于加密,除非显式指定选项;
- 不鼓励使用 EAX AEAD 模式(延续 0.17.0 中“AEAD 默认 OCB 而非 EAX”的方向);
- 支持导入 GnuPG-armored 文件(带 ARMORED FILE 头)的 dearmoring;
- 支持 DSA 4096 位密钥(因为部分实体在使用);
- 由仅加密密钥/子密钥产生的签名被标记为无效;
- 密钥过期时间变更时,从弱哈希函数自动升级;
- 导入 armored 密钥时允许多余空格;
- 更好地支持 Botan 3.5.0+,以及各系统的兼容性修复、内部重构与性能更新。
FFI 新增(0.18.0)
rnp_signature_error_count()/rnp_signature_error_at():用于检查签名验证失败的具体原因——这对 MongoDB 的扩展签名验证器非常有用,可以把“验证失败”细化为可诊断的错误;rnp_key_certification_create()及rnp_key_signature_set_*/rnp_key_signature_get_*:创建与定制密钥认证签名。
三、Botan 3 / OpenSSL 3 支持:0.17.x 里程碑
0.17.1 [2024-04-08]
- 新增Botan 3支持;
- 更新OpenSSL 3支持(这是 MongoDB 选择 OpenSSL 后端路径时的关键版本依据);
- literal data packet 支持 mimemode;
- 放宽 Base64 解码,允许校验和之后出现空格。
FFI:新增rnp_signature_get_features()。
0.17.0 [2023-05-01]
General 章节的变化点较多,值得逐条理解:
- 解密时支持隐藏接收者(hidden recipient);
- OpenSSL 后端支持AEAD-OCB;
- 改进默认密钥选择时对离线秘密密钥(offline secret keys)的支持;
- 支持 GnuPG 2.3+ 的秘密密钥存储格式;
- SExp 解析代码拆分为独立库 libsexpp(MongoDB 的 Bazel 构建中对应独立的
sexpptarget,并且排除了带main()的sexp-main.cpp,见 BUILD.bazel 中的注释); - 主密钥过期时,子密钥标记为“已过期”而非“无效”;
- AEAD 默认从 EAX 切换为 OCB;
- 不再尝试验证“意外类型”的签名;
- 使用线程安全的时间/日期处理函数;
- 新增构建期选项
ENABLE_BLOWFISH、ENABLE_CAST5、ENABLE_RIPEMD160; - OpenSSL 后端版本 < 1.1.1e 时不使用
EVP_PKEY_CTX_set_dsa_paramgen_q_bits(); - CEK/KEK 算法不一致时修正其用法。
FFI:新增rnp_signature_export();rnp_op_verify_set_flags()新增RNP_VERIFY_ALLOW_HIDDEN_RECIPIENT标志。
CLI(rnp工具):--enarmor增加默认 armor 消息类型;新增--set-filename(指定消息中存储的文件名);--edit-key增加--add-subkey与set-expire子命令;新增--s2k-iterations、--s2k-msec选项;新增--allow-weak-hash允许使用弱哈希算法;导入密钥时报告新增/更新密钥数量。
四、0.16.x:安全规则落地与验证语义收紧
0.16.x 系列是 RNP 安全行为成型的关键区间,四个版本逐层递进。
0.16.3 [2023-04-11](Security)
- 修复畸形输入可能导致的挂起(CVE-2023-29479);
- 修复某些情况下秘密密钥使用完后保持未上锁的问题(CVE-2023-29480)。
这两个都是“不可信输入 → 资源/机密性风险”类型的问题,对像 MongoDB 这样用 RNP 验证外部扩展签名的宿主而言尤为重要:验证路径必须对畸形 OpenPGP 输入保持健壮。
0.16.1 [2022-09-06]
General:确保 RHEL9/CentOS Stream 9/Fedora 36 支持(OpenSSL 3.0 后端适配);可选导入/导出 base64 编码密钥;可选原始(raw)加密;可选覆盖当前时间戳;对未知签名版本、未知 PKESK/SKESK 包版本不再直接失败;支持头部后无空行的 armored 消息;基于后端做自动特性检测。
Security:
- 数据签名与密钥签名分离的安全规则,将 SHA1 密钥签名支持延长到 2024-01-19;
- 默认密钥有效期设为 2 年;
- AEAD 分块位数上限 16。
FFI:
rnp_op_verify_execute()行为变更:现在要求至少一个有效签名才算验证成功(这是语义上的破坏性变化,依赖该函数的宿主必须理解);- 新增
rnp_op_verify_set_flags()以覆盖默认验证行为; - 新增
rnp_key_is_expired(); - 新增
rnp_op_encrypt_set_flags()与RNP_ENCRYPT_NOWRAP(允许原始加密); rnp_import_keys()新增RNP_LOAD_SAVE_BASE64标志;rnp_key_export_autocrypt()新增RNP_KEY_EXPORT_BASE64;- 新增
rnp_set_timestamp()允许覆盖当前时间(用于测试/复现); - 安全规则函数引入
RNP_SECURITY_VERIFY_KEY与RNP_SECURITY_VERIFY_DATA标志。
CLI:--source(指定分离签名的源文件)、--no-wrap(原始数据加密)、--current-time(覆盖时间戳);解密/验签时剥离.pgp/.asc等已知扩展名;密钥列表中显示密钥与签名有效性状态等。
0.16.0 [2022-01-20]
这一版最大的 General 变化是新增 OpenSSL 加密后端,使 RNP 可以在没有 Botan 的系统上构建和使用——这正是 MongoDB 内嵌版本采用的后端(下文第四节)。其余要点:编译期开关可禁用 AEAD、Brainpool 曲线、SM2/SM3/SM4、Twofish;修复 RNP→GnuPG 导出 x25519 秘密密钥的兼容性问题;支持None压缩算法;改进大签名数量密钥的导入性能等。
Security 章节确立了默认安全基线:
- 新增可定制安全 profile的初步支持(后续版本的安全规则都建立在此之上);
- 2019-01-19 之后产生的 SHA1 签名标记为无效;
- 2012-01-01 之后产生的 MD5 签名标记为无效;
- 默认密钥偏好中移除 SHA1 与 3DES;
- 使用 SHA1 时启用 SHA1 碰撞检测代码(仓库构建中对应
dist/src/lib/crypto/sha1cd/目录与SHA1DC_FORCE_ALIGNED_ACCESS宏); - 带未知 critical notation 的签名标记为无效;
- 提前验证秘密密钥材料;限制消息接收者/签名数量为 16k、限制签名子包数量。
FFI 引入了安全规则操作三件套:rnp_add_security_rule()、rnp_get_security_rule()、rnp_remove_security_rule(),以及rnp_backend_string()/rnp_backend_version()(可在运行时查询后端——MongoDB 的 version.h 中RNP_BACKEND "openssl"正是该机制的构建期产物)。
CLI 增加了-(stdin/stdout)与env:VAR_NAME输入/输出说明符、--notty、算法别名(SHA-256/SHA256等)、--edit-key下的--check-cv25519-bits/--fix-cv25519-bits等。
五、0.14/0.15:健壮性大修与 2038 问题
0.15.x
- 0.15.2 [2021-07-20]:放宽 userid 校验、修复密钥过期时间计算、FFI 新增
rnp_key_get_default_key()(按操作类型挑选默认密钥/子密钥); - 0.15.1 [2021-05-28]:修复 2038 年后密钥过期检查、
rnp_key_valid_till64()正确处理 2038 年后的过期时间、RNP_FEATURE_*宏替代裸字符串;Security 上修复了rnp_key_unprotect()/rnp_key_protect()之后明文密钥数据残留的问题(CVE-2021-33589)——这是典型的敏感数据擦除类漏洞; - 0.15.0 [2021-04-04]:库文件名去主版本(librnp-0.so → librnp.so)、支持离线构建(不下载 Googletest/ruby-rnp)、放宽 armor CRC 缺失为警告、FFI 新增
rnp_signature_remove、rnp_uid_remove、rnp_key_remove_signatures等。
0.14.0 [2021-01-15]
这是 CHANGELOG 中篇幅最长的一个版本,集中体现了 RNP 向“可处理真实世界畸形输入”的成熟过程:
- 密钥校验要求至少一个有效、未过期的自签名;
- 支持无 userid/认证但带有效子密钥绑定签名的“stripped”密钥;
- 修复 MDC 位于 8k 边界时的读取问题、限制 OpenPGP 包嵌套层级、修复多处畸形 armored 输入的崩溃;
- 支持 GnuPG 离线主密钥(
gnupg --export-secret-subkeys)与智能卡密钥; - 修复文本模式签名的 CR 处理、修复符号可见性使库只导出 FFI 函数;
- 内部代码大规模迁移到 C++(这也解释了为何 MongoDB 的 Bazel 目标全部以
.cppglob 组织); - 默认改用最新的加密子密钥加密。
FFI 层面,0.14.0 补齐了撤销签名(rnp_key_export_revocation、rnp_key_revoke)、密码回调(rnp_request_password)、保护信息查询(rnp_key_get_protection_type等)、autocrypt 导出(rnp_key_export_autocrypt)、异常守卫(FFI 边界)等能力;并新增RNP_LOAD_SAVE_PERMISSIVE(跳过错误包)、RNP_LOAD_SAVE_SINGLE导入标志。Security 章节则记录了启用 oss-fuzz 模糊测试、移除 armor 版本头等。
六、0.12–0.13:曲线扩展、JSON 生成 API 与打包
- 0.13.0 [2019-12-31]:修复 armor 头 double-free、截断 armored 密钥的无限循环;DSA 默认 qbits 改进;FFI 引入非 JSON 的新密钥生成 API(
rnp_op_generate_create等)、rnp_unload_keys/rnp_key_remove、密钥属性访问器(rnp_key_get_bits、rnp_key_get_curve)、rnp_supports_feature/rnp_supported_features、rnp_guess_contents等;打包上将 RPM 拆为librnp0/librnp0-devel/rnp0。0.13.1 [2020-01-15] 单独修复了rnpkeys可能生成未保护秘密密钥的问题(issue #1030)——对密钥管理工具是严重缺陷。 - 0.12.0 [2019-01-13]:要求 Botan 2.8+;修复多种密钥类型的 key grip 计算;修复 SM2 签名“对消息哈希再哈希”的问题;新增 G10 ECC 密钥支持与额外曲线:Brainpool p256/p384/p512(ECDSA/ECDH)、secp256k1(ECDSA/ECDH)、x25519;CLI 新增
rnp -f/--keyfile、redumper -g;FFI 新增AEAD 支持。 - 0.11.0 / 0.10.0:动态计算 S2K 迭代次数、从秘密密钥提取公钥、密钥间信息合并;armor 改用 PRIVATE KEY 头;ECDSA 使用匹配哈希做确定性 nonce。
- 0.9.x(2018):首个正式发布 0.9.0;0.9.1 在认证与子密钥绑定中加入 issuer fingerprint;0.9.2 支持签名子密钥的内嵌签名子包、加载时验证密钥材料以提升非对称操作性能。
七、MongoDB 如何消费这份 CHANGELOG 的版本事实
结合仓库证据,可以把 CHANGELOG 与 MongoDB 的集成方式对应起来:
- 版本钉住:src/third_party/rnp/scripts/import.sh 中
VERSION=0.18.1,与 CHANGELOG 最新条目一致,且明确避开了被撤回的 0.18.0。 - 可复现的头文件生成:scripts/build_rnp_headers.sh 在 manylinux_2_28 容器中运行 CMake configure 生成
config.h/version.h,默认CRYPTO_BACKEND=openssl——这与 CHANGELOG 0.16.0 “OpenSSL 后端”条目和 0.17.1 “OpenSSL 3 支持”条目直接对应。 - 生成头中的能力快照:dist/build/src/lib/version.h 记录了内嵌版本的关键事实:
RNP_VERSION_STRING "0.18.1"、RNP_BACKEND "openssl"(构建时用 OpenSSL 1.1.1k)、RNP_HAS_AEAD 1且RNP_HAS_AEAD_OCB 1/RNP_HAS_AEAD_EAX 0——这正好印证了 CHANGELOG 中 0.17.0 “AEAD 默认 OCB”与 0.18.0 “不鼓励 EAX”的演进结果;RNP_HAS_BLOWFISH/CAST5/RIPEMD160/IDEA 1则对应 0.17.0 新增的ENABLE_BLOWFISH/ENABLE_CAST5/ENABLE_RIPEMD160编译开关。 - 消费链路:src/mongo/db/extension/host/rnp/BUILD.bazel 将封装库依赖到
//src/third_party/rnp,并同样限制为 Linux(排除 Amazon Linux 2);signature_validator.cpp 通过RnpContext导入单个公钥并执行 OpenPGP 验证。由于 MongoDB 走的是 FFI 验证路径,CHANGELOG 中 0.16.1 关于rnp_op_verify_execute()的语义收紧(要求至少一个有效签名)、0.14.0 的 FFI 异常守卫,以及 0.18.0 的rnp_signature_error_count()/rnp_signature_error_at(),都是与该链路直接相关的行为事实。
八、如何核对与延伸阅读
- 完整变更明细以 src/third_party/rnp/dist/CHANGELOG.md 为准,本文按版本区间重组,未删改条目语义;
- FFI 函数声明位于 src/third_party/rnp/dist/include/rnp/ 下的公共头文件,可对照 CHANGELOG 中的函数名逐一查看原型;
- 构建集成细节见 src/third_party/rnp/BUILD.bazel 与 src/third_party/rnp/scripts/import.sh;
- MongoDB 侧的使用封装见 src/mongo/db/extension/host/rnp/rnp.h、rnp.cpp 与 signature_validator.h。
适用前提与限制:以上所有版本事实均针对仓库内嵌的 RNP 0.18.1(OpenSSL 后端);MongoDB 的构建目标将 RNP 限定在 Linux 平台(且排除 OpenSSL 版本不足的 Amazon Linux 2),非 Linux 平台上相关 Bazel target 被标记为 incompatible。RNP 的默认安全规则(SHA1/MD5 签名失效阈值、默认密钥有效期等)随版本演进,如需调整验证行为,应基于 0.16.0 引入的安全规则 FFI(rnp_add_security_rule()等)显式配置,而不是依赖默认值。
【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考