摘要

  • 在 RFC 9811 的普通 CMP-over-HTTP 交互中,成功的 HTTP 请求必须返回 200 OK,响应体承载 CMP 响应;证书操作究竟是接受、修改后批准、拒绝还是等待,仍由内部 PKIStatus 表示。
  • 可靠的自动化凭证必须把目标权威、HTTP、受保护的 PKIMessage、transactionID、轮询、确认、密钥库变更和依赖方验证连在一起,同时保留每一层的独立含义。

证书自动化最危险的误判,往往不是失败告警,而是一行被过度解释的 200 OK。

RFC 9811 于 2025 年 7 月作为 IETF 标准轨 RFC 发布。它规定 CMP 如何通过 HTTP 传送:把 DER 编码的 PKIMessage 放进 POST 请求体,使用 application/pkixcmp 媒体类型;普通请求在 HTTP 层成功时,服务器以 200 返回,CMP 响应位于响应体。其他成功的 2xx 状态码不得代替这一形式。

这不是让 200 成为证书裁决,而是把外层收据固定下来,让内层协议继续拥有裁决权。

两套状态语言

RFC 9810 规定 CMP 响应状态,包括 accepted、grantedWithMods、rejection 和 waiting。因此,HTTP 200 可以承载完全批准、带修改的批准、明确拒绝,也可以承载尚未处理完毕的事务。它们在 HTTP 成功率图上颜色相同,在操作上却要求四种不同处理。

反过来,看到 4xx 或 5xx 就丢弃响应体也不合规。RFC 9811 要求客户端能够处理 2xx、4xx 和 5xx 响应体中的 CMP PKIMessage。外层错误可能同时带来最具体、可验证、可关联的内部说明。

正确顺序不是“先看 HTTP,得出最终结论”,而是逐层累积:接收响应,检查媒体类型与大小,解析 DER,验证 CMP 保护和发送者,把消息接到正确事务,再解释消息类型、状态与失败信息。前一层通过只允许进入下一层,不允许替下一层作答。

没有响应,是不确定,不是无副作用证明

RFC 9811 要求:如果没有 HTTP 响应确认接收,就必须假定 CMP 消息没有成功送达目的地。这是一条保守的传输规则,防止客户端在没有收据时声称成功。它却不能看到服务器内部。

连接可能在服务器读取甚至处理请求以后、客户端收到响应以前中断。客户端只能确认“送达未证实”;服务器一侧可能已经建立事务或作出动作。立即换一个新标识重试,可能生成重复请求;完全不重试,又可能让续期逾期。

所以重试必须保留原始 transactionID、请求体哈希、目标 CA 或 RA、操作类型和时间边界,并按 CMP 的继续或轮询规则进行。无法对账时,应把状态明确写成未知并升级处理,而不是用一个新事务把旧的不确定性藏起来。

无状态传输上的有状态事务

某些 PKI 管理操作需要多组请求与响应。HTTP 每次交互可以是无状态的,CMP 的 transactionID 仍把这些消息归入同一事务。RFC 9810 要求一旦标识建立,后续请求和响应都使用它;同一客户端不得同时向同一服务器运行两个相同标识的事务。

客户端创建标识时,规范建议使用 128 位伪随机数据。服务器可根据识别客户端的能力,要求 {client, transactionID} 或标识本身唯一;无法正确关联的冲突应返回 transactionIdInUse。

但是,关联不是认证。transactionID 不证明客户身份,不授权证书配置,不验证消息完整性,也不自动提供业务幂等性。消息保护、nonce、请求编号和本地政策各有职责。审计系统应把它们连接起来,不能把追踪号升级为权力凭证。

waiting 有自己的时钟

waiting 最直观地证明 HTTP 结束不等于操作结束。它表示请求体尚未处理完成,客户端应发送 pollReq。CA 或 RA 准备好后给出最终响应;否则返回包含 checkAfter 的 pollRep,客户端至少等待指定秒数再查询。

等待原因可能是后台负载、PKI 管理实体之间的离线传送,或 RA 操作员的人工作批。网络往返已经结束,组织内部的决定仍然开放。

自动化系统必须为等待状态保存负责人、最早下次查询时间、累计时长、升级阈值和原始事务上下文。早于 checkAfter 反复查询,不会加速人工批准,只会消耗服务能力。把等待当成失败会制造并行申请,把等待当成成功则会在没有证书时关闭控制项。

CA 返回证书以后,事务可能还没关闭

RFC 9810 定义 certConf,让客户端接受或拒绝收到的证书;之后的 pkiconf 可以确认并关闭交互。CA 若改变了申请字段,终端实体必须检查实际证书。grantedWithMods 绝不是“直接安装”的同义词。

