跳到主要内容

4. 签名对象

  1. 签名对象

COSE 支持两种不同的 signature 结构. COSE_Sign 允许对同一内容应用一个或多个 signature. COSE_Sign1 限制为单个 signer. 这些结构不能相互转换; 因为 signature 计算包含一个用于标识所用结构的参数, 转换后的结构将无法通过 signature validation.

4.1. 使用一个或多个签名者进行签名

COSE_Sign 结构允许对消息 payload 应用一个或多个 signature. 与内容相关的 header parameters 以及与 signature 相关的 header parameters 会与 signature 本身一起承载. 这些 header parameters 可以由 signature 认证, 也可以只是存在于结构中. 与内容相关的 header parameter 示例是 content type header parameter. 与 signature 相关的 header parameter 示例包括用于创建 signature 的算法和 key.

[RFC5652] 指出:

| 当存在多个 signature 时, 对给定 signer 关联的一个 signature 成功验证通常会被视为该 signer 的有效 signature. 但是, 在某些应用环境中需要其他规则. 如果应用采用的规则不是每个 signer 一个有效 signature, 则该应用必须指定这些规则. 此外, 当 signer identifier 的简单匹配不足以确定多个 signature 是否由同一 signer 生成时, 应用规范必须说明如何确定哪些 signature 由同一 signer 生成. 支持不同 recipient 群体, 是 signer 选择包含多个 signature 的主要原因.

例如, COSE_Sign 结构可以包含使用 Edwards-curve Digital Signature Algorithm (EdDSA) [RFC8032] 和 Elliptic Curve Digital Signature Algorithm (ECDSA) [DSS] 生成的 signature. 这允许 recipient 验证与其中一种算法关联的 signature. 关于多个 signature evaluation 的更详细信息见 [RFC5752].

signature 结构可根据使用上下文编码为 tagged 或 untagged. tagged COSE_Sign 结构由 CBOR tag 98 标识. 表示它的 CDDL 片段为:

COSE_Sign_Tagged = #6.98(COSE_Sign)

COSE Signed Message 分为两个部分定义. 承载 body 和消息相关信息的 CBOR object 称为 COSE_Sign 结构. 承载 signature 和 signature 相关信息的 CBOR object 称为 COSE_Signature 结构. COSE Signed Messages 示例见 Appendix C.1.

COSE_Sign 结构是一个 CBOR array. array 的字段按顺序为:

protected: 如 Section 3 所述.

unprotected: 如 Section 3 所述.

payload: 此字段包含待签名内容的序列化形式. 如果消息中不存在 payload, 应用程序需要单独提供 payload. payload 封装在 bstr 中, 以确保传输时不会发生变化. 如果 payload 单独传输("detached content"), 则在此位置放置一个 nil CBOR object, 并由应用程序负责确保它在传输时不会发生变化.

  Note: 当使用带有 message recovery algorithm 的 signature 时(Section 8.1), 可恢复的最大字节数是原始 payload 的长度. 已编码 payload 的大小会按将被恢复的字节数减少. 如果原始 payload 的所有字节都被消耗, 则传输的 payload 编码为零长度 byte string, 而不是编码为不存在.

signatures: 此字段是 signature array. 每个 signature 表示为一个 COSE_Signature 结构.

表示上述 COSE_Sign 文本的 CDDL 片段如下.

COSE_Sign = [ Headers, payload : bstr / nil, signatures : [+ COSE_Signature] ]

COSE_Signature 结构是一个 CBOR array. array 的字段按顺序为:

protected: 如 Section 3 所述.

unprotected: 如 Section 3 所述.

signature: 此字段包含计算得到的 signature 值. 字段类型为 bstr. 如果 signature 值不是 8 bit 的倍数, 算法 MUST 指定 padding.

表示上述 COSE_Signature 文本的 CDDL 片段如下.

COSE_Signature = [ Headers, signature : bstr ]

4.2. 使用一个签名者进行签名

当消息上只放置一个 signature 时, 使用 COSE_Sign1 signature 结构. 处理内容和 signature 的 header parameters 被放在同一对 bucket 中, 而不是像 COSE_Sign 那样分离.

该结构可根据使用上下文编码为 tagged 或 untagged. tagged COSE_Sign1 结构由 CBOR tag 18 标识. 表示它的 CDDL 片段为:

COSE_Sign1_Tagged = #6.18(COSE_Sign1)

承载 body, signature 以及 body 和 signature 相关信息的 CBOR object 称为 COSE_Sign1 结构. COSE_Sign1 消息示例见 Appendix C.2.

COSE_Sign1 结构是一个 CBOR array. array 的字段按顺序为:

protected: 如 Section 3 所述.

unprotected: 如 Section 3 所述.

