我正在尝试使用 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;
}