XML签名Cannot resolve element with ID XXXX 解决方案

最近同银行做接口联调,需要对XML文件做加签和解签操作,本地的开发环境是Mac 10.10,JDK的版本是1.6.0.65。小小的一段加签代码,一直报错,却久久也找不到解决方法,网上的资料非常少,错误记录如下:

 1 javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID FIQReq
 2 Exception in thread "main" java.lang.RuntimeException: javax.xml.crypto.dsig.XMLSignatureException: javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID FIQReq
 3 at util.xml.XMLSigner.sign(XMLSigner.java:111)
 4 at test.TestSign.main(TestSign.java:34)
 5 Caused by: javax.xml.crypto.dsig.XMLSignatureException: javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID FIQReq
 6 at org.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java:412)
 7 at org.jcp.xml.dsig.internal.dom.DOMReference.digest(DOMReference.java:338)
 8 at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.digestReference(DOMXMLSignature.java:471)
 9 at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign(DOMXMLSignature.java:367)
10 at util.xml.XMLSigner.sign(XMLSigner.java:108)
11 ... 1 more
12 Caused by: javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID FIQReq
13 at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(DOMURIDereferencer.java:124)
14 at org.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java:404)
15 ... 5 more
16 Caused by: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID FIQReq
17 at com.sun.org.apache.xml.internal.security.utils.resolver.implementations.ResolverFragment.engineResolve(ResolverFragment.java:90)
18 at com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver.resolve(ResourceResolver.java:283)
19 at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(DOMURIDereferencer.java:117)
20 ... 6 more

唯一一个说的比较对的上的就是这篇Bug记录了:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8017171

产生该问题的原因就是无法根据XML文档节点的ID属性定位到对应的节点,所以在加签的时候会提示不能解析该ID,那么怎样才能让他可以根据我节点的ID,解析并定位到对应的节点呢,让我们先看下我项目中的代码:

首先是要进行加签的XML文件:

<?xml version="1.0" encoding="UTF-8"?>
<SoEv>
    <Message id="54b8db6c24574e23423********">
        <FIQReq id="FIQReq">
            <version>1.0.1</version>
            <instId>9550811********</instId>
            <certId>0001</certId>
            <channelDate>20150608</channelDate>
            <beginPos>0</beginPos>
            <pageNum>10</pageNum>
        </FIQReq>
    </Message>
</SoEv>

加签的代码:

 1 public void sign(Document doc, PrivateKey privateKey, String referenceId, Node signNode) {
 2         if(!isInit){
 3             throw new RuntimeException("XMLSigner is not init !");
 4         }
 5         try{
 6             //创建 <Reference> 元素,引用指定ID的节点,<Signature> 元素不会被计算在内
 7             Reference refToRootDoc = signFactory.newReference("#"+referenceId,
 8                     sha1DigMethod, Collections.singletonList(envelopedTransform), null, null);
 9             //创建 <SignedInfo> 元素
10             SignedInfo signedInfo = signFactory.newSignedInfo(c14nWithCommentMethod,
11                     rsa_sha1SigMethod, Collections.singletonList(refToRootDoc));
12             //创建签名实例
13             XMLSignature signature = signFactory.newXMLSignature(signedInfo, null);
14             //创建签名上下文,在指定节点生成
15             DOMSignContext dsc = new DOMSignContext(privateKey, signNode);
16             //设置签名域命名空间前缀
17             if (defaultNamespacePrefix != null) {
18                 dsc.setDefaultNamespacePrefix(defaultNamespacePrefix);21             }
22             //签名
23             signature.sign(dsc);
24         }catch(Exception e){
25             System.out.println(e.getMessage());
26             throw new RuntimeException(e);
27         }
28     }

方法外传入需要做加签处理的XML文档树,私钥,需要加签节点的ID,这里就是上面XML中的FIQReq节点的ID内容(FIQReq),还有一个节点就是加签所生成的SignedInfo的父元素,也就是要把SignedInfo节点写在那个节点下面。

这样执行这段代码就会报如上所示的错误代码。

在上面介绍的http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8017171中,有这样三条解决建议:

There are 3 potential workarounds that you can apply:

1. Use a validating schema which will register the elements with ID references.

2. Register the ID elements with the DOMValidateContext.setIdAttributeNS method before validating the signature

3. Implement a custom URIDereferencer which can find these references and override the builtin URIDereferencer with the DOMValidateContext.setURIDereferencer method.

但是看起来还不是特别直观不能一下子解决该问题。但是给出了解决问题的方向,而我解决该问题的着眼点就在于第二条:

2. Register the ID elements with the DOMValidateContext.setIdAttributeNS method before validating the signature

上面介绍的加签代码虽然没有DOMValidateContext对象的参与,但是有DOMSignContext,他也有setIdAttributeNS方法,所以我们就是要在这个方法上做文章:

在上面的加签代码上加入如下两条代码即可解决该问题:

Element element = (Element)doc.getElementsByTagName(referenceId).item(0);
dsc.setIdAttributeNS(element, null, "id");

加入这两行代码后的整体代码变为:

/**
     * XML签名
     * <p>签名使用内嵌方式,生成在指定节点</p>
     * @param doc XML文档
     * @param privateKey 私钥
     * @param referenceId 需签名的元素标识
     * @param signNode 生成签名的节点
     */
    public void sign(Document doc, PrivateKey privateKey, String referenceId, Node signNode) {
        if(!isInit){
            throw new RuntimeException("XMLSigner is not init !");
        }
        try{
            //创建 <Reference> 元素,引用指定ID的节点,<Signature> 元素不会被计算在内
            Reference refToRootDoc = signFactory.newReference("#"+referenceId,
                    sha1DigMethod, Collections.singletonList(envelopedTransform), null, null);
            //创建 <SignedInfo> 元素
            SignedInfo signedInfo = signFactory.newSignedInfo(c14nWithCommentMethod,
                    rsa_sha1SigMethod, Collections.singletonList(refToRootDoc));
            //创建签名实例
            XMLSignature signature = signFactory.newXMLSignature(signedInfo, null);
            //创建签名上下文,在指定节点生成
            DOMSignContext dsc = new DOMSignContext(privateKey, signNode);
            //设置签名域命名空间前缀
            if (defaultNamespacePrefix != null) {
                dsc.setDefaultNamespacePrefix(defaultNamespacePrefix);
                Element element = (Element)doc.getElementsByTagName(referenceId).item(0);
                dsc.setIdAttributeNS(element, null, "id");
            }
            //签名
            signature.sign(dsc);
        }catch(Exception e){
            System.out.println(e.getMessage());
            throw new RuntimeException(e);
        }
    }

再次运行程序后,问题解决。

具体的加签操作指导,详见如下文档:

http://www.apihome.cn/api/java/XMLSignatureFactory.html(中文)

http://docs.oracle.com/javase/6/docs/technotes/guides/security/xmldsig/XMLDigitalSignature.html(英文,但是介绍的更详细,直接拷贝出来即可)

时间: 2024-11-05 19:01:02

XML签名Cannot resolve element with ID XXXX 解决方案的相关文章

[Fatal Error] :3:13: Open quote is expected for attribute &quot;{1}&quot; associated with an element type &quot;id&quot;.

用DOM解析XML时出现了如下错误: [Fatal Error] :3:13: Open quote is expected for attribute "{1}" associated with an  element type  "id".org.xml.sax.SAXParseException: Open quote is expected for attribute "{1}" associated with an  element t

【Java密码学】XML签名

http://www.oracle.com/technetwork/articles/javase/dig-signature-api-140772.html XML签名的结构和类型 基本上XML签名有三种类型: 封内签名enveloped 封外签名enveloping 分离签名detached 封内签名:这种签名是将签名作为XML对象的子信息,也就是说是邮件中XML文件的子标签 <RootElement> <Signature> ... </Signature> &l

Error parsing XML: junk after document element

sax解析回传数据时,出现Error parsing XML: junk after document element 错误 <notify func="NewDevice" macaddress="00124B0004271B65" type="511" id="67"/> <notify func="NewDevice" macaddress="00124B0004271B6

android.content.res.Resources$NotFoundException: String resource ID XXXX

错误:android.content.res.Resources$NotFoundException: String resource ID XXXX 原因:一般发生在参数 int resId 错误,你把String赋值给int的resId,所以编译器找不到正确的resource于是报错. 最简单的例子,检查一下你的Toast.makeText()啊textView.setText啊之类的函数,这种函数通常有几个重载,如: textView.setText(CharSequence text);

websphere启动报/WEB-INF/applicationContext-orm- hibernate.xml]: Could not resolve placeholder &#39;hibernate.hbm2ddl.auto&#39; in string value &quot;${hibernate.hbm2ddl.auto}&quot;

启动websphere错误: [17-11-20 16:19:52:834 CST] 0000008e webapp I com.ibm.ws.webcontainer.webapp.WebApp log SRVE0292I: Servlet 消息 - [market_war#market.war]:.Initializing Spring root WebApplicati onContext [17-11-20 16:19:53:361 CST] 0000008e SystemOut O 2

Xcode真机调试出现The account &#39;***&#39; has no team with ID &#39;***&#39;的解决方案

前段时间,想用真机调试的时候出现 The account '***' has no team with ID '***'的问题, 以前页真机调试过,没有这种情况,于是我登陆开发者中心,进去发现说我的账号有问题: There may be a problem with your account. Please contact us. 于是我就查看了我的icloud邮件,大概在几天前有这么一封apple发送的邮件: Dear ***, You have revoked your certificat

struts2输入校验(附ActionName-validate.xml文件中正则表达式不起作用的解决方案),PS:有点问题希望知道的人指点下

PS:最后附上遇到的疑惑,希望知道的人指点下 前台页面(附代码): <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.or

[转]XML中元素(Element)与节点(Node)的区别

前言: element是特殊的node 一段纯文本即text-node也是node 但不是element w3c的原话是 A node can be an element node, an attribute node, a text node, or any other of the node types explained in the "Node types" chapter. 一.xmlnode类节点: xmlnode类表示xml文档中的单个节点,其命名空间为:System.X

mybatis mapper xml文件配置resultmap时,id行和result行有什么区别?

<resultMap id = "CashInvoiceMap" type="com.dfire.soa.invoice.bo.Invoice">    <id column="id" property="id" />    <result column="order_id" property="orderId" />    <result co