错误信息
Verification failure
这是 OpenSSL 3.x 的措辞。OpenSSL 1.1.x 写作首字母大写的“Verification Failure”。openssl pkeyutl -verify 输出与之对应的“Signature Verification Failure”。在 OpenSSL 3.x 上,两者都会伴随一行错误栈信息,例如“error:030000EA:digital envelope routines:EVP_DigestVerifyFinal:provider signature failure”(已在 3.6 上复现)。根本不是 DER 格式的签名走不到这一步:它会报错“Error verifying data”。
含义
openssl dgst -verify 计算了数据的摘要,用公钥检查了签名,而数学运算给出了否定的结果。密钥、数据和签名都能正常读取——但三者之中有一个与另外两个不匹配。作为对比,成功时的输出是“Verified OK”。
原因
数据与签名时的内容不同
常见编辑器添加的末尾换行符、git 执行的 CRLF 与 LF 转换,或者对已经哈希过的摘要再次哈希(dgst 会对输入做哈希——把 SHA-256 摘要交给它,签名的就是哈希的哈希)。
摘要算法不匹配
常见签名时用的是 -sha256,验证时却用了 -sha384(或者签名方的库默认使用了另一种哈希算法)。摘要是签名内容的一部分;双方必须使用同一种摘要算法。
公钥错误
偶见已轮换的密钥、另一个服务的密钥,或者从另一把私钥(而不是签名所用的私钥)派生出的公钥。
修复方法
- 1.
先排除签名编码问题
dgst -verify 只按 ASN.1 DER 解析 ECDSA 签名。来自 WebCrypto、JWS 或 Go/Python 原始模式 API 的原始 r‖s 签名(P-256 恰好 64 字节,P-384 恰好 96 字节)会更早失败,报错“Error verifying data”。如果你的签名是 DER 格式,却仍然在这里失败,那么出错的是数据、摘要或密钥。下方的 DER ⇄ 原始格式转换工具可以在两种格式之间转换,并标记出严格的验证器会拒绝的非规范 high-S 值。
- 2.
用 pkeyutl 验证预先计算的摘要
如果你手里只有摘要而不是消息,dgst 就不是合适的工具(它会再哈希一次)。pkeyutl 直接用原始摘要验证签名。
bash openssl dgst -sha256 -binary message.bin > msg.hash openssl pkeyutl -verify -pubin -inkey pub.pem \ -sigfile sig.der -in msg.hash -pkeyopt digest:sha256 - 3.
排除数据差异
在两端分别对各自实际使用的字节原样计算摘要并比较;只要有差异,就说明是消息变了,而不是密码学运算出了问题。
bash openssl dgst -sha256 message.bin # run on signer and verifier sides xxd message.bin | tail -2 # check for a sneaky trailing 0a