You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CMSSignedData分离签名可通过Bouncy Castle验证但java.security.Signature验证失败

问题原因与解决方案

这问题我之前也碰到过!核心原因是你混淆了两种完全不同的签名格式:

  • CMSSignedDataGenerator生成的是PKCS#7/CMS格式的签名数据:这是一个包含签名值、签名证书、摘要算法信息甚至完整证书链的封装容器,不是单纯的签名字节。
  • Java自带的Signature类验证的是原始PKCS#1签名值:也就是直接用私钥对消息摘要加密后的原始字节数组,没有任何额外封装。

这就是为什么BC自己的验证能过(它能解析CMS容器),但Signature类验证失败的原因——你把整个CMS容器传给它当签名值,当然不对。

两种解决思路

思路1:从CMS签名中提取原始PKCS#1签名值,再用Signature验证

如果你一定要用Java的Signature类验证,可以先解析CMS数据,提取出里面的原始签名值,再进行验证。修改你的shouldVerifyBySignature方法如下:

private static void shouldVerifyBySignature(byte[] signatureBytes) throws Exception {
    // 先解析CMS数据,提取原始签名值
    CMSSignedData cms = new CMSSignedData(new CMSProcessableByteArray(DATA_TO_BE_SIGNED), signatureBytes);
    SignerInformationStore signers = cms.getSignerInfos();
    SignerInformation signerInfo = (SignerInformation) signers.getSigners().iterator().next();
    byte[] rawSignature = signerInfo.getSignature(); // 这才是PKCS#1格式的原始签名值

    // 再用Signature类验证
    Signature signatureVerifier = Signature.getInstance(SHA_1_WITH_RSA, PROVIDER_NAME);
    signatureVerifier.initVerify(signer.getPublicKey());
    signatureVerifier.update(DATA_TO_BE_SIGNED);
    boolean verified = signatureVerifier.verify(rawSignature);
    System.out.println(verified ? "VERIFIED BY SIGNATURE CLASS" : "! Not verified by Signature class !");
}

思路2:推荐继续使用BouncyCastle的验证方式

CMS签名的设计初衷就是为了携带完整的签名上下文(比如证书链、签名算法、时间戳等),用BouncyCastle的SignerInformation.verify()方法验证是最适配的,它会自动处理证书链验证、摘要匹配等逻辑,比手动用Signature类更可靠。

额外说明

  • 你提到的“验证流程期望PKCS1结构,生成器输出PKCS7结构”完全正确,这就是问题的核心。
  • 流程中没有异常抛出是因为Signature.verify()只是检查签名值是否匹配,不会因为传入的字节格式不对而抛出异常,只会返回false。

内容的提问来源于stack exchange,提问作者bobo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:39:02