如何验证带PKCS#7分离签名(p7s)的JSON文件?代码报错求助
解决PKCS#7(p7s)签名验证的长度不匹配问题
你遇到的Signature length not correct错误,核心原因是p7s是完整的PKCS#7/CMS签名容器——它不止包含原始签名字节,还封装了签名算法、证书链、签名属性等元数据,直接把整个p7s文件字节传给Signature.verify()会导致长度不匹配(RSA-2048签名固定256字节,而p7s容器要大得多)。
解决方案
不需要手动提取签名字节,直接用CMS签名验证API结合BouncyCastle提供者解析p7s文件并完成验证,步骤如下:
- 添加BouncyCastle依赖(Maven示例):
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version> </dependency>
- 修改验证代码:
替换原有Signature相关逻辑,改用CMSSignedData处理p7s文件,同时用你持有的公证书验证签名有效性:
import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.SignerInformation; import org.bouncycastle.cms.SignerInformationStore; import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.io.ByteArrayInputStream; import java.security.Security; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Collection; public void getFiles(@RequestParam("json") MultipartFile json, @RequestParam("json-sig") MultipartFile jsonSig) throws Exception { // 注册BouncyCastle安全提供者 Security.addProvider(new BouncyCastleProvider()); // 加载持有的公证书 String certificateStr = CERTIFIFATE; CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); byte[] certBytes = Base64.getDecoder().decode(certificateStr); X509Certificate publicCert = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(certBytes)); // 解析p7s签名文件为CMS签名数据 CMSSignedData cmsSignedData = new CMSSignedData(jsonSig.getBytes()); // 获取签名信息集合 SignerInformationStore signerStore = cmsSignedData.getSignerInfos(); Collection<SignerInformation> signers = signerStore.getSigners(); if (signers.isEmpty()) { throw new IllegalArgumentException("p7s文件中未找到有效签名"); } // 验证签名及原始文件一致性 boolean isVerified = false; for (SignerInformation signer : signers) { // 用持有的公证书验证签名有效性 if (signer.verify(publicCert, BouncyCastleProvider.PROVIDER_NAME)) { // 验证原始JSON与签名绑定的内容是否一致 byte[] signedContent = (byte[]) cmsSignedData.getSignedContent().getContent(); if (java.util.Arrays.equals(signedContent, json.getBytes())) { isVerified = true; break; } } } // isVerified即为最终验证结果,可根据业务逻辑处理 System.out.println("签名验证结果:" + isVerified); }
关键说明
- 注册BouncyCastle是为了兼容更多CMS签名特性,避免解析失败;
- 遍历签名集合是因为p7s可能包含多个签名,只需匹配你持有的公证书对应的签名即可;
- 额外比对原始JSON与签名绑定内容,防止签名被篡改或关联错误文件;
- 可根据业务需求调整异常处理逻辑,比如签名不存在、证书不匹配等场景的提示。
内容的提问来源于stack exchange,提问作者Adam Jedrzejko
相关产品推荐
相关产品推荐

