Question

I am trying to use xades4j library for verification which uses bouncycastle for Xades-BES and I am getting the following stacktrace:

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

Here is the code from xades4j which throws exception:

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);
}

The problem occurs only when I sign a file with a software provided by cryptoki tokens' manufacturer which by the way worked great till now and I was able to validate the same files with different validation software for xades. The problem occurs only in xades4j.

When I sign the same file with xades4j, it verifies everything as expected.

Below is the code for verification. certDataList is a list with all certificates from the document in String and getCert will return List. DummyCertificateValidationProvider returns ValidationData with a list of previously constructed 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;
}
Was it helpful?

Solution

CertificateValidationProvider must return a ValidationData with the certificate chain that validates the certificate represented by the supplied CertSelector. As described on the documentation, the certificates on ValidationData should be in order, namely, the first certificate should be the signing certificate.

When validating a TS token, the signing certificate is the TSA's certificate. When CertificateValidationProvider is asked to do the validation with a CertSelector, it must return the TSA cert in the first position of the chain. The TS validation code will assume that it is in the first position, as documented.

In your validation code you're picking all the certificates in the signature. That list is not a valid certificate chain for ALL the needed certificate validations. Eventually, the TSA certificate won't even be present on the signature.

I think you'll need to change your CertificateValidationProvider implementation to return, at least, the appropriate certificate in the first position. Let me know if this helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top