完整证据链至少包括:受保护的 CMP 响应及状态;证书指纹和申请差异;客户端确认或拒绝;协议关闭;密钥库写入;服务加载;依赖方对链、名称、用途和有效期的验证。相同指纹可以连接这些记录,却不能证明每一步都发生了。

发证数据库里存在一张证书,不代表负载均衡器已经展示它。部署工具显示成功,不代表客户端接受它。服务目前可访问,也不能证明 CMP 确认记录完整。运行事实和协议关闭必须各有收据。

推送公告使用另一套收据

RFC 9811 为 CA 推送的密钥更新、证书、吊销或 CRL 公告规定了不同流程。此时 CMP 服务器充当 HTTP 客户端,接收方不返回 CMP 响应,只返回空的 HTTP 响应。

201 Created 表示公告内容已存储或原本已存在;202 Accepted 只表示进入后续处理。收到 202 后,发送方可以等待再试,直到得到处理完成的确认。这些代码不能套用到普通证书申请,因为普通流程由 200 承载 CMP 决定。

如果公告回执没有得到适当认证与保护,其处理声明便不可信,PKI 架构也不得依赖它必然送达。状态码必须带着来源和保护语境,才是证据。

/.well-known/cmp 规定路径,不授予权威

为改善多厂商互操作,支持 HTTP 或 HTTPS 的 CMP 服务器必须支持 /.well-known/cmp 前缀,后续段可区分操作、CA 或证书配置。IANA Well-Known URIs 注册表把 cmp 列为由 IETF 控制的永久后缀。

这个约定说明在某个 origin 上从哪里询问,却不负责发现正确主机。RFC 8615 明确说它不定义主机名发现,并提醒 well-known 位置代表整个 origin 的控制面。配置来源、解析结果、重定向、TLS 对端、受保护 CMP 消息的发送者以及本地信任规则,都要单独保存。

RFC 9811 允许实现支持 3xx,但要求谨慎决定是否自动跟随。恶意保存的 301 目的地可以把客户端长期引离正确服务器。HTTP 的便利不应暗中改写 PKI 的权威边界。

把交接保存成证据图

最低限度的事务档案应记录:预期 CA/RA;配置和最终 URI;重定向链;TLS 对端;HTTP 方法、状态、媒体类型与请求/响应哈希;CMP 发送者、接收者、消息类型和保护验证;transactionID、nonce、请求编号;PKIStatus、失败信息、checkAfter;证书指纹、申请差异、certConf/pkiconf;密钥库版本、启用结果、回滚指针;以及关键依赖系统的独立验证。

它也必须允许保存否定式结论:无响应是送达未确认;200 是响应已到;已签发是证书对象存在;已安装是本地状态改变;某次连接成功是某个依赖方接受。后一个事实不能由前一个事实自动生成。

这套区分还改变了故障处理的先后顺序。HTTP 5xx 不一定意味着只查看代理、负载均衡和 Web 服务器;如果响应体含有可验证的 CMP 错误,调查必须把它交给证书事务的负责人。HTTP 200 也不意味着基础设施团队可以关闭工单;若内部状态是 waiting,真正的阻塞点可能是 RA 审批队列。把每个状态交给拥有该决定的人,比建立一个拥有所有状态却看不见任何细节的总控面更可靠。

证据保留还要考虑迁移。供应商更换或 CA 层级调整时,如果旧平台只导出“成功/失败”和最终证书,新的平台无法判断哪些 200 属于拒绝、哪些等待已经过期、哪些确认没有完成。可移植档案至少要保留原始消息哈希、事务标识、状态时间线、证书指纹和保护验证结果。退出能力不是额外的治理功能,而是避免自动化工具把协议历史变成锁定资产的基本条件。

传输保密与消息真实性也不能互相冒充。HTTPS 可以保护链路并认证终止 TLS 的对端,CMP 保护则验证协议消息本身。两者都通过仍不代表申请合乎本地证书政策;本地政策批准也不代表依赖系统会接受最终证书。把四者并列记录,才能在某个控制失效时知道其他控制究竟补偿了什么,而不是笼统宣布“通道安全”。

Running-Code Primacy 把最终检验放在实际运行的客户端、CA/RA 状态、密钥库和业务连接上。Minimum Initial Specification, Localized Future Decision, and Voluntary Adoption 支持严格但狭窄的共同传输规则,同时把证书政策、批准、启用和退出留给本地承担者。Reality Layers 则要求不要用一个绿色图标压平这些不同层次的真实。

RFC 9811 没有削弱 200 OK。它让这个收据恢复诚实:HTTP 请求成功了,CMP 响应到了。证书决定仍要从里面读出来。

来源