我正在尝试使用xades4j库进行验证,它使用bouncycastle进行Xades-BES,我得到以下堆栈跟踪:
xades4j.verification.TimeStampInvalidSignatureException: Verification failed for property 'SignatureTimeStamp': invalid token signature
at xades4j.verification.TimeStampVerifierBase.getEx(TimeStampVerifierBase.java:114)
at xades4j.verification.TimeStampVerifierBase.verify(TimeStampVerifierBase.java:89)
at xades4j.verification.TimeStampVerifierBase.verify(TimeStampVerifierBase.java:38)
at xades4j.verification.QualifyingPropertiesVerifierImpl.verifyProperties(QualifyingPropertiesVerifierImpl.java:59)
at xades4j.verification.XadesVerifierImpl.getValidationDate(XadesVerifierImpl.java:250)
at xades4j.verification.XadesVerifierImpl.verify(XadesVerifierImpl.java:174)
at com.signapplet.sign.SignComponent.verify(SignComponent.java:663)
Caused by: xades4j.providers.TimeStampTokenSignatureException: Invalid token signature or certificate
at xades4j.providers.impl.DefaultTimeStampVerificationProvider.verifyToken(DefaultTimeStampVerificationProvider.java:154)
at xades4j.verification.TimeStampVerifierBase.verify(TimeStampVerifierBase.java:71)
... 42 more
Caused by: org.bouncycastle.tsp.TSPValidationException: certificate hash does not match certID hash.
at org.bouncycastle.tsp.TimeStampToken.validate(Unknown Source)
at xades4j.providers.impl.DefaultTimeStampVerificationProvider.verifyToken(DefaultTimeStampVerificationProvider.java:150)
... 43 more
以下是来自xades4j的代码,它抛出异常:
try
{
tsToken.validate(this.signerInfoVerifierBuilder.build(tsaCert)); //tsToken==org.bouncycastle.tsp.TimeStampToken
}
catch (TSPValidationException ex)
{
throw new TimeStampTokenSignatureException("Invalid token signature or certificate", ex);
}
catch (Exception ex)
{
throw new TimeStampTokenVerificationException("Error when verifying the token signature", ex);
}
只有当我使用cryptoki令牌制造商提供的软件对文件进行签名时才会出现问题,顺便说一下,到目前为止,我能够使用不同的xades验证软件验证相同的文件。该问题仅发生在xades4j中。
当我使用xades4j签署同一文件时,它会按预期验证所有内容。
以下是验证码。 certDataList是一个列表,其中包含String中文档的所有证书,getCert将返回List。 DummyCertificateValidationProvider返回ValidationData,其中包含先前构造的x509certs的列表。
public boolean verify(final File file) {
if (!Dictionaries.valid()) {
return true;
}
certList = null;
try {
final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
final DocumentBuilder db = dbf.newDocumentBuilder();
final Document doc = db.parse(file);
doc.getDocumentElement().normalize();
final NodeList nList = doc.getElementsByTagName("ds:Signature");
Element elem = null;
for (int temp = 0; temp < nList.getLength(); temp++) {
final Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
elem = (Element) nNode;
}
}
final NodeList nList2 = doc.getElementsByTagName("ds:X509Certificate");
final List<String> certDataList = new ArrayList<String>();
for (int temp = 0; temp < nList2.getLength(); temp++) {
final Node nNode = nList2.item(temp);
certDataList.add(nNode.getTextContent());
}
certList = getCert(certDataList);
final CertificateValidationProvider certValidator = new DummyCertificateValidationProvider(certList);
final XadesVerificationProfile p = new XadesVerificationProfile(certValidator);
final XadesVerifier v = p.newVerifier();
final SignatureSpecificVerificationOptions opts = new SignatureSpecificVerificationOptions();
// for relative document paths
final String baseUri = "file:///" + file.getParentFile().getAbsolutePath().replace("\\", "/") + "/";
LOGGER.debug("baseUri:" + baseUri);
opts.useBaseUri(baseUri);
v.verify(elem, opts);
return true;
} catch (final IllegalArgumentException | XAdES4jException | CertificateException | IOException | ParserConfigurationException | SAXException e) {
LOGGER.error("XML not validated!", e);
}
return false;
}
答案 0 :(得分:2)
CertificateValidationProvider
必须返回ValidationData
,其中包含验证所提供的CertSelector
所代表的证书的证书链。作为described on the documentation,ValidationData
上的证书应该是有序的,即第一个证书应该是签名证书。
验证TS令牌时,签名证书是TSA的证书。当要求CertificateValidationProvider
使用CertSelector进行验证时,它必须在链的第一个位置返回TSA证书。 TS验证代码将假定它处于第一个位置,如文档所述。
在您的验证码中,您将选择签名中的所有证书。该列表不是所有所需证书验证的有效证书链。最终,TSA证书甚至不会出现在签名上。
我认为您需要更改CertificateValidationProvider
实施,以便至少返回第一个位置的相应证书。如果这有帮助,请告诉我。