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

使用Bouncy Castle在Java中验签失败问题求助

验签返回false的排查与解决

操作背景

我用OpenSSL生成了证书test.cer和密钥库test.p12,接着用Bouncy Castle完成签名流程并生成signed.p7s文件,但验签时始终返回false,已替换{JAVA_HOME}/lib/security下的local_policy.jar,求排查原因。

签名流程代码

  1. 加载X.509证书
Security.addProvider(new BouncyCastleProvider());
CertificateFactory certFactory = CertificateFactory.getInstance("X.509", "BC");

X509Certificate certificate = (X509Certificate) certFactory
        .generateCertificate(new FileInputStream("test.cer"));
  1. 读取源文件与私钥
byte[] fileContent = Files.readAllBytes(new File("source.txt").toPath());
char[] keystorePassword = "password".toCharArray();
char[] keyPassword = "password".toCharArray();
KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(new FileInputStream("test.p12"), keystorePassword);
PrivateKey privateKey = (PrivateKey) keystore.getKey("archive", keyPassword);
  1. 生成签名文件signed.p7s
byte[] signedMessage = null;
List<X509Certificate> certList = new ArrayList<X509Certificate>();
CMSTypedData cmsData = new CMSProcessableByteArray(data);
certList.add(signingCertificate);
Store certs = new JcaCertStore(certList);
CMSSignedDataGenerator cmsGenerator = new CMSSignedDataGenerator();
ContentSigner contentSigner
        = new JcaContentSignerBuilder("SHA256withRSA").build(signingKey);
cmsGenerator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
        new JcaDigestCalculatorProviderBuilder().setProvider("BC")
                .build()).build(contentSigner, signingCertificate));
cmsGenerator.addCertificates(certs);
CMSSignedData cms = cmsGenerator.generate(cmsData, true);
byte[] signedMessage = cms.getEncoded();
File targetFile = new File(Paths.get(fileDir).getParent().toString(), "/" + "signed.p7s");
targetFile.createNewFile();
Files.write(Paths.get(targetFile.getAbsolutePath()), signedMessage);

验签代码

byte[] signedData = Files.readAllBytes(new File("signed.p7s").toPath());
ByteArrayInputStream bIn = new ByteArrayInputStream(signedData);
ASN1InputStream aIn = new ASN1InputStream(bIn);
CMSSignedData s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
aIn.close();
bIn.close();
Store certs = s.getCertificates();
SignerInformationStore signers = s.getSignerInfos();
Collection<SignerInformation> c = signers.getSigners();
SignerInformation signer = c.iterator().next();
Collection<X509CertificateHolder> certCollection = certs.getMatches(signer.getSID());
Iterator<X509CertificateHolder> certIt = certCollection.iterator();
X509CertificateHolder certHolder = certIt.next();
boolean verifResult = signer.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certHolder));

几个可能的问题点和解决办法

1. 签名用的数据源不匹配

签名代码里用了CMSProcessableByteArray(data),但前面明明读取了源文件内容到fileContent变量,如果data不是fileContent,等于签名的内容和验签预期的源内容不一致,直接导致验签失败。
修改方式:将data替换为fileContent:

CMSTypedData cmsData = new CMSProcessableByteArray(fileContent);

2. 签名代码变量名不对应

你前面加载的证书是certificate、私钥是privateKey,但签名代码里用了未定义的signingCertificate和signingKey,如果这些变量没有正确赋值,等于用错误的证书/私钥签名,验签肯定失败。
修改方式:替换为正确的变量名:

certList.add(certificate);
ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256withRSA").build(privateKey);
cmsGenerator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
        new JcaDigestCalculatorProviderBuilder().setProvider("BC").build())
        .build(contentSigner, certificate));

3. 验签未指定Bouncy Castle Provider

验签代码里new JcaSimpleSignerInfoVerifierBuilder()没有指定Provider,可能默认Provider无法正确识别Bouncy Castle生成的签名格式。
修改方式:添加Provider指定:

boolean verifResult = signer.verify(new JcaSimpleSignerInfoVerifierBuilder()
        .setProvider("BC")
        .build(certHolder));

4. 签名文件写入路径错误

生成signed.p7s时的路径拼接用了"/" + "signed.p7s",可能导致路径格式错误(比如出现重复斜杠),进而导致写入的签名文件损坏。
修改方式:用更可靠的路径生成方式,且Files.write会自动创建文件,无需手动调用createNewFile():

File targetFile = new File(Paths.get(fileDir).getParent().resolve("signed.p7s").toString());
Files.write(targetFile.toPath(), signedMessage);

5. 证书与私钥不配对

先确认test.cer的证书和test.p12中alias="archive"的私钥是配对的,用OpenSSL命令验证:

# 查看证书的公钥
openssl x509 -in test.cer -pubkey -noout
# 查看p12中私钥对应的公钥
openssl pkcs12 -in test.p12 -nocerts -nodes | openssl rsa -pubout

如果两个公钥不一致,说明证书和私钥不匹配,需要重新生成。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 13:08:10