摘要

  • draft-ietf-cose-hpke-27 允许把 HPKE 产生的密文放在 COSE_Encrypt 或 COSE_Encrypt0 之外传输,此时结构中的 ciphertext 位置为 nil。随后套在 COSE 对象上的签名或 MAC 并不覆盖那份分离密文。
  • AEAD 标签可以为分离密文提供完整性,但它证明的是密文与关联数据在内容密钥下有效,不等于证明公开发送者身份、业务授权或外部动作已经完成。
  • 2026 年 10 月 1 日,修订版 27 仍处于 IESG 的 AD Evaluation::AD Followup。文档 shepherd 提到三个实现验证了示例,这不等于任何生产系统已经正确管理 Blob 与信封的对应关系。

最危险的状态不是验证失败,而是验证成功后把结论说得过大。

系统收到一个带有合法外层签名的 COSE 对象。对象告诉接收方去哪里取得一份大体积密文。存储服务返回字节,AEAD 验证通过,HPKE 也成功打开接收方所需的密钥材料。每个局部步骤都可能是正确的,但如果审计记录只剩下 verified=true,事后就无法回答:外层签名是否承诺了这一份具体密文?

COSE-HPKE 修订版 27 直接写出了这一边界。当 COSE_Encrypt 或 COSE_Encrypt0 使用分离密文时,之后通过 COSE_Sign、COSE_Sign1、COSE_Mac 或 COSE_Mac0 加上的完整性保护不会覆盖分离密文。实现者必须让分离密文本身获得完整性保护。

这不是说分离设计“不安全”。它是在要求系统准确声明不同密码学原语分别覆盖什么。

nil 不是没有内容,而是内容走了另一条路径

RFC 9052 定义了 COSE 的基础结构。内容可以从 COSE 控制结构中分离,由应用通过另一条路径提供;结构里原本承载内容的位置写成 nil。对于大文件、固件包、媒体或多层对象存储,这种设计避免复制,也让控制信息和数据拥有不同生命周期。

在 COSE-HPKE 集成加密模式中,HPKE 输出 ct。根据修订版 27 纯文本,它可以直接进入 COSE_Encrypt0,也可以分开运输。在密钥加密模式中,第 0 层用内容加密密钥 CEK 加密正文,第 1 层再用 HPKE 为一个或多个接收方加密 CEK。XML 源文件 描述的是同一套层次。

从这一刻起,Blob 的选择规则就是安全边界。可变 URL、重复使用的对象名、自动覆盖的“latest”、CDN 分段重组、透明解压或存储修复,都可能让同一个合法信封指向不同字节。一个通过验证的信封与一份错误密文可以同时存在。

因此,审计不能只记对象编号。它必须记住当时实际读取的密文字节长度、摘要、不可变版本与解析路径。

五个绿色结果不能压成一盏灯

第一项凭据是外层签名或 MAC。它只能证明实际进入 Sig_structure 或 MAC_structure 的字节在相应密钥下有效。视觉上位于“里面”或“旁边”的数据,不会自动加入计算。

第二项凭据是第 0 层 AEAD。若接收方使用正确 CEK、nonce 与关联数据,标签验证可以检测密文被改动。这是分离密文最自然的完整性保护,也是草案明确举出的情形。但其结论仍然有限:它证明对称密钥上下文内的密文有效,并不公开证明谁发送了消息。

第三项凭据是 HPKE 接收方处理。接收方能否用指定私钥打开封装并得到 CEK,与外层签名是否覆盖 Blob 是两个问题。

第四项凭据是身份。kid 解析出的密钥是否真的属于被声称的主体,需要命名空间、证书或登记记录、版本、用途和撤销状态支持。

第五项凭据是业务效果。即使密码学与身份都正确,当前主体是否有权修改该设备、转移该资产或发布该配置,仍由应用策略决定;授权通过后是否真的提交,还要有外部结果凭据。

层次 能够证明 不能替代
外层签名/MAC 被覆盖 COSE 对象在指定密钥下有效 未进入计算的分离密文完整性
第 0 层 AEAD 密文及关联数据在 CEK 下未被篡改 公开发送者身份与业务权限
HPKE Open 接收方密钥处理与解密结果 kid 所代表主体的权威
身份解析 密钥与受信主体的关联 对本次动作的授权
授权与提交 策略许可与状态改变 前述密码学来源,除非显式绑定

Recipient_structure 修补的是算法绑定

COSE-HPKE 没有简单沿用含义较模糊的上下文,而是定义 Recipient_structure。它把下一层算法标识和接收方受保护头部纳入 HPKE 的 info 输入。这样,保护 CEK 的机制便与消费 CEK 的内容加密算法建立显式关系。

