2. 签名算法
- 签名算法
[RFC9052] 第 8.1 节包含对签名算法的通用描述. 本文档为两种签名算法定义 signature algorithm identifiers.
2.1. ECDSA
Elliptic Curve Digital Signature Algorithm (ECDSA) [DSS] 定义了一种使用 Elliptic Curve Cryptography (ECC) 的签名算法. 实现 SHOULD 使用 ECDSA 的确定性版本, 例如 [RFC6979] 中定义的版本. 使用确定性签名算法使系统能够避免依赖随机数生成器来防止生成相同的 "k" 值 (每消息随机值). 有偏的 "k" 值生成可能受到攻击, 而该值碰撞会导致 key 泄露. 它还允许对签名算法执行确定性测试. 使用 deterministic ECDSA 并不会降低创建私钥时对良好随机数生成的需求.
ECDSA 签名算法以 hash function (h) 参数化. 如果 hash function 输出长度大于 key 的 group, 则使用 hash 输出最左侧的字节.
本文档定义的算法见表 1.
+=======+=======+=========+==================+
| Name | Value | Hash | Description |
+=======+=======+=========+==================+
| ES256 | -7 | SHA-256 | ECDSA w/ SHA-256 |
+-------+-------+---------+------------------+
| ES384 | -35 | SHA-384 | ECDSA w/ SHA-384 |
+-------+-------+---------+------------------+
| ES512 | -36 | SHA-512 | ECDSA w/ SHA-512 |
+-------+-------+---------+------------------+
表 1: ECDSA Algorithm Values
本文档定义 ECDSA 仅与 curve P-256, P-384 和 P-521 配合工作. 本文档要求使用 "EC2" (two coordinate elliptic curve) key type 对这些 curve 进行编码. 实现在创建和验证签名时需要检查 key type 和 curve 是否正确. 未来文档可能会定义它与其他 curve 和 key type 配合工作.
为促进互操作性, 建议 SHA-256 仅与 curve P-256 一起使用, SHA-384 仅与 curve P-384 一起使用, SHA-512 仅与 curve P-521 一起使用. 这与 [RFC5480] 第 4 节中的建议一致.
该签名算法产生一对整数 (R, S). 这些整数的长度将与签名过程中使用的 key 长度相同. 签名通过把这些整数转换为与 key size 长度相同的 byte string 来编码. 长度向上取整到最接近的字节, 并在左侧用零比特填充到正确长度. 然后将两个整数连接在一起, 形成作为结果签名的 byte string.
使用 [RFC8017] 中定义的函数, 签名为:
Signature = I2OSP(R, n) | I2OSP(S, n)
其中 n = ceiling(key_length / 8)
对此算法使用 COSE key 时, 执行以下检查:
-
"kty" 字段 MUST 存在, 且 MUST 为 "EC2".
-
如果 "alg" 字段存在, 它 MUST 匹配正在使用的 ECDSA signature algorithm.
-
如果 "key_ops" 字段存在, 创建 ECDSA 签名时它 MUST 包含 "sign".
-
如果 "key_ops" 字段存在, 验证 ECDSA 签名时它 MUST 包含 "verify".
2.1.1. ECDSA 的安全考量
签名的安全强度不超过 key 比特长度关联的安全强度和 hash function 安全强度二者中的较小值.
注意: 即使存在良好的随机数生成, 使用确定性签名技术也是好主意. 这样既降低两个签名操作中出现相同 "k" 值的可能性, 又允许可复现的签名值, 从而有助于测试. 最近存在通过对设备注入故障以提取 key 的攻击. 这可以通过同时结合随机性和确定性来处理 [CFRG-DET-SIGS].
理论上可对 ECDSA 签名算法发起两种替换攻击.
-
改变用于验证签名的 curve: 如果改变用于验证签名的 curve, 则潜在地可能有两条具有相同签名的消息, 且每条消息都在不同 curve 下计算. 对新 curve 的唯一要求是其 order 与旧 curve 相同, 并且客户端可接受它. 一个例子是从使用 curve secp256r1 (即 P-256) 改为使用 secp256k1. (二者都是 256-bit curves.) 目前除了限制可使用的整体 curve 集合外, 我们没有其他方式处理这种攻击变体.
-
改变用于验证签名的 hash function: 如果拥有两个长度相同的不同 hash function, 或者可以截断某个 hash function, 则可能找到 hash function 之间的碰撞, 而不是单个 hash function 内部的碰撞. 例如, 将 SHA-512 截断到 256 位可能与 SHA-256 hash 值碰撞. 由于 hash algorithm 是 signature algorithm identifier 的一部分, 通过在 protected-header bucket 中包含 signature algorithm identifier 可以缓解此攻击.
2.2. Edwards-Curve Digital Signature Algorithm (EdDSA)
[RFC8032] 描述了 elliptic curve 签名方案 Edwards-curve Digital Signature Algorithm (EdDSA). 在该文档中, 签名算法使用 edwards25519 和 edwards448 curves 的参数实例化. 该文档还描述了 EdDSA 算法的两种变体: Pure EdDSA, 即签名前不对内容应用 hash function; 以及 HashEdDSA, 即签名前对内容应用 hash function 并签署该 hash function 的结果. 对于 EdDSA, 待签名内容 (消息或 prehash 值) 在签名算法内部会被处理两次. 与 COSE 一起使用时, 只使用 pure EdDSA 版本. 这是因为预计不会需要极大的内容, 并且根据消息结构的安排, 为创建或验证签名, 整个消息都需要保存在内存中. 因此, 似乎不需要能够对 hash 执行块更新, 然后从内存中移除消息. 应用可以通过把消息内容定义为 hash 值, 并把 COSE object (带 hash 值) 和内容作为分离项传输, 来提供相同特性.
本文档定义的算法见表 2. 其中定义了单个签名算法, 可用于多个 curve.
+=======+=======+=============+
| Name | Value | Description |
+=======+=======+=============+
| EdDSA | -8 | EdDSA |
+-------+-------+-------------+
表 2: EdDSA Algorithm Value
[RFC8032] 描述了签名值的编码方法.
对此算法使用 COSE key 时, 执行以下检查:
-
"kty" 字段 MUST 存在, 且 MUST 为 "OKP" (Octet Key Pair).
-
"crv" 字段 MUST 存在, 且 MUST 是为此签名算法定义的 curve.
-
如果 "alg" 字段存在, 它 MUST 匹配 "EdDSA".
-
如果 "key_ops" 字段存在, 创建 EdDSA 签名时它 MUST 包含 "sign".
-
如果 "key_ops" 字段存在, 验证 EdDSA 签名时它 MUST 包含 "verify".
2.2.1. EdDSA 的安全考量
EdDSA 和 Elliptic Curve Diffie-Hellman (ECDH) 中 public values 的计算方式不同; 因此, 一个算法中的 public key 不应与另一个算法一起使用.
如果执行批量签名验证, 则 REQUIRED 使用种子良好的加密随机数生成器 ([RFC8032] 第 8.2 节). 签名和非批量签名验证是确定性操作, 不需要任何类型的随机数.