摘要

  • COSE kid 是帮助查找候选密钥的非结构化提示,不保证唯一,也不是公钥指纹、设备身份或授权主体。
  • 完整收据要保留查询范围、全部候选、真正通过验签的密钥指纹、被签字节、身份绑定、授权政策以及应用结果,不能让一个短值替代整条证据链。

设想一台验证设备收到了 COSE_Sign1 对象。未保护头中的 kid 是 0x19。本地密钥库返回两项:一项是轮换窗口里尚未清退的旧钥匙,另一项属于不同客户空间。第一把失败,第二把成功。

此时能够确认的是:第二把具体钥匙对这一组具体字节给出了有效验证结果。不能确认的是“0x19 这个身份签了消息”。如果数据库只存短值和一个布尔量,候选集、查询命名空间、库版本与真正胜出的钥匙都会消失。

这不是对某个真实部署事故的描述,而是一个检验数据模型的假设场景。COSE 规范没有把短值设计错;把提示字段升级成永久主键,才是证据错误的起点。

kid 先缩小范围,不负责裁决

RFC 9052 是现行 COSE 结构与处理规范。公共头参数表把整数标签 4 分给 kid,取值类型是字节串。这个字段可以与 COSE_Key 中的 kid 成员匹配,也可以被其他密钥分发方法定义为同等的查找输入。

规范随后明确否定唯一性假设:相同 kid 可能关联多把钥匙,应用可能需要逐一检查。它也没有规定短值的内部结构。在 COSE_Key 里,这个值可以由用户指定,也可以从公钥部分计算出来;即便如此,它仍可出现在代表不同钥匙的对象中。

所以查询至少需要五个维度:应用或协议配置、租户或发行方、密钥库版本、观察时间和收到的原始字节。查询的产物是候选集合。只有实际运行密码学验证后,才能指出哪一把完整钥匙成功。成功者的稳定指纹是新证据,不是对 kid 的自动解释。

IANA 的 COSE 注册表保留了这层克制:kid 是标签 4、类型 bstr 的密钥标识符。表中另有独立的 kid context。并非所有 COSE 应用都必须采用后者,但注册表本身已经说明,短标识与它所处的上下文不是同一个字段。

放在未保护头,是语义提示

COSE 安全对象同时带有受保护头和未保护头。受保护参数进入认证构造;未保护参数可以随对象传送,却不因此获得相同的密码学覆盖。两类容器都存在,就是为了让接收者看清哪些声明受保护、哪些只是附带信息。

RFC 9052 把 kid 称为选钥提示,并明确说它不是安全关键字段,因此可以放进未保护头。这里的意思不是“随便改也没有运维影响”。恶意或错误的值可能扩大查询、把请求引向错误租户、造成拒绝服务,或者留下误导性的日志。真正的意思是:安全结论不得依赖这个提示自身为真。

更改未保护的 kid,不会凭空造出能被无关公钥验证的签名。接收者仍然必须用某把真实候选钥匙,对精确输入完成验签。恰当的控制是限制候选数量、隔离命名空间、保存尝试顺序与结果,而不是把提示涂成“已认证身份”。

签名覆盖的是一组精确字节

RFC 9052 定义的 Sig_structure 包含签名上下文、正文受保护参数、适用时的签名者受保护参数、应用提供的外部认证数据,以及完整载荷。它们编码后形成 ToBeSigned。验证算法接收的是这段字节、具体算法、具体钥匙和签名。

验签收据因此应保存结构类型、受保护头的原始字节、external_aad 的生成规则、实际载荷哈希以及每把候选钥匙的完整指纹与来源。若解析器因重复标签、畸形结构或无法理解的关键参数而拒绝消息,拒绝发生在密码学运算之前,也应成为记录的一部分。

界面尤其容易越界。它可以在绿色“签名有效”旁边显示 kid,却不能把空间上的相邻画成密码学上的覆盖。若短值来自未保护头,读者需要直接看到这一事实。

数学通过之后,还有两道门

RFC 9052 在验签步骤后另外要求应用检查:这把钥匙是否正确对应所声称的签名身份;该身份是否有权在执行动作之前提出这个请求。

第一道门是身份绑定。证书、供应记录、硬件证明、账户登记或本地治理的映射,都可能提供依据。第二道门是授权。角色、资源、用途、时间、策略版本与密钥使用限制共同决定当前能否行动。四号头参数没有携带这些事实。

轮换会暴露差异。新旧钥匙可以在宽限期内共用短提示,旧钥匙也可能继续验证历史对象,却不能再签发新命令。撤销会改变当前授权,而不改写过去一次签名确实有效的事实。把两者合并成“有效/无效”,会同时损害审计与处置。

应用结果还要再单独记录。授权允许不等于动作提交成功,内部提交成功也不等于外部设备产生预期变化。kid 与验签结果都不能替这一步作证。

访问控制协议仍不把它当唯一值

RFC 9052 的应用剖面章节把消息类型、安全服务、头参数、算法与协商方式留给具体协议选择。COSE 提供的是可组合的安全结构,不是全世界共用的一套身份司法管辖。

RFC 9200 把 OAuth 用于受限环境,并在一个携带持有证明 COSE_Key 的授权服务器响应中再次划线:kid 只用于简化密钥索引与取回,客户端和资源服务器各自的域内都不应假定它唯一。

这意味着即使语境本来就与授权有关,短标识仍只完成查找。可靠记录还要写明剖面版本、授权服务器或发行方、客户端或资源服务器、受众、密钥用途和实际政策决定。

Schaad 留下的是规范贡献,不是个人裁决权

Jim Schaad 是 2017 年原始 COSE 规范 RFC 8152 的作者。后来 RFC 9052 取代了其中结构与处理部分,算法部分则由 RFC 9053 承接;RFC 9052 的作者栏同样列出 J. Schaad。IETF Datatracker 的 Jim Schaad 个人页把这些文件放进更长的 RFC 记录中。

这些是 IETF 共识文档,不是作者对任何产品或网络下达的命令。署名也不能证明实现已经部署、配置正确或处于安全状态。Oregon Wine Press 的纪念文章提供了本篇人物配图所依据的署名公共照片;酒庄场景只用于身份来源,不构成 COSE 技术证据。

不要删掉失败的候选

记录应从收到的原始对象开始:对象哈希、COSE 结构、受保护与未保护头、外部数据规则和载荷引用。查找记录另建一层,写明作用域、库版本、时间、原始 kid 以及完整候选列表。

每位候选都保存全量公钥指纹、来源、有效期、允许用途和验证结果。成功项再指向 ToBeSigned 的哈希。身份绑定证据、授权策略与应用回执依次连接,不覆盖前一层。

失败候选不是噪声。它们能解释轮换期为何出现两项、某节点为何与另一节点不同、数据库顺序为何改变行为。若只保留胜者和短标签,历史会伪装成从未存在歧义。完整结论应该分句写出:哪把钥匙验证了哪些字节,什么证据把它绑定到哪个身份,哪版政策允许或拒绝了什么动作,最终观察到什么结果。

来源