java - 异常选择签名:无法验证签名
问题描述
我有以下代码,取自PDFBox 2 中的ShowSignature示例。我正在运行五个测试,其中 4 个通过没有问题(无签名、单签名、双签名、过期签名),但是第五个是机智的椭圆曲线,但它失败了。
有趣的是,当我仅在测试类上启动 JunitTest 时它会通过,但一旦我在包或项目级别启动它就会失败。
我会假设测试类之前的某些东西正在干扰,但找不到暗示它可能是什么。我检查了 bouncycastle(始终使用 1.54),java jdk 在任何时候都正确使用(jdk1.8.0_181)。
我正在检查要抛出的异常(ERROR_VERIFYING_PDF_SIGNATURE
),它是在类测试中抛出的,但是在更高级别开始时会抛出一个不同的异常。
if 中发生错误(signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certFromSignedData))
并且具有此堆栈跟踪:
java.lang.AssertionError:
Expected: (an instance of de.bdr.rt.core.common.api.BusinessLogicException and exception with message a string containing "Die Signatur des PDF-Dokuments konnte nicht verifiziert werden.")
but: an instance of de.bdr.rt.core.common.api.BusinessLogicException <org.bouncycastle.operator.RuntimeOperatorException: exception obtaining signature: Could not verify signature> is a org.bouncycastle.operator.RuntimeOperatorException
Stacktrace was: org.bouncycastle.operator.RuntimeOperatorException: exception obtaining signature: Could not verify signature
at org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder$SigVerifier.verify(Unknown Source)
at org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder$RawSigVerifier.verify(Unknown Source)
at org.bouncycastle.cms.SignerInformation.doVerify(Unknown Source)
at org.bouncycastle.cms.SignerInformation.verify(Unknown Source)
at de.bdr.gematik.tsp.sc.antragsverwaltung.impl.itsp.ds.PDFDigitalSignatureCheckTest.verifyPKCS7(PDFDigitalSignatureCheckTest.java:280)
at de.bdr.gematik.tsp.sc.antragsverwaltung.impl.itsp.ds.PDFDigitalSignatureCheckTest.testPdfSignature(PDFDigitalSignatureCheckTest.java:170)
at de.bdr.gematik.tsp.sc.antragsverwaltung.impl.itsp.ds.PDFDigitalSignatureCheckTest.testPDFECKeySignaturFails(PDFDigitalSignatureCheckTest.java:112)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by: java.security.SignatureException: Could not verify signature
at sun.security.ec.ECDSASignature.engineVerify(ECDSASignature.java:325)
at java.security.Signature$Delegate.engineVerify(Signature.java:1222)
at java.security.Signature.verify(Signature.java:655)
at org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder$SignatureOutputStream.verify(Unknown Source)
... 32 more
Caused by: java.security.InvalidAlgorithmParameterException
at sun.security.ec.ECDSASignature.verifySignedDigest(Native Method)
at sun.security.ec.ECDSASignature.engineVerify(ECDSASignature.java:321)
... 35 more
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
at org.junit.Assert.assertThat(Assert.java:956)
at org.junit.Assert.assertThat(Assert.java:923)
at org.junit.rules.ExpectedException.handleException(ExpectedException.java:252)
at org.junit.rules.ExpectedException.access$000(ExpectedException.java:106)
at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:241)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
代码:
private void verifyPKCS7(byte[] byteArray, COSString contents, PDSignature sig)
throws CMSException, CertificateException, StoreException, OperatorCreationException,
NoSuchAlgorithmException, NoSuchProviderException {
CMSProcessable signedContent = new CMSProcessableByteArray(byteArray);
CMSSignedData signedData = new CMSSignedData(signedContent, contents.getBytes());
@SuppressWarnings("unchecked")
Store<X509CertificateHolder> certificatesStore = signedData.getCertificates();
Collection<SignerInformation> signers = signedData.getSignerInfos().getSigners();
SignerInformation signerInformation = signers.iterator().next();
@SuppressWarnings("unchecked")
Collection<X509CertificateHolder> matches = certificatesStore
.getMatches((Selector<X509CertificateHolder>) signerInformation.getSID());
X509CertificateHolder certificateHolder = matches.iterator().next();
X509Certificate certFromSignedData = new JcaX509CertificateConverter().getCertificate(certificateHolder);
System.out.println("certFromSignedData: " + certFromSignedData);
try {
certFromSignedData.checkValidity(sig.getSignDate().getTime());
System.out.println("Certificate valid at signing time");
} catch (CertificateExpiredException ex) {
System.err.println("Certificate expired at signing time");
} catch (CertificateNotYetValidException ex) {
System.err.println("Certificate not yet valid at signing time");
}
if (isSelfSigned(certFromSignedData)) {
System.err.println("Certificate is self-signed, LOL!");
} else {
System.out.println("Certificate is not self-signed");
// todo rest of chain
}
if (signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certFromSignedData))) {
System.out.println("Signature verified");
} else {
System.out.println("Signature verification failed");
throw new BusinessLogicException(Messages.ERROR_VERIFYING_PDF_SIGNATURE);
}
}
解决方案
这是 PDFBox 示例的一个缺点。请更换
signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certFromSignedData));
至
signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME).build(certFromSignedData));
您可能需要将 BC 注册为提供者:
Security.addProvider(new BouncyCastleProvider());
推荐阅读
- python - 从 JSON 文件计数到 python
- java - 这个接口和类是如何实现的?
- reactjs - Draft.js - 从数据库中检索格式化文本
- php - Laravel7如何自定义RegisterController以在用户选择时保存多个数据
- reactjs - React JS 用一个按钮改变一个值
- python - 如何将列表的元素除以另一个不同维度的列表的元素?
- python - 字典的键替换键?
- python - Python 计数在快速排序功能中的变化和比较
- node.js - 节点版本卡在 v6.13.1
- python - 为什么 matplotlib 直方图中的列不在数字之上