XML签名在向文档显式添加元素时未验证(JAVA)?

XML签名在向文档显式添加元素时未验证(JAVA)?,java,xml,jaxb,document,xml-signature,Java,Xml,Jaxb,Document,Xml Signature,我正在使用第三方提供的给定XSD的JAXB创建以下XML文档。第三方请求对文档进行签名,并在文档中添加一个额外的元素来保存签名。使用JDK1.7 下面是编组的代码示例: JAXBContext jaxbContext = JAXBContext.newInstance(DataPDU.class); DataPDU myDataPDU = new DataPDU(); myDataPDU.setRevision("2.0.6"); // marshall the file Marshaller

我正在使用第三方提供的给定XSD的JAXB创建以下XML文档。第三方请求对文档进行签名,并在文档中添加一个额外的元素来保存签名。使用JDK1.7

下面是编组的代码示例:

JAXBContext jaxbContext = JAXBContext.newInstance(DataPDU.class);
DataPDU myDataPDU = new DataPDU();
myDataPDU.setRevision("2.0.6");

// marshall the file
Marshaller marshaller = jaxbContext.createMarshaller();

DOMResult domResult = new DOMResult();
marshaller.marshal(myDataPDU, domResult);

// get the document list
Document document = (Document) domResult.getNode();
然后,我创建如下元素(LAU),并使用
HMAC-SHA256
算法和JSR105 JAVA API对文档进行签名(为了减少冗长,我不打算包含整个签名代码,而是使用
XMLSignature
类的标准行为,然后使用XML转换器将文档从DOMSource转换为文件输出流):

XML签名正确,但验证时,计算的摘要值与摘要值不同

我注意到,在创建LAU元素时更改名称空间值时,摘要从未更改,就好像文档正在签名,而忽略了LAU元素的名称空间,我想这就是它失败的原因。文档整体上的任何其他更改,或LAU元素前缀的更改都会直接影响cts有效负载的计算摘要

如果我直接将签名附加到根元素,而不是创建LAU元素,那么验证工作正常

LAU元素存在于XSD中,可以使用JAXB创建,但问题是我找不到一种方法来分配与根元素具有相同名称空间的前缀(仅在文档中为其分配前缀)

问题:

有效负载摘要中是否实际省略了名称空间 使用
createElements
appendChild
将元素添加到文档时的计算

有没有办法通过JAXB为同一根提供前缀 名称空间是否仅限于单个元素

如何找到由API签名的实际XML字符串,我在启用
javax.XML.crypto.dsig.cacheReference
后尝试读取引用输入流,但签名时不起作用,仅在验证时起作用

下面是XML的一个示例:

<DataPDU xmlns="urn:swift:saa:xsd:saa.2.0">
  <Revision>2.0.6</Revision>
  <Saa:LAU xmlns:Saa="urn:swift:saa:xsd:saa.2.0"> Signature lies here </Saa:LAU>
</DataPDU>

2.0.6
签名在这里
更新-完整的XML签名过程
JAXBContext-JAXBContext=JAXBContext.newInstance(DataPDU.class);
DataPDU myDataPDU=新DataPDU();
myDataPDU.setRevision(“2.0.6”);
//整理档案
Marshaller=jaxbContext.createMarshaller();
DOMResult DOMResult=新的DOMResult();
marshaller.marshall(myDataPDU,domResult);
//获取文档列表
Document Document=(Document)domResult.getNode();
//签署过程
XMLSignatureFactory=XMLSignatureFactory.getInstance(“DOM”);
SignatureMethod SignatureMethod=
factory.newSignatureMethod(“http://www.w3.org/2001/04/xmldsig-more#hmac-sha256“,空);
规范化方法规范化方法=
newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE,(XMLStructure)null);
列表转换=新建ArrayList();
add(factory.newTransform(Transform.ENVELOPED,(XMLStructure)null));
transforms.add(factory.newTransform(“http://www.w3.org/2001/10/xml-exc-c14n#“,(XMLStructure)null”);
DigestMethod=factory.newDigestMethod(“http://www.w3.org/2001/04/xmlenc#sha256“,空);
Reference=factory.newReference(“”,digestMethod,transforms,null,null);
签名信息签名信息=
newSignedInfo(规范化方法,signatureMethod,Collections.singletonList(参考));
String secretKey=“Abcd1234abcd1234Abcd1234abcd1234”;
SecretKeySpec secret_key=新的SecretKeySpec(secretKey.getBytes(),“HmacSHA256”);
Element laulement=document.createElements(“urn:swift:saa:xsd:saa.2.0”、“saa:LAU”);
Element rootElement=document.getDocumentElement();
appendChild(lauement);
DOMSignContext DOMSignContext=新的DOMSignContext(secret_key,laulement);
domSignContext.setDefaultNamespacePrefix(“ds”);
XMLSignature signature=factory.newXMLSignature(signedInfo,null);
signature.sign(domSignContext);
如何找到由API签名的实际XML字符串,我在启用javax.XML.crypto.dsig.cacheReference后尝试读取引用输入流,但这在签名时不起作用,仅在验证时起作用

幸运的是,假设使用了默认实现,它提供了一些调试功能。下面是一个使用
FINE
粒度登录控制台的设置示例,尽管
FINE
似乎已经足够了

handlers= java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level = FINER
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
org.jcp.xml.dsig.internal.level = FINER
com.sun.org.apache.xml.internal.security.level = FINER
您可以将其保存为一个
logging.properties
文件,并通过命令行选项
-Djava.util.logging.config.file
提供其路径,不过也可以通过编程方式完成

这样做实际上会显示正在签名的规范化XML,这回答了以下问题:

在使用createElementNS和appendChild将元素添加到文档时,有效负载摘要计算中是否实际忽略了名称空间

确实是这样。运行我在日志中看到的代码,作为签名的规范化XML

<DataPDU xmlns="urn:swift:saa:xsd:saa.2.0"><Revision>2.0.6</Revision><Saa:LAU></Saa:LAU></DataPDU>
我认为DOMResult可能使用了一个未设置为名称空间感知的文档生成器,但我尝试了这一点,没有任何区别:

DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder docBuilder = domFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
DOMResult domResult = new DOMResult(doc);
marshaller.marshal(myDataPDU, domResult);
这可能是DOMResult本身的一个缺陷。解决方法有点混乱,但它确实起到了作用。这实际上改变了摘要。我尝试了这一点,提供了
lauement
和文档根作为
DOMSignContext
的输入,这两种情况下都会产生相同的签名(摘要和签名值)尽管在后一种情况下,签名被添加到根,而不是元素

这还告诉我们,整个文档将用作签名的输入,即使您提供元素并使用独占规范化方法。它只更改签名的位置。URI解析将查找anc
 LAUElement.setAttribute("xmlns:Saa", "urn:swift:saa:xsd:saa.2.0");
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder docBuilder = domFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
DOMResult domResult = new DOMResult(doc);
marshaller.marshal(myDataPDU, domResult);
XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM");

NodeList sigList = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
if (sigList.getLength() == 0) {
    throw new Exception("Cannot find Signature element");
}
String secretKey = "Abcd1234abcd1234Abcd1234abcd1234";
SecretKeySpec secret_key = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
DOMValidateContext valContext = new DOMValidateContext(secret_key, sigList.item(0));
XMLSignature signature = factory.unmarshalXMLSignature(valContext);

System.out.println("Core validity: " + signature.validate(valContext));