最近同银行做接口联调,需要对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文件:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <SoEv>
  3. <Message id="54b8db6c24574e23423********">
  4. <FIQReq id="FIQReq">
  5. <version>1.0.1</version>
  6. <instId>9550811********</instId>
  7. <certId>0001</certId>
  8. <channelDate>20150608</channelDate>
  9. <beginPos>0</beginPos>
  10. <pageNum>10</pageNum>
  11. </FIQReq>
  12. </Message>
  13. </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); }
  19. //签名
  20. signature.sign(dsc);
  21. }catch(Exception e){
  22. System.out.println(e.getMessage());
  23. throw new RuntimeException(e);
  24. }
  25. }

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

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

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

  1. There are 3 potential workarounds that you can apply:
  2.  
  3. 1. Use a validating schema which will register the elements with ID references.
  4.  
  5. 2. Register the ID elements with the DOMValidateContext.setIdAttributeNS method before validating the signature
  6.  
  7. 3. Implement a custom URIDereferencer which can find these references and override the builtin URIDereferencer with the DOMValidateContext.setURIDereferencer method.

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

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

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

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

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

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

  1. /**
  2. * XML签名
  3. * <p>签名使用内嵌方式,生成在指定节点</p>
  4. * @param doc XML文档
  5. * @param privateKey 私钥
  6. * @param referenceId 需签名的元素标识
  7. * @param signNode 生成签名的节点
  8. */
  9. public void sign(Document doc, PrivateKey privateKey, String referenceId, Node signNode) {
  10. if(!isInit){
  11. throw new RuntimeException("XMLSigner is not init !");
  12. }
  13. try{
  14. //创建 <Reference> 元素,引用指定ID的节点,<Signature> 元素不会被计算在内
  15. Reference refToRootDoc = signFactory.newReference("#"+referenceId,
  16. sha1DigMethod, Collections.singletonList(envelopedTransform), null, null);
  17. //创建 <SignedInfo> 元素
  18. SignedInfo signedInfo = signFactory.newSignedInfo(c14nWithCommentMethod,
  19. rsa_sha1SigMethod, Collections.singletonList(refToRootDoc));
  20. //创建签名实例
  21. XMLSignature signature = signFactory.newXMLSignature(signedInfo, null);
  22. //创建签名上下文,在指定节点生成
  23. DOMSignContext dsc = new DOMSignContext(privateKey, signNode);
  24. //设置签名域命名空间前缀
  25. if (defaultNamespacePrefix != null) {
  26. dsc.setDefaultNamespacePrefix(defaultNamespacePrefix);
  27. Element element = (Element)doc.getElementsByTagName(referenceId).item(0);
  28. dsc.setIdAttributeNS(element, null, "id");
  29. }
  30. //签名
  31. signature.sign(dsc);
  32. }catch(Exception e){
  33. System.out.println(e.getMessage());
  34. throw new RuntimeException(e);
  35. }
  36. }

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

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

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

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

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

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

    用DOM解析XML时出现了如下错误: [Fatal Error] :3:13: Open quote is expected for attribute "{1}" associa ...

  2. 【Java密码学】XML签名

    http://www.oracle.com/technetwork/articles/javase/dig-signature-api-140772.html XML签名的结构和类型 基本上XML签名 ...

  3. XML签名

    英文:https://www.javacodegeeks.com/2013/10/xml-security-with-digital-signature-in-java.html 中文:http:// ...

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

    mybatis mapper xml文件配置resultmap时,id行和result行有什么区别? <resultMap id = "CashInvoiceMap" typ ...

  5. org.apache.shiro.session.UnknownSessionException: There is no session with id [xxxx]的解决方案

    org.apache.shiro.session.UnknownSessionException: There is no session with id [xxxx]的解决方案 背景描述 Sprin ...

  6. Error parsing XML: junk after document element这样的错误 - CSDN博客

    很多开发者可能在编写XML布局文件时提示Error parsing XML: junk after document element这样的错误,这里Android123提示大家一般合法的XML文件只有 ...

  7. 【RF库XML测试】Get Element

    Name:Get ElementSource:XML <test library>Arguments:[ source | xpath=. ]Returns an element in t ...

  8. xml DTD中的ELEMENT和ATTLIST

    是W3C的一个文档类型定义规则文件,是用来让浏览器根据你定义的DTD(文档类型定义)来解释页面代码的. doctype声明指出阅读程序应该用什么规则集来解释文档中的标记.在Web文档的情况下,“阅读程 ...

  9. javax.servlet.ServletException: Could not resolve view with name‘ XXXX’in servlet with name 'spring'的解决方案-----SKY

    出现的异常如下: javax.servlet.ServletException: Could not resolve view with name '{"msg":"成功 ...

随机推荐

  1. ES6的新特性(10)——Class 的基本语法

    Class 的基本语法 简介 JavaScript 语言中,生成实例对象的传统方法是通过构造函数.下面是一个例子. function Point(x, y) { this.x = x; this.y ...

  2. win2008 r2 开启TLS1.2

    Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityPr ...

  3. PSP Daily软件Alpha版本——基于NABCD评论,及改进建议

    1.根据(不限于)NABCD评论作品的选题: 此软件的用户人群较为明确,即:用户(软件工程课上学生)记录例行报告.写每周PSP表格和统计的需求.潜在用户还有未来该课堂的学生和需要用PSP方法记录任务完 ...

  4. 关于cnblog.com的用户体验

    首先我自己目前是一个学生党,每天在博客园上就上发布一些自己做的东西以及老师布置的作业,还能在上面学习很多别人的一些好的列子,我就希望博客园能够很好地为我们这些学生服务,当我们用它时能够很好地达到我们的 ...

  5. java调试器

    javac.exe是编译.java文件 java.exe是执行编译好的.class文件 javadoc.exe是生成Java说明文档 jdb.exe是Java调试器 javaprof.exe是剖析工具 ...

  6. Traffic Steering for Service Function Chaining

    Introduction 目前通过vlan标签来把流量引向对应的sfc 以前的sfc静态(SFs相邻组成SFC),有了sdn之后具有动态性.(SFs不需要彼此相邻.将流量动态地导向所需的SFs.) 流 ...

  7. J2EE Oa项目上传服务器出现的乱码解决过程

    (= =)搞了许久觉得有必要记下来.. 由于我本地的mysql都设置好了,但是服务器的又不能去改它 毕竟还有其他人要用- -: 所以只能是我建的时候去设置一下了, 首先先建数据库 ,表;; creat ...

  8. DELL服务器PXE前期处理

    thaks:https://www.cnblogs.com/520ZXL/ PXE批量推系统,服务器要具备条件:raid处理好,设置为pxe启动,与PXE服务器网络要通 先进入磁盘阵列(ctrl+R) ...

  9. QTemporaryDir及QTemporaryFile建立临时目录及文件夹

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QTemporaryDir及QTemporaryFile建立临时目录及文件夹     本文地址 ...

  10. php中扩展pecl与pear

    要为大家分享的内容是PECL 和 PEAR 他们之间的不同和相同之处. PEAR 是“PHP Extension and Application Repository”的缩写,即PHP扩展和应用仓库. ...