Tsv*_*kov 8 java xml cxf xml-signature
我有以下工作流程:
\n\n下面是签名创建方法:
\n\npublic static String createXMLDSign(String xmlString) throws Exception{\n // Create a DOM XMLSignatureFactory that will be used to\n // generate the enveloped signature.\n String providerName = System.getProperty("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI");\n XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(providerName).newInstance());\n\n // Load the KeyStore and get the signing key and certificate.\n KeyStore ks = KeyStore.getInstance("JKS");\n ks.load(new FileInputStream("src/main/resources/jks/client-keystore.jks"), keyStorePass .toCharArray());\n KeyStore.PrivateKeyEntry keyEntry =\n (KeyStore.PrivateKeyEntry) ks.getEntry\n ("client-keypair", new KeyStore.PasswordProtection(keyPass .toCharArray()));\n X509Certificate cert = (X509Certificate) keyEntry.getCertificate();\n\n // Create the KeyInfo containing the X509Data.\n KeyInfoFactory kif = fac.getKeyInfoFactory();\n List x509Content = new ArrayList();\n x509Content.add(cert.getSubjectX500Principal().getName());\n x509Content.add(cert);\n X509Data xd = kif.newX509Data(x509Content);\n KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));\n\n // Instantiate the document to be signed.\n DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();\n dbf.setNamespaceAware(true);\n Document doc = dbf.newDocumentBuilder().parse\n (new InputSource(new StringReader(xmlString)));\n\n\n // Get element which will be signed\n Element child =(Element)doc.getElementsByTagName("ns2:Eid").item(0);\n child.setAttribute("Id", "1234");\n child.setIdAttribute("Id", true); \n String id = child.getAttributes().getNamedItem("Id").getNodeValue();\n String uri = String.format("#%s", id);\n\n List<Transform> transformList = new LinkedList<>();\n transformList.add(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null));\n Reference reference = fac.newReference(uri,\n fac.newDigestMethod(DigestMethod.SHA256, null), transformList, null, null);\n\n SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(\n CanonicalizationMethod.EXCLUSIVE, (C14NMethodParameterSpec) null), fac\n .newSignatureMethod("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", null), Collections.singletonList(reference));\n\n // Remove element from the Node\n Node node = doc.getElementsByTagName("ns2:Eis").item(0);\n Node eumNode = doc.getElementsByTagName("ns2:EumSignature").item(0);\n node.removeChild(eumNode);\n\n // Create a DOMSignContext and specify the RSA PrivateKey and\n // location of the resulting XMLSignature\'s parent element.\n DOMSignContext dsc = new DOMSignContext\n (keyEntry.getPrivateKey(), /*doc.getDocumentElement()*/node);\n dsc.setDefaultNamespacePrefix("ds");\n\n // Create the XMLSignature, but don\'t sign it yet.\n XMLSignature signature = fac.newXMLSignature(si, ki);\n\n // Marshal, generate, and sign the enveloped signature.\n signature.sign(dsc);\n\n /////////////Signature verification\n // Find Signature element.\n signVerification(fac, doc, signature);\n\n // Convert DocToString and verify\n String stringDoc = Utils.docToString(doc);\n // Instantiate the document to be signed.\n DocumentBuilderFactory dbf2 = DocumentBuilderFactory.newInstance();\n dbf2.setNamespaceAware(true);\n Document doc2 = dbf2.newDocumentBuilder().parse\n (new InputSource(new StringReader(stringDoc)));\n signVerification(fac, doc2, signature);\n\n /////////////////////////\n return Utils.docToString(doc);\n\n}\nRun Code Online (Sandbox Code Playgroud)\n\n注意:我在要签名的元素中手动添加 \xe2\x80\x9cId\xe2\x80\x9d 属性,因为它在原始 XML 中不存在。
\n\n以下是用于 docToString 转换的方法:
\n\npublic static String docToString(Document doc) {\n try {\n DOMSource domSource = new DOMSource(doc);\n StringWriter writer = new StringWriter();\n StreamResult result = new StreamResult(writer);\n TransformerFactory tf = TransformerFactory.newInstance();\n Transformer transformer = tf.newTransformer();\n transformer.transform(domSource, result);\n return writer.toString();\n } catch (TransformerException ex) {\n ex.printStackTrace();\n return null;\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n执行结果第一次验证成功通过,但转换后的第二次验证失败并出现错误:
\n\n\n\n\njavax.xml.crypto.dsig.XMLSignatureException:javax.xml.crypto.URIReferenceException:com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException:无法解析 org.jcp 处 ID 为 1234\n 的元素.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java:431)\n 在 org.jcp.xml.dsig.internal.dom.DOMReference.validate(DOMReference.java:393)\n 在 org.jcp .xml.dsig.internal.dom.DOMXMLSignature.validate(DOMXMLSignature.java:278)\n 位于 com.innonetworks.utils.XmlSignatureHelper.signVerification(XmlSignatureHelper.java:185)\n 位于 com.innonetworks.utils.XmlSignatureHelper.createXMLDSign (XmlSignatureHelper.java:160)\n 在 com.innonetworks.interceptor.XMLDSignInterceptor.changeOutboundMessage(XMLDSignInterceptor.java:36)\n 在 com.innonetworks.interceptor.MessageChangeInterceptor.handleMessage(MessageChangeInterceptor.java:56)\n 在 org. apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)\n 在 com.innonetworks.interceptor.MessageChangeInterceptor.handleMessage(MessageChangeInterceptor.java:41)\n 在 org.apache.cxf.phase.PhaseInterceptorChain.doIntercept( PhaseInterceptorChain.java:308)\n 在 org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:531)\n 在 org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:440)\n在 org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:355)\n 在 org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:313)\n 在 org.apache.cxf.frontend .ClientProxy.invokeSync(ClientProxy.java:96)\n 位于 org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:140)\n 位于 com.sun.proxy.$Proxy55.es1RegisterEIS(未知来源)\ n 在 com.innonetworks.es1.client.SoapClientApp.callSoapClient(SoapClientApp.java:178)\n 在 com.innonetworks.es1.client.SoapClientApp.main(SoapClientApp.java:63)\n 引起:javax.xml。 crypto.URIReferenceException:com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException:无法解析 org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(DOMURIDereferencer 处 ID 为 1234\n 的元素.java:134)\n 在 org.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java:425)\n ... 18 更多
\n
注意如果我将参考参数“uri”替换为“”,则两个验证均成功通过
\n\n解决方案\n我解决了问题,并希望分享是否可以帮助其他人。我在Oracle页面JDK-8017265中找到的解决方案:XMLSignature Cannot Resolve ID
\n\n我使用了第二种解决方法 - 在验证签名之前使用 DOMValidateContext.setIdAttributeNS 方法注册 ID 元素
\n\n这是代码:
\n\nDOMValidateContext valContext = new DOMValidateContext\n (new X509KeySelector(), nl.item(0));\n final NodeList elements = docNew.getElementsByTagName("ns2:EumSignedInfo");\n if (elements.getLength() > 0) {\n valContext.setIdAttributeNS((Element) elements.item(0), null, "Id");\n }\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
4509 次 |
| 最近记录: |