XAdES BES时间戳验证错误

时间:2014-03-23 16:09:16

标签: bouncycastle xades4j

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

1 个答案:

答案 0 :(得分:2)

CertificateValidationProvider必须返回ValidationData,其中包含验证所提供的CertSelector所代表的证书的证书链。作为described on the documentationValidationData上的证书应该是有序的,即第一个证书应该是签名证书。

验证TS令牌时,签名证书是TSA的证书。当要求CertificateValidationProvider使用CertSelector进行验证时,它必须在链的第一个位置返回TSA证书。 TS验证代码将假定它处于第一个位置,如文档所述。

在您的验证码中,您将选择签名中的所有证书。该列表不是所有所需证书验证的有效证书链。最终,TSA证书甚至不会出现在签名上。

我认为您需要更改CertificateValidationProvider实施,以便至少返回第一个位置的相应证书。如果这有帮助,请告诉我。