payload: 如 Section 4.1 所述.

signature: 此字段包含计算得到的 signature 值. 字段类型为 bstr.

表示上述 COSE_Sign1 文本的 CDDL 片段如下.

COSE_Sign1 = [ Headers, payload : bstr / nil, signature : bstr ]

4.3. 外部提供的数据

COSE 提供的一项功能是, 应用程序可以提供需要被认证但不作为 COSE object 一部分承载的附加数据. 支持此功能的主要原因可以从 CoAP message structure [RFC7252] 看出: CoAP 允许 options 承载在 payload 之前. 可放在该位置的数据示例包括 CoAP code 或 CoAP options. 如果数据位于 CoAP 消息的 headers 中, 则代理可以使用这些数据来协助执行代理操作. 例如, 代理可以使用 Accept option 判断其缓存中是否有适当值. sender 可以使用 additional-data 功能来检测代理或攻击者对 Accept 值集合所做的任何更改. 通过把该字段包含在 externally supplied data 中, 后续任何修改都会导致服务器处理该消息失败.

本文档描述了使用外部提供的认证数据 byte array 的过程; byte array 的构造方法由应用决定. 使用此功能的应用需要定义 externally supplied authenticated data 应如何构造. 这种构造需要考虑以下问题:

  • 如果包含多个 item, 应用需要确保不同输入不会产生相同 byte string. 问题场景的一个示例是拼接 text string "AB" 和 "CDE", 或拼接 text string "ABC" 和 "DE". 通常通过将字段设为固定宽度和/或把字段长度编码为输出的一部分来解决此问题. 以 CoAP [RFC7252] 的 options 为例, 这些字段使用 TLV 结构, 因此可以直接拼接而不会出现问题.

  • 如果包含多个 item, 需要定义这些 item 的顺序. 以 CoAP options 为例, 应用可以声明字段按 option number 排序.

  • 应用需要确保 byte string 在双方完全相同. 如果使用 CoAP options, 且保持相同的相对编号方式, 可能会出现问题. 中间节点可以插入或移除 option, 从而改变相对编号的方式. 应用需要指定, 相对编号必须重新编码为只相对于 external data 中的 options.

4.4. 签名和验证过程

为了创建 signature, 需要一个定义明确的 byte string. Sig_structure 用于创建 canonical form. 此签名和验证过程输入 body information (COSE_Sign 或 COSE_Sign1), signer information (COSE_Signature), 以及 application data (external source). Sig_structure 是一个 CBOR array. Sig_structure 的字段按顺序为:

  1. 一个 context text string, 用于标识 signature 的上下文. context text string 为:

    使用 COSE_Signature 结构的 signature 为 "Signature".

    使用 COSE_Sign1 结构的 signature 为 "Signature1".

  2. 来自 body structure 的 protected attributes, 编码为 bstr 类型. 如果没有 protected attributes, 则使用零长度 byte string.

  3. 来自 signer structure 的 protected attributes, 编码为 bstr 类型. 如果没有 protected attributes, 则使用零长度 byte string. 对 COSE_Sign1 signature 结构, 该字段省略.

  4. 来自应用程序的 externally supplied data, 编码为 bstr 类型. 如果未提供此字段, 它默认为零长度 byte string. (关于构造此字段的应用指导, 见 Section 4.3.)

  5. 待签名的 payload, 编码为 bstr 类型. 此处使用完整 payload, 与它如何传输无关.

描述上述文本的 CDDL 片段为:

Sig_structure = [ context : "Signature" / "Signature1", body_protected : empty_or_serialized_map, ? sign_protected : empty_or_serialized_map, external_aad : bstr, payload : bstr ]

signature 计算步骤:

  1. 创建 Sig_structure 并填充适当字段.

  2. 按 Section 9 所述编码方式, 将 Sig_structure 编码为 byte string, 以创建 ToBeSigned 值.

  3. 调用 signature creation algorithm, 传入 K (用于签名的 key), alg (用于签名的 algorithm), 以及 ToBeSigned (待签名的值).

  4. 将生成的 signature 值放在正确位置. 该位置是 COSE_Signature 或 COSE_Sign1 结构的 "signature" 字段.

signature 验证步骤:

  1. 创建 Sig_structure 并填充适当字段.

  2. 按 Section 9 所述编码方式, 将 Sig_structure 编码为 byte string, 以创建 ToBeSigned 值.

  3. 调用 signature verification algorithm, 传入 K (用于验证的 key), alg (用于签名的 algorithm), ToBeSigned (待签名的值), 以及 sig (待验证的 signature).

除执行 signature verification 外, 应用程序还会执行适当检查, 以确保 key 与 signing identity 正确配对, 并确保 signing identity 在执行操作前已经获得授权.