资讯动态

Certbot ACME 库的 Crypto_util 加密工具模块深度解析:CSR 生成、SAN 提取与证书序列化

发布时间:2026/9/19 20:01:50 来源:尧图企业网站定制
网络安全CLI后端【免费下载链接】certbotCertbot is EFFs tool to obtain certs from Lets Encrypt and (optionally) auto-enable HTTPS on your server. It can also act as a client for any other CA that uses the ACME protocol.项目地址https://gitcode.com/gh_mirrors/ce/certbot点击查看免费下载导读本文以 acme/docs/api/crypto_util.rst 所定义的 API 文档页面为骨架深入剖析acme包中acme.crypto_util模块的全部公开接口。该模块是 Certbot 与任何 ACME 协议 CA 交互时最底层的加密支撑它负责生成包含域名/IP 的证书签名请求CSR、从证书与 CSR 中提取 SAN 与 Common Name、构造自签名证书以及将证书链序列化为 PEM/DER 字节流。读完本文你将掌握这些工具函数的完整签名、参数语义、弃用状态与边界行为并能直接在自定义 ACME 客户端中复用它。一、模块定位与文档组织acme/docs/api/crypto_util.rst是 Sphinx 生成的 API 参考页正文由 automodule 指令构成Crypto_util ----------- .. automodule:: acme.crypto_util :members:它通过:members:自动收集 acme/src/acme/crypto_util.py 中所有带文档字符串的公开符号与acme/docs/api.rst的api/*通配 toctree 一起挂载进完整 API 文档。因此该文档页的真实内容就是模块源码中的 docstring——这也是本文逐函数展开的依据。从模块导入结构看它建立在两大加密库之上cryptographyx509、hashes、serialization 以及 rsa/dsa/ec/ed25519/ed448 非对称算法OpenSSL.crypto仅用于Format枚举与 pyOpenSSL 常量兼容。模块在导入时还会把自己替换为_ClientDeprecationModule包装对象见下文弃用机制用于对已弃用属性发出警告。二、make_csr生成 ACME 证书签名请求make_csr是模块中最核心、使用最频繁的函数Certbot 签发证书的整个流程都从这里开始def make_csr( private_key_pem: bytes, domains: Optional[Union[set[str], list[str]]] None, must_staple: bool False, ipaddrs: Optional[list[Union[ipaddress.IPv4Address, ipaddress.IPv6Address]]] None, ) - bytes:2.1 参数语义与默认值参数类型默认值含义private_key_pembytes必填PEM 编码的 PKCS#8 私钥即serialization.load_pem_private_key(..., passwordNone)可解析的字节串domainsset[str]/list[str]None视为空要写入 subjectAltNames 的 DNS 域名列表must_stapleboolFalse是否添加 TLS Feature 扩展即 OCSP Must-StapleRFC 7633ipaddrslist[IPv4Address/ IPv6Address]None视为空要写入 SAN 的 IP 地址对象列表参数顺序特意保持位置参数向后兼容先域名、再 must_staple、最后 IP 列表。2.2 处理流程与约束密钥加载与类型校验先用serialization.load_pem_private_key解析私钥随后检查其类型是否落在CertificateIssuerPrivateKeyTypesTpl元组内DSA、RSA、EC、Ed25519、Ed448否则抛出ValueError。测试用 X25519 密钥验证了这一点见 crypto_util_test.py 中test_make_csr_invalid_key_type。空输入保护domains与ipaddrs都为空时抛出ValueErrortest_make_csr_without_hostname覆盖。构造 CSR使用空 subject 名的CertificateSigningRequestBuilder添加一个criticalFalse的SubjectAlternativeName扩展将每个域名编码为x509.DNSName、每个 IP 编码为x509.IPAddress。Must-Staplemust_stapleTrue时追加x509.TLSFeature([x509.TLSFeatureType.status_request])扩展即status_request业界通称 OCSP Must-Staple。测试断言此时 CSR 恰好有两个扩展。签名与输出以 SHA-256 摘要算法签名返回 PEM 编码字节串。2.3 测试验证acme/src/acme/_internal/tests/crypto_util_test.py 的MakeCSRTest验证了输出包含--BEGIN CERTIFICATE REQUEST--/--END CERTIFICATE REQUEST--标记且可被x509.load_pem_x509_csr重新解析多域名时 SAN 扩展依次为DNSName(a.example)、DNSName(b.example)域名与 IP 混用127.0.0.1、::1时 SAN 同时包含 DNSName 与 IPAddress空域名、非法密钥类型均抛ValueError。2.4 在 Certbot 中的实际调用certbot/src/certbot/crypto_util.py 中init_save_csr直接调用acme_crypto_util.make_csr(privkey.pem, names, must_staplemust_staple, ipaddrsipaddrs)并落盘保存certbot/src/certbot/_internal/client.py 在签发流程中把域名集合、self.config.must_staple与解析出的 IP 地址一并传入完整示例 acme/examples/http01_example.py 展示new_csr_comp先用 RSA 生成 2048 位私钥再调用crypto_util.make_csr(pkey_pem, [domain_name])产出 CSR随后交给client_acme.new_order(csr_pem)。三、名称提取从证书/CSR 读取域名与 IP3.1 get_identifiers_from_x509def get_identifiers_from_x509(subject, exts) - tuple[list[str], list[str]]:返回(DNS 名称列表, IP 地址列表)二元组提取逻辑遍历 subject 中所有COMMON_NAME属性收集 CN 列表bytes类型仅可能出现在其他 OID此处安全地 cast 为str尝试exts.get_extension_for_class(x509.SubjectAlternativeName)若不存在 SAN 扩展则两个列表均为空存在时分别用get_values_for_type(x509.DNSName)与get_values_for_type(x509.IPAddress)取值IP 统一转为字符串CN 置首若 CN 存在返回[cns[0]] [d for d in dns_names if d ! cns[0]]即第一个 CN 排在最前并去重这与旧版 pyOpenSSL 实现行为保持一致无 CN 则直接返回 SAN 列表。该函数是acme客户端内部将 CSR 转换为 ACME 订单 identifiers 的关键桥接在 acme/src/acme/client.py 中new_order解析 CSR 后调用它得到dns_names, ip_addrs再逐一构造成messages.Identifier(typIDENTIFIER_FQDN, ...)。在 Certbot 侧certbot/src/certbot/_internal/san.py 也复用它把名称转换成内部DNSName/IPAddress结构。3.2 get_names_from_subject_and_extensionsdef get_names_from_subject_and_extensions(subject, exts) - list[str]:get_identifiers_from_x509的便捷封装丢弃 IP 列表、只返回 DNS 名称含首个 CN。Certbot 在 certbot/src/certbot/crypto_util.py 用它解析用户提供的 CSR 文件、同文件 L491-L493 与 L519-L521 用它从证书或 CSR 对象提取 SAN 集合用于后续校验与续期判断。3.3 _cryptography_cert_or_req_san内部 APIdef _cryptography_cert_or_req_san(cert_or_req) - list[str]:同时接受x509.Certificate或x509.CertificateSigningRequest仅返回 DNS SAN无 SAN 扩展时返回空列表。docstring 明确标注这是acme内部 API曾被 letsencrypt 使用并标记为自 3.2.1 起弃用。测试覆盖了无 SAN、双 SAN、100 个 SAN、IDN 名称以及 critical SAN 等多种边界见 crypto_util_test.py 中CryptographyCertOrReqSANTest。四、make_self_signed_cert构造自签名证书def make_self_signed_cert( private_key: types.CertificateIssuerPrivateKeyTypes, domains: Optional[list[str]] None, not_before: Optional[datetime] None, validity: Optional[timedelta] None, force_san: bool True, extensions: Optional[list[x509.Extension]] None, ips: Optional[list[Union[ipaddress.IPv4Address, ipaddress.IPv6Address]]] None, ) - x509.Certificate:该函数已弃用调用即触发DeprecationWarning但仍是理解证书构建逻辑的参考实现其行为要点前提断言domains与ips至少提供一个否则AssertionErrortest_no_name覆盖序列号x509.random_serial_number()随机生成测试test_sn_collisions连续生成 5 张证书验证序列号不冲突基础约束始终添加BasicConstraints(caTrue, path_length0)critical 为 TrueSAN 策略force_sanTrue或域名多于一个或含 IP 时才添加SubjectAlternativeName域名编码为 DNSName、IP 编码为 IPAddress单域名且force_sanFalse时仅使用 CN不添加 SAN 扩展有效期not_before缺省取_now()可被单测 mock 的 UTC 当前时间validity缺省为 7 天timedelta(seconds7*24*60*60)not_valid_after not_before validity自定义扩展extensions中的每一项会被逐个写入 builder测试用TLSFeature(status_request)验证签名以 SHA-256 对证书签名后返回x509.Certificate对象。五、dump_cryptography_chain证书链序列化def dump_cryptography_chain( chain: list[x509.Certificate], encoding: Encoding Encoding.PEM, ) - bytes:将cryptography.x509.Certificate列表拼接为 PEM默认或 DER 的证书链 bundle非 PEM/DER 的编码如Encoding.SMIME直接抛ValueErrortest_dump_cryptography_chain_wrong_encoding覆盖拼接方式为b.join(cert.public_bytes(encoding) for cert in chain)依赖public_bytes输出自带结尾换行符这一行为注释提示当链为空时返回空字节串这是为了让上层RenewableCert安静工作而非最佳方案同样标注自 3.2.1 起弃用默认编码 PEM 的调用路径由test_dump_cryptography_chain验证。六、Format 枚举与模块级弃用机制6.1 Format 枚举已弃用class Format(enum.IntEnum): DER crypto.FILETYPE_ASN1 PEM crypto.FILETYPE_PEM一个向后兼容 pyOpenSSLFILETYPE_ASN1/FILETYPE_PEM常量的整数枚举提供to_cryptography_encoding()将其映射为serialization.Encoding.DER或Encoding.PEM。访问该属性会触发DeprecationWarning见test_to_cryptography_encoding。6.2 _ClientDeprecationModule 包装模块加载末尾执行sys.modules[__name__] _ClientDeprecationModule(sys.modules[__name__])把自己替换为委托代理对Format属性的访问会额外发出将在下一个大版本移除的DeprecationWarning其余属性原样转发到底层模块。这套机制是 Certbot 在演进中逐步淘汰 pyOpenSSL 风格 API、全面转向cryptography库的过渡手段。七、弃用状态速查与迁移建议符号状态替代方案make_csr正常使用直接使用get_names_from_subject_and_extensions正常使用直接使用get_identifiers_from_x509正常使用直接使用make_self_signed_cert弃用调用即警告用x509.CertificateBuilder自行构建dump_cryptography_chain弃用3.2.1 起逐证书public_bytes拼接_cryptography_cert_or_req_san弃用3.2.1 起内部 APIget_identifiers_from_x509Format弃用访问即警告serialization.Encoding八、可复用的最小代码示例from datetime import timedelta import ipaddress from cryptography import x509 from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import rsa from acme import crypto_util # 1. 生成 RSA 私钥并序列化为 PEM PKCS#8 key rsa.generate_private_key(public_exponent65537, key_size2048) key_pem key.private_bytes( encodingserialization.Encoding.PEM, formatserialization.PrivateFormat.PKCS8, encryption_algorithmserialization.NoEncryption(), ) # 2. 生成含域名与 IP 的 CSR含 OCSP Must-Staple csr_pem crypto_util.make_csr( key_pem, domains[example.com, www.example.com], must_stapleTrue, ipaddrs[ipaddress.ip_address(192.0.2.1)], ) # 3. 从 CSR 中反向提取标识符 csr x509.load_pem_x509_csr(csr_pem) dns_names, ip_addrs crypto_util.get_identifiers_from_x509(csr.subject, csr.extensions) print(dns_names, ip_addrs) # [example.com, www.example.com] [192.0.2.1]完整可运行示例参见 acme/examples/http01_example.py其中make_csr与client.ClientV2.new_order、perform_http01串联演示了从账户注册、CSR 生成、HTTP-01 挑战到签发/续期/吊销的端到端 ACME 流程。九、总结acme.crypto_util是 Certbot 与 ACME CA 交互的加密基础层make_csr负责把域名与 IP 变成可提交的 PEM CSR名称提取系列函数负责反向解析证书与 CSR 中的标识符并支撑订单与续期逻辑而make_self_signed_cert、dump_cryptography_chain、Format则作为历史 API 处于弃用过渡期。掌握本模块的签名与边界行为密钥类型白名单、空输入校验、CN 置首规则、Must-Staple 扩展、弃用警告即可在任何基于 python-acme 的自研客户端中安全复用这些能力。赞分享网络安全CLI后端【免费下载链接】certbotCertbot is EFFs tool to obtain certs from Lets Encrypt and (optionally) auto-enable HTTPS on your server. It can also act as a client for any other CA that uses the ACME protocol.项目地址https://gitcode.com/gh_mirrors/ce/certbot点击查看免费下载相关推荐acme-tiny CSR解析技术如何从证书请求中提取域名acme tiny CSR解析技术如何从证书请求中提取域名 在SSL/TLS证书申请过程中CSRCertificate Signing Request文Certbot与Puppet配置管理工具中的证书自动化模块Certbot与Puppet配置管理工具中的证书自动化模块 1. 证书管理的自动化痛点与解决方案 在现代IT基础设施中SSL/TLS证书的管理是一个关键但常网络安全CLI后端Certbot achallenges 模块深度解析ACME 客户端注记挑战AnnotatedChallenge的设计与实战Certbot achallenges 模块深度解析ACME 客户端注记挑战AnnotatedChallenge的设计与实战 导读 certbot.ach网络安全CLI后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价