Java Xades4j验证签名Xades-EPES:错误的XML签名

Java Xades4j验证签名Xades-EPES:错误的XML签名,java,xades4j,Java,Xades4j,我正在使用Xades4J开发一个简单的Java程序,用XADES-EPES对XML进行签名和验证。签名过程似乎工作正常,并生成了有效的签名XML(尽管我们不需要其中的SignaturePolicyIdentifier部分) *options arguments来自joptsimple库,用于解析参数 这是我的符号功能: void signXML(OptionSet options) { KeyingDataProvider kp; try { Signature

我正在使用Xades4J开发一个简单的Java程序,用XADES-EPES对XML进行签名和验证。签名过程似乎工作正常,并生成了有效的签名XML(尽管我们不需要其中的SignaturePolicyIdentifier部分)

*options arguments来自joptsimple库,用于解析参数

这是我的符号功能:

void signXML(OptionSet options) {
    KeyingDataProvider kp;
    try {

        SignaturePolicyInfoProvider policyInfoProvider = new SignaturePolicyInfoProvider() {
            public SignaturePolicyBase getSignaturePolicy() {
                return new SignaturePolicyIdentifierProperty(
                        new ObjectIdentifier("oid:/1.2.4.0.9.4.5", IdentifierType.OIDAsURI, "Policy description"),
                        new ByteArrayInputStream("Test policy input stream".getBytes()))
                                .withLocationUrl("http://www.example.com/policy");
            }
        };

        kp = new FileSystemKeyStoreKeyingDataProvider("pkcs12", options.valueOf("certificate").toString(),
                new FirstCertificateSelector(), new DirectPasswordProvider(options.valueOf("password").toString()),
                new DirectPasswordProvider(options.valueOf("password").toString()), false);

        // SignaturePolicyInfoProvider spi = new
        XadesSigningProfile p = new XadesEpesSigningProfile(kp, policyInfoProvider);
        p.withBasicSignatureOptionsProvider(new SignatureOptionsProvider());
        XadesSigner signer = p.newSigner();

        // open file
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        DocumentBuilder builder = null;
        builder = factory.newDocumentBuilder();
        Document doc1 = builder.parse(new File(options.valueOf("input").toString()));
        Element elemToSign = doc1.getDocumentElement();

        // sign whole document
        new Enveloped(signer).sign(elemToSign);

        // save output file
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        Result output = new StreamResult(new File(options.valueOf("output").toString()));
        Source input = new DOMSource(doc1);
        transformer.transform(input, output);

    } catch (KeyStoreException | ParserConfigurationException | SAXException | IOException | XAdES4jException
            | TransformerException e) {

        e.printStackTrace();
    }
}
这是它创建的一个示例签名:(具有 在base64值的每行末尾?)

如果有人能告诉我问题所在,我将不胜感激。谢谢

更新 检查堆栈跟踪后,我发现以下异常:

    xades4j.xml.unmarshalling.UnmarshalException: Bad XML signature
    at xades4j.verification.XadesVerifierImpl.verify(XadesVerifierImpl.java:130)
    at com.qprotex.Main.verifyXML(Main.java:190)
    at com.qprotex.Main.<init>(Main.java:99)
    at com.qprotex.Main.main(Main.java:81)
Caused by: org.apache.xml.security.exceptions.XMLSecurityException: Cannot create a null:null from a http://www.w3.org/2000/09/xmldsig#:Signature element
java.lang.NullPointerException
at xades4j.xml.unmarshalling.FromXmlSignaturePolicyConverter.getLocationUrl(FromXmlSignaturePolicyConverter.java:71)
at xades4j.xml.unmarshalling.FromXmlSignaturePolicyConverter.convertFromObjectTree(FromXmlSignaturePolicyConverter.java:64)
at xades4j.xml.unmarshalling.FromXmlSignaturePolicyConverter.convertFromObjectTree(FromXmlSignaturePolicyConverter.java:1)
at xades4j.xml.unmarshalling.UnmarshallerModule.convertProperties(UnmarshallerModule.java:64)
at xades4j.xml.unmarshalling.DefaultQualifyingPropertiesUnmarshaller.unmarshalProperties(DefaultQualifyingPropertiesUnmarshaller.java:83)
at xades4j.verification.XadesVerifierImpl.verify(XadesVerifierImpl.java:175)
at com.qprotex.Main.verifyXML(Main.java:190)
at com.qprotex.Main.<init>(Main.java:99)
at com.qprotex.Main.main(Main.java:81)
但这不起作用,我得到了一个“xades4j.providers.CannotBuildCertificationPathException:信任锚密钥库没有受信任的证书条目”异常

            FileInputStream fis = new FileInputStream(options.valueOf("certificate").toString());
            KeyStore ks = KeyStore.getInstance("pkcs12");
            ks.load(fis, options.valueOf("password").toString().toCharArray());                         
            fis.close();
            CertificateValidationProvider provider = new PKIXCertificateValidationProvider(ks, false);
  • 您可能在库中发现了一个bug。我创建了一个跟踪这个。如果你想订阅的话
  • 如果它真的是一个bug,那么它一定是在v1.4.0中引入的,所以现在,您可以尝试使用v1.3.2
  • 既然你说你不需要签名身份识别器,为什么你要使用XAdES EPES?您可以使用
    xadesbessingprofile
    生成XAdES-BES签名
  • 假设您仍然需要XAdES EPE,请注意,您需要指定如何使用
    XadesVerificationProfile
    上的
    withPolicyDocumentProvider
    获取签名策略文档进行验证
  • 我不确定base64字符串后的编码字符,但让我们拭目以待,看看这是否是一个问题
更新2后:


例外信息似乎很清楚。您的目标是使用签名证书作为信任锚?密钥库上的条目类型需要是“信任锚”。我想您应该添加两个条目:一个带有cert/key(类型“certificate”),另一个只带有cert(类型“trust-anchor”)。或者使用单独的密钥库。

感谢您的帮助。我确实将我的签名函数改为使用XadesBesSigningProfile,现在它可以工作了,但我有一个小问题。请检查我的更新2。谢谢,你解决了吗?我也有类似的问题
java.lang.NullPointerException
at xades4j.xml.unmarshalling.FromXmlSignaturePolicyConverter.getLocationUrl(FromXmlSignaturePolicyConverter.java:71)
at xades4j.xml.unmarshalling.FromXmlSignaturePolicyConverter.convertFromObjectTree(FromXmlSignaturePolicyConverter.java:64)
at xades4j.xml.unmarshalling.FromXmlSignaturePolicyConverter.convertFromObjectTree(FromXmlSignaturePolicyConverter.java:1)
at xades4j.xml.unmarshalling.UnmarshallerModule.convertProperties(UnmarshallerModule.java:64)
at xades4j.xml.unmarshalling.DefaultQualifyingPropertiesUnmarshaller.unmarshalProperties(DefaultQualifyingPropertiesUnmarshaller.java:83)
at xades4j.verification.XadesVerifierImpl.verify(XadesVerifierImpl.java:175)
at com.qprotex.Main.verifyXML(Main.java:190)
at com.qprotex.Main.<init>(Main.java:99)
at com.qprotex.Main.main(Main.java:81)
            KeyStore trustAnchors = KeyStore.getInstance("Windows-ROOT"); 
            trustAnchors.load(null);

            CertificateValidationProvider provider = new PKIXCertificateValidationProvider(trustAnchors, false);
            FileInputStream fis = new FileInputStream(options.valueOf("certificate").toString());
            KeyStore ks = KeyStore.getInstance("pkcs12");
            ks.load(fis, options.valueOf("password").toString().toCharArray());                         
            fis.close();
            CertificateValidationProvider provider = new PKIXCertificateValidationProvider(ks, false);