You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XAdES与XMLDsig签名验证问题排查及新异常咨询

XAdES与XMLDSig签名验证问题及解决方案

一、XAdES签名验证初始问题

验证代码

NodeList nl = doc.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", "Signature");

FileSystemDirectoryCertStore certStore = new
        FileSystemDirectoryCertStore("cert/store/");
KeyStore ks;
try (FileInputStream fis = new FileInputStream("cert/store/myStore")) {
    ks = KeyStore.getInstance("jks");
    ks.load(fis, "password".toCharArray());
} 
CertificateValidationProvider provider = new PKIXCertificateValidationProvider( ks, false,certStore.getStore() );

XadesVerificationProfile profile = new XadesVerificationProfile(provider);
org.w3c.dom.Element sigElem = (org.w3c.dom.Element) nl.item(0);
XAdESVerificationResult r = profile.newVerifier().verify(sigElem, null);

异常信息

xades4j.verification.ReferenceValueException: Reference '#xmldsig-xxxx-abc-object11' cannot be validated

对应XML签名片段(模拟数据)

<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="xmldsig-abc">
    <ds:SignedInfo>
        <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
        <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
        <ds:Reference Id="xmldsig-aee6fb07-8566-47eb-acb7-abc-ref0"
                      Type="http://www.w3.org/2000/09/xmldsig#Object"
                      URI="#xmldsig-xxx-abc-object11">
            <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
            <ds:DigestValue>XXXX</ds:DigestValue>
        </ds:Reference>
        <ds:Reference Type="http://uri.etsi.org/01903#SignedProperties"
                      URI="#xmldsig-xxx-abc-signedprops">
            <ds:Transforms>
                <ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
            <ds:DigestValue>XXXXX</ds:DigestValue>
        </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue Id="xmldsig-xxxx-sigvalue">XXXXX
    </ds:SignatureValue>
    <ds:KeyInfo>
        <ds:X509Data>
            <ds:X509Certificate>xXxxxxxx
            </ds:X509Certificate>
            <ds:X509IssuerSerial>
                <ds:X509IssuerName>xxxxx</ds:X509IssuerName>
                <ds:X509SerialNumber>xxxx</ds:X509SerialNumber>
            </ds:X509IssuerSerial>
            <ds:X509SubjectName>xxxxx
            </ds:X509SubjectName>
        </ds:X509Data>
    </ds:KeyInfo>
    <ds:Object Id="xmldsig-xxx-abc-object11">
        <ns2:Vehicle xmlns:ns2="xx:xx"
                            xmlns="xx:xx"> 
                            .................................
        </ns2:Vehicle>
    </ds:Object>
    <ds:Object>
        <xades:QualifyingProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#"
                                    xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#"
                                    Target="#xmldsig-xxx-abc">
            <xades:SignedProperties Id="xmldsig-xxx-abc-signedprops">
                <xades:SignedSignatureProperties>
                    <xades:SigningTime>xxxxxxx</xades:SigningTime>
                    <xades:SigningCertificate>
                        <xades:Cert>
                            <xades:CertDigest>
                                <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                                <ds:DigestValue>xxxxxxxxxx</ds:DigestValue>
                            </xades:CertDigest>
                            <xades:IssuerSerial>
                                <ds:X509IssuerName>xxxxxxxxxxx
                                </ds:X509IssuerName>
                                <ds:X509SerialNumber>xxxxxxxxxxx</ds:X509SerialNumber>
                            </xades:IssuerSerial>
                        </xades:Cert>
                        <xades:Cert>
                            <xades:CertDigest>
                                <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                                <ds:DigestValue>xxxxxxxxx</ds:DigestValue>
                            </xades:CertDigest>
                            <xades:IssuerSerial>
                                <ds:X509IssuerName>xxxxxxxxxx
                                </ds:X509IssuerName>
                                <ds:X509SerialNumber>xxxxxxxxxxxx</ds:X509SerialNumber>
                            </xades:IssuerSerial>
                        </xades:Cert>
                        <xades:Cert>
                            <xades:CertDigest>
                                <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                                <ds:DigestValue>xxxxxxxxx</ds:DigestValue>
                            </xades:CertDigest>
                            <xades:IssuerSerial>
                                <ds:X509IssuerName>xxxxxxxxxxxx
                                </ds:X509IssuerName>
                                <ds:X509SerialNumber>xxxxxxxxxxxx</ds:X509SerialNumber>
                            </xades:IssuerSerial>
                        </xades:Cert>
                    </xades:SigningCertificate>
                </xades:SignedSignatureProperties>
                <xades:SignedDataObjectProperties>
                    <xades:CommitmentTypeIndication>
                        <xades:CommitmentTypeId>
                            <xades:Identifier>http://uri.etsi.org/01903/v1.2.2#ProofOfOrigin</xades:Identifier>
                            <xades:Description>xxxxxxxxxxxxx
                            </xades:Description>
                        </xades:CommitmentTypeId>
                        <xades:AllSignedDataObjects/>
                    </xades:CommitmentTypeIndication>
                </xades:SignedDataObjectProperties>
            </xades:SignedProperties>
        </xades:QualifyingProperties>
    </ds:Object>
