ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Erlang/OTP Public_Key 应用深度指南:公钥基础设施、PKIX 证书链与数字签名

Erlang/OTP Public_Key 应用深度指南:公钥基础设施、PKIX 证书链与数字签名 编程语言语言运行时标准库编译器并发编程【免费下载链接】otpErlang/OTP项目地址https://gitcode.com/gh_mirrors/ot/otp点击查看免费下载导读本文围绕 Erlang/OTP 中负责公钥基础设施Public Key Infrastructure的public_key应用展开系统梳理其库应用、纯内存二进制处理的设计定位、完整支持的 PKIX 标准族、与crypto/asn1的依赖关系以及唯一例外的系统 CA 证书加载接口cacerts_load/0,1与cacerts_get/0。读完本文你将掌握 public_key 的模块架构与核心 API 分布理解 X.509 证书、CRL、数字签名、证书路径验证与主机名校验在 OTP 中的落地方式并能直接上手 PEM 编解码、RSA 加解密、签名验签等实战操作。Public_Key 应用定位库应用不碰文件系统public_key应用处理与公钥相关的文件格式、数字签名以及 X.509 证书RFC 5280相关的全部工作包括证书路径certificate path验证证书吊销列表CRLCertificate Revocation List验证证书、密钥、CRL 的其他处理功能。其最核心的设计约束是它是一个库应用library application自身不读写文件。它期望的输入、返回的输出都是文件内容或部分文件内容的二进制形式binary。也就是说调用方需要自行完成file:read_file/1、file:write_file/2这类文件操作把内容以 binary 交给 public_key 处理。唯一的例外是以下三个函数会真正读取文件public_key:cacerts_load/0public_key:cacerts_load/1public_key:cacerts_get/0它们用于加载操作系统提供的受信任 CA 证书细节见下文唯一的文件读取例外一节。这一设计在 public_key.erl 的模块文档中亦有呼应所有记录的 ASN.1 结构由规范生成并通过-include_lib(public_key/include/public_key.hrl)提供给用户使用。支持的 PKIX 功能全景public_key对 PKIX 相关标准的支持覆盖证书、密钥、消息语法三大类完整清单如下对应 public_key_app.md 的 Supported PKIX functionality 一节标准内容仓库中的 ASN.1 规范证据RFC 5280Internet X.509 公钥基础设施证书与 CRL 配置文件证书策略Certificate policies自 OTP-26.2 起支持OTP-PKIX.asn1、OTP-PKIX-Relaxed.asn1PKCS-1RFC 3447RSA 密码学标准PKCS-1.asn1DSSFIPS 186-3数字签名标准DSA 数字签名算法DSS.asn1PKCS-3Diffie-Hellman 密钥协商标准PKCS-3.asn1CMSRFC 5652密码消息语法含基于原始 PKCS-5 的密码加密PBE目前暂不官方支持第 10~12 节的大部分内容例如属性证书 v2若证明有用将来可能加入CryptographicMessageSyntax-2009.asn1、CryptographicMessageSyntaxAlgorithms-2009.asn1PKCS-8RFC 5208私钥信息语法标准由 OTP-PKIX.asn1 及 PKCS-FRAME.set.asn 覆盖PKCS-10RFC 5967证书请求语法标准PKCS-10.asn1PKIXCMPRFC 9810证书管理协议PKIXCMP-2023.asn1PKIXCRMFRFC 5912证书请求消息格式PKIXCRMF-2009.asn1这些 ASN.1 模块并不是纸上标准——它们全部在 public_key.app.src 的modules列表中登记为应用模块如PKIXCMP-2023、PKIXCRMF-2009、OCSP-2024-08、PKCS-1、DSS等由 asn1 编译器在构建期生成 Erlang 编解码代码供public_key的各个pubkey_*模块调用。从该列表还可以看出仓库正在持续跟进新标准SLH-DSA-Module-2024、X509-ML-DSA-2025、X509-ML-KEM-2025、KEMAlgorithmInformation-2023等后量子签名与密钥封装算法模块已纳入应用清单可以推断后续版本会逐步开放相应算法能力。依赖关系与启动顺序public_key的运作建立在两个底层应用之上Crypto 应用负责执行底层密码学运算RSA/DSA/ECC 加解密、哈希、签名原语等ASN.1 应用负责处理 PKIX-ASN.1 规范即上表中的 ASN.1 模块的编译与运行。因此这两个应用必须先被加载public_key才能正常工作。在 public_key.app.src 中可以确认完整的依赖声明{applications, [asn1, crypto, kernel, stdlib]}, {runtime_dependencies, [stdlib-4.0,kernel-8.0,erts-13.0, crypto-5.8,asn1-5.0]}在嵌入式embedded环境中依赖应用不会自动启动必须在启动public_key之前显式调用application:start/[1,2]依次启动asn1、crypto等依赖。典型顺序application:start(asn1), application:start(crypto), application:start(public_key).从源码结构看public_key自身没有注册进程{registered, []}、也没有环境变量配置{env, []}进一步印证了其纯库应用的属性——它不维护长期运行的进程所有函数都是同步计算并直接返回结果。源码架构模块划分与核心 APIpublic_key的源码集中在 lib/public_key/src按职责拆分为以下模块模块职责public_key.erl唯一对外 API 入口3424 行导出全部公开函数pubkey_cert.erl证书解析、证书路径验证、扩展检查、verify_fun 回调机制pubkey_crl.erlCRL 解析、吊销状态跟踪、CRL 签名验证pubkey_ocsp.erlOCSP在线证书状态协议请求/响应处理pubkey_pem.erlPEM 格式的编解码pubkey_pbe.erl基于密码的加密Password-Based Encryptionpubkey_os_cacerts.erl从操作系统/文件加载受信任 CA 证书pubkey_policy_tree.erl证书策略树处理对应 OTP-26.2 引入的策略支持pubkey_ssh.erlSSH 相关密钥格式dh_gex_group等pubkey_translation.erl不同密钥表示之间的转换核心 API 分组见 public_key.erl 的导出声明格式编解码pem_decode/1、pem_encode/1、pem_entry_decode/1,2、pem_entry_encode/2,3、der_decode/2、der_encode/2、pkix_decode_cert/2、pkix_encode/3加解密encrypt_private/2,3、decrypt_private/2,3、encrypt_public/2,3、decrypt_public/2,3签名验签sign/3,4、verify/4,5密钥处理generate_key/1、compute_key/2,3、dh_gex_group/4、dh_gex_group_sizes/0证书操作pkix_sign/2、pkix_verify/2、pkix_is_self_signed/1、pkix_is_issuer/2、pkix_issuer_id/2、pkix_subject_id/1、pkix_normalize_name/1验证类pkix_path_validation/3、pkix_verify_hostname/2,3、pkix_crls_validate/3、pkix_crl_verify/2、pkix_ocsp_validate/5系统 CA 证书cacerts_get/0、cacerts_load/0,1、cacerts_clear/0。其中证书路径验证pkix_path_validation/3在 pubkey_cert.erl 中实现核心机制是逐证书调用verify_fun回调verify_fun/4类型见 pubkey_cert.erl验证过程会依次检查证书有效期cert_expired、invalid_validity_dates、签发者invalid_issuer、名称约束distinguished_name_not_permitted、name_not_permitted、签名invalid_signature以及扩展约束每一步失败都会以{bad_cert, Reason}元组形式交给用户提供的verify_fun决定接受还是拒绝。CRL 验证则位于 pubkey_crl.erl导出validate/7、init_revokation_state/0、fresh_crl/3、verify_crl_signature/4等接口用于在路径验证过程中查询吊销状态。唯一的文件读取例外系统信任 CA 证书虽然public_key总体不读写文件但系统信任 CA 证书这一组接口是例外它们在 public_key.erl 中定义OTP 25.0 起cacerts_get() - [combined_cert()]返回已加载的受信任 CA 证书若尚未加载则内部调用cacerts_load/0完成加载加载失败时直接抛出{failed_load_cacerts, Reason}错误cacerts_load() - ok | {error, Reason}加载操作系统提供的受信任 CA 证书cacerts_load(File) - ok | {error, Reason}从指定文件加载受信任 CA 证书cacerts_clear() - boolean()清空已加载的 CA 证书缓存若此前确有加载则返回true。底层实现集中在 pubkey_os_cacerts.erl平台分发load/0依据os:type()选择加载策略见 pubkey_os_cacerts.erl——Linux/OpenBSD/FreeBSD/DragonFly/NetBSD 读取各自的标准系统证书路径Solaris 走sunos_paths()macOS 走load_darwin()Windows 通过 NIFos_cacerts/0读取系统证书存储不支持的平台返回{error, {enotsup, Os}}路径覆盖load/1接收文件路径列表并依序尝试可用于在load/0不适用的平台上手动指定证书来源缓存加载结果缓存在persistent_term中get/0首次调用时若缓存为空会先触发加载pubkey_os_cacerts.erl。更重要的是cacerts_path应用环境变量当设置该变量时get/0会优先从该路径加载而不再走操作系统默认位置pubkey_os_cacerts.erl。官方文档给出的命令行设置方式为erl -public_key cacerts_path /path/to/certs.pem使用警告这一覆盖机制需要使用者自行负责。必须确保替代路径中的证书对该运行系统而言是可信任的否则等于主动引入了不可信的信任锚存在安全风险。错误处理模型无错误日志器public_key是库应用不使用错误日志器error logger。所有函数要么成功返回结果要么直接以运行时错误runtime error失败例如cacerts_get/0在无法加载任何 CA 证书时抛出{failed_load_cacerts, Reason}。这意味着调用方需要通过 try/catch 等 Erlang 异常机制自行处理失败而不是依赖日志系统发现问题。这也与库应用不做副作用、纯函数式计算的设计哲学保持一致。实战PEM 编解码、RSA 加解密、签名与主机名校验本节的完整示例来自官方指南 using_public_key.md其中的密钥与证书仅供测试使用。PEM 文件结构PEMPrivacy Enhanced Mail是公钥数据的常见存储格式结构如下text -----BEGIN SOMETHING----- Attribute : Value Base64 encoded DER data -----END SOMETHING----- text一个文件可包含多个BEGIN/END块块间的文本行被忽略属性行除Proc-Type与DEK-Info用于 DER 数据加密场景外均被忽略。文件读取由调用方完成例如1 {ok, PemBin} file:read_file(dsa.pem). {ok,-----BEGIN DSA PRIVATE KEY-----\nMIIBuw...}解码 DSA 私钥2 [DSAEntry] public_key:pem_decode(PemBin). [{DSAPrivateKey,48,130,1,187,..., not_encrypted}] 3 Key public_key:pem_entry_decode(DSAEntry). #DSAPrivateKey{version 0, p 12900045185019966618...6593, q 1216700114794736143432235288305776850295620488937, g 10442040227452349332...47213, y 87256807980030509074...403143, x 510968529856012146351317363807366575075645839654}pem_decode/1返回条目三元组{Type, DerBin, EncInfo}其中EncInfo为not_encrypted或{Cipher, Iv}pem_entry_decode/2的第二个参数即口令。解码带口令的 RSA 私钥2 [RSAEntry] public_key:pem_decode(PemBin). [{RSAPrivateKey,224,108,117,..., {DES-EDE3-CBC,kÙeø¼pµL}}] 3 Key public_key:pem_entry_decode(RSAEntry, abcd1234). #RSAPrivateKey{version two-prime, modulus 1112355156729921663373...2737107, publicExponent 65537, ...}这里的口令解密正是由 pubkey_pbe.erl 配合 PEM 头部的Proc-Type/DEK-Info属性完成的。解码 X.509 证书1 {ok, PemBin} file:read_file(cacerts.pem). 2 [CertEntry1, CertEntry2] public_key:pem_decode(PemBin). 3 Cert public_key:pem_entry_decode(CertEntry1).也可以使用pkix_decode_cert/2它支持两种模式otp模式递归解码为标准 OTP 记录形式#OTPCertificate{}各 RDN 属性值、扩展值均已解出便于程序直接访问如#BasicConstraints{cA true}、[keyCertSign, cRLSign]、[{rfc822Name,petererix.ericsson.se}]plain模式等价于pem_entry_decode/1保持原始 ASN.1 记录。对证书中局部结构的解码可用public_key:der_decode(Type, DerBin)例如按X520CommonName类型解码 CN 值。编码回 PEM 格式1 PemEntry public_key:pem_entry_encode(RSAPublicKey, RSAPubKey). {RSAPublicKey, 48,72,..., not_encrypted} 2 PemBin public_key:pem_encode([PemEntry]). -----BEGIN RSA PUBLIC KEY-----\nMEgC... 3 file:write_file(rsa_pub_key.pem, PemBin). ok若改用SubjectPublicKeyInfo类型则生成标准的-----BEGIN PUBLIC KEY-----块。RSA 公钥加解密%% 私钥加密公钥解密传统数字签名用法 RsaEncrypted public_key:encrypt_private(Msg, PrivateKey), Msg public_key:decrypt_public(RsaEncrypted, PublicKey), %% 公钥加密私钥解密 RsaEncrypted2 public_key:encrypt_public(Msg, PublicKey), Msg public_key:decrypt_private(RsaEncrypted2, PrivateKey),警告该原始 RSA算法已被认为不安全虽然配合适当的 OpenSSL 密码库存在软件层面的防护但难以保证安全性官方强烈建议不要使用见 using_public_key.md 的 Warning。数字签名Signature public_key:sign(Msg, sha, PrivateKey), true public_key:verify(Msg, sha, Signature, PublicKey),若先自行计算摘要则第二个参数传noneDigest crypto:sha(Msg), Signature public_key:sign(Digest, none, PrivateKey), true public_key:verify(Digest, none, Signature, PublicKey),证书路径验证使用pkix_path_validation/3验证证书链可通过verify_fun选项定制每个证书的检查行为pubkey_cert.erl 中路径验证每一步都会回调该函数Opts [{verify_fun, fun(Cert, Event, UserState) - case Event of {bad_cert, Reason} - {fail, Reason}; % 或 {valid, UserState} 放行 {extension, Ext} - {unknown, UserState} % 未知扩展交由应用裁决 end end, UserState}], public_key:pkix_path_validation(TrustedCert, CertChain, Opts).主机名校验RFC 6125当客户端校验服务端证书时除链验证外还需做主机名校验防止 DNS 劫持等攻击——恶意服务器可能持有一张完全合法签名有效、未被吊销、链到可信根但域名不符的证书。public_key:pkix_verify_hostname/2,3实现了 RFC 6125 的默认匹配流程其中关键规则包括证书中的 Presented IDsSubject的 CN 字段或Subject Alternative Name扩展中的dNSName/uniformResourceIdentifier须至少与客户端的 Reference IDs 匹配一个若证书含Subject Alternative Name则禁止再使用Subject的 CN 做校验通配符仅允许出现在第一个标签且只有一个如*.example.com可匹配foo.example.com但不能匹配example.com或foo.bar.example.com国际化域名IDN暂不支持。调用示例public_key:pkix_verify_hostname(CertFromHost, [{uri_id, https://www.example.net}]).对于自定义协议可用fqdn_fun自定义主机名提取、用match_fun重定义匹配逻辑返回true/false/default其中default回退到默认规则。若希望人工钉住pinning一张不匹配的证书类似浏览器的仍然继续提示可传入fail_callback-include_lib(public_key/include/public_key.hrl). % 记录定义 ... Fail fun(#OTPCertificate{} C) - case in_my_cache(C) orelse my_accept(C) of true - enter_my_cache(C), true; false - false end end, public_key:pkix_verify_hostname(CertFromHost, RefIDs, [{fail_callback, Fail}]).注ssl/tls 等上层应用通常会透传相关选项到pkix_verify_hostname日常 TLS 编程中你多半不需要直接调用它。进一步阅读public_key 应用文档本文所依据的官方应用描述Public Key 使用示例PEM、RSA、签名、主机名校验的完整交互式示例Public-key Records 指南所有 ASN.1 生成记录#OTPCertificate{}、#RSAPrivateKey{}等的字段说明public_key API 模块全部公开函数签名与文档应用启动与管理可参考m:applicationapplication:start/[1,2]、application:load/1。赞分享编程语言语言运行时标准库编译器并发编程【免费下载链接】otpErlang/OTP项目地址https://gitcode.com/gh_mirrors/ot/otp点击查看免费下载相关推荐OpenCore Legacy Patcher 官方 FAQ 技术详解版本策略、更新机制与 AVX、Metal 兼容性故障排查OpenCore Legacy Patcher 官方 FAQ 技术详解版本策略、更新机制与 AVX、Metal 兼容性故障排查 本文基于 OpenCore L编程语言语言运行时标准库编译器并发编程Diem Crypto 组件深度解析哈希、签名与密钥派生基础设施Diem Crypto 组件深度解析哈希、签名与密钥派生基础设施 Diem 区块链的密码学基础全部封装在 diem crypto crate 中覆盖哈希、签区块链金融科技EMQX 5.8.8 升级 Erlang/OTP 26.2.5.14 深度解析TLS 证书续期竞态修复与 RSA-PSS 签名证书支持EMQX 5.8.8 升级 Erlang/OTP 26.2.5.14 深度解析TLS 证书续期竞态修复与 RSA PSS 签名证书支持 本篇技术指南围绕 EM后端物联网消息队列通信上一篇AutoGPT 前端性能实践用 better-all 做依赖驱动并行化消除部分依赖的数据获取瀑布下一篇WhiteSur 主题实操指南6 步装好、调美、卸干净创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表