草案要求按 RFC 8949 的核心确定性编码规则序列化该结构。发送方与接收方各自构造同一份、不在消息中直接传输的输入;如果同样的数据有不同编码,健全的密码学也会因为输入不同而失败。

确定性编码解决的是字节表示不一致,不是身份、授权或 Blob 不可变性。治理上常见的错误,是把一个局部歧义被消除,汇报成所有歧义都已消除。

recipient_extra_info 还能把双方通过带外方式获得的上下文带入 HPKE:租户、会话、设备类别或交易目的都可能适用。它不随 COSE 消息传输,因此双方如何取得、版本如何升级、缺失时是否拒绝,都必须另有规则。静默退回空字符串会把设计中的上下文绑定悄悄取消。

kid 是查找线索,不是身份徽章

草案建议使用 kid 明确标识发送方采用的接收方静态公钥。在密钥加密模式中,若把它放进受保护头部,它还会经 Recipient_structure 进入 HPKE 密钥调度。这种绑定很有价值。

但 kid 仍只是字节串。两个租户可以使用相同短编号;缓存可以在轮换后返回旧密钥;灾备密钥可以具备解密能力却不具备日常业务角色。系统必须保存 kid 所属命名空间、解析服务、密钥版本、激活期、用途限制与撤销结果。

草案把 HPKE 封装密钥 ek 放在未保护头部区域。这不应被误读成“不会被检查”。篡改通常会在 HPKE 打开或后续认证阶段造成失败。正确的做法是记录收到的 ek 摘要与实际验证结果,而不是仅凭字段所在的区域推断结论。

为接收方加密,不等于识别发送方

RFC 9180 给出了现行 HPKE 的基础安全模型。当前的后继 HPKE 草案 若获批准将取代 RFC 9180,但截至本文证据冻结时仍是进行中的标准工作。资产清单必须记录具体草案/RFC 版本、模式与套件,不能只写“使用 HPKE”。

HPKE Base 模式的 KEM 本身不认证发送方。COSE 可以通过签名或 MAC 增加认证,但前提是团队检查其真实覆盖范围,而不是把对象嵌套想象成覆盖嵌套。

RFC 9338 对反签名给出相邻的提醒:证明加密数据存在,与证明未加密数据的语义不是一回事。若领导层需要的是“某主体批准了这段明文含义”,协议必须有意构造这项证明,不能从一次成功解密倒推出批准。

RFC 9053、IANA COSE 注册表 与 IANA HPKE 注册表 协调算法与编号。编号被登记,不代表某产品拒绝了过时套件、正确完成轮换或执行了授权。

评审进度不是部署合格证

Datatracker 页面 显示,2026 年 10 月 1 日,修订版 27 是 COSE 工作组提交给 IESG、目标为 Proposed Standard 的 Internet-Draft,状态为 AD Evaluation::AD Followup。文档历史 记录该版本在 9 月 12 日发布。它还没有 RFC 编号,内容仍可能变化。

Shepherd 报告 称工作组进行了广泛讨论,作者在 IETF 125 表示有三个独立实现用来验证示例。这是值得保留的运行代码证据,却不是生产普查。它没有证明某个系统正确锁定 Blob 版本、管理带外上下文、处理密钥撤销或把授权置于解密之后。

为每一次决策建立覆盖清单

最小清单应保存:完整 COSE 字节;消息类型与 tag;受保护及未保护头部;密文内嵌或分离;不可变 Blob 定位符、长度和摘要;签名/MAC 输入摘要;AEAD 算法、关联数据摘要和标签结果;HPKE 模式与套件;ek 与 Recipient_structure 摘要;recipient_extra_info 来源;kid 解析出的密钥版本;打开结果;可信边界内的明文摘要;发送者身份结论;授权结论;提交编号;独立观察到的效果。

清单不需要记录私钥或把明文泄露到日志。摘要、版本化引用与决策凭据足以形成连续证据。没有覆盖也要诚实记录:outer_signature_covers_blob=false 在 AEAD 正确保护 Blob 时可以是合理设计,但绝不能改写成含义模糊的 signed=true。

最低初始规范 支持把覆盖清单作为最薄的共同规则,而不集中所有业务政策。运行代码优先 要求检查真正送入密码学 API 的缓冲区。政策之镜 提醒我们,对象存储、密钥解析与默认值实际分配权力。现实分层 则防止语法、字节、证明、身份、许可与效果被压成同一个符号。

来源