</ds:Signature>

疑问与解答

1. 验证方法是否正确?

整体框架是正确的:使用xades4j的XadesVerificationProfile结合PKIX证书验证提供者,符合XAdES规范的标准验证流程。但存在细节疏漏,比如证书链完整性(未使用根证书)和数据源可靠性(磁盘文件读取风险)。

2. 摘要值不匹配的原因?

  • 数据源问题:磁盘读取的XML文件可能在存储或读取过程中被修改(如编码变更、额外空格/换行插入),导致待验证内容与签名时的原始内容不一致,摘要计算结果不匹配。
  • 证书链不完整:未引入根证书,导致证书验证环节存在缺陷,间接影响签名验证流程的完整性。

二、XMLDSig验证新异常(XAdES问题已解决)

XAdES问题解决原因

  • 原从磁盘读取XML文件存在篡改或读取异常,改为直接验证API返回的字符串后修复。
  • 验证过程未使用根证书,添加根证书后完成XAdES验证。

新的XMLDSig验证代码

NodeList nl = doc.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", "Signature");
DOMValidateContext valContext = new DOMValidateContext(new KeyValueKeySelector(), nl.item(0));
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
XMLSignature signature = fac.unmarshalXMLSignature(valContext);
signature.validate(valContext);

异常信息

om.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID xmldsig-xxx-abc-signedprops

解决方案

该异常是因为默认XMLDSig解析器无法识别XAdES命名空间下的Id属性,导致无法解析引用的#xmldsig-xxx-abc-signedprops元素,可通过以下方式解决:

1. 注册XAdES命名空间的Id属性为ID类型

在创建DOMValidateContext后,显式将XAdES命名空间的Id属性注册为ID:

// 获取文档DOM实现并注册XAdES的Id属性
DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
DOMImplementationLS domImpl = (DOMImplementationLS) registry.getDOMImplementation("LS");
// 注册XAdES命名空间下的Id属性为ID
((org.w3c.dom.Document) doc).getDocumentElement()
    .setIdAttributeNS("http://uri.etsi.org/01903/v1.3.2#", "Id", true);

2. 使用自定义ResourceResolver

实现自定义解析器,处理XAdES元素的ID查找:

valContext.setResourceResolver(new ResourceResolver() {
    @Override
    public ResourceResolverResult resolve(ResourceResolverContext context) throws ResourceResolverException {
        String uri = context.getUri();
        if (uri.startsWith("#")) {
            String id = uri.substring(1);
            // 查找XAdES命名空间下的元素
            NodeList xadesNodes = doc.getElementsByTagNameNS("http://uri.etsi.org/01903/v1.3.2#", "*");
            for (int i = 0; i < xadesNodes.getLength(); i++) {
                Element elem = (Element) xadesNodes.item(i);
                if (id.equals(elem.getAttribute("Id"))) {
                    return new ResourceResolverResult(elem, context.getBaseUri(), null, null);
                }
            }
            // 查找所有命名空间的元素
            NodeList allNodes = doc.getElementsByTagName("*");
            for (int i = 0; i < allNodes.getLength(); i++) {
                Element elem = (Element) allNodes.item(i);
                if (id.equals(elem.getAttribute("Id")) || id.equals(elem.getAttributeNS(null, "Id"))) {
                    return new ResourceResolverResult(elem, context.getBaseUri(), null, null);
                }
            }
        }
        // 调用默认解析器处理其他情况
        return XMLSecurity.getDefaultResourceResolver().resolve(context);
    }
});

3. 确保XML解析时保留命名空间和ID属性

解析XML时开启命名空间支持:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.setValidating(false);
// 禁用DTD加载避免干扰
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(inputStream);

内容的提问来源于stack exchange,提问作者Kevin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 07:41:35