0

I'm having a problem generating a document with signed nodes. I have a bunch of signed XMLs, in text format. They signature is valid, I've tested it with xmlsec1. I have to load all the XMLs and put them in another XML document, for sending it to another service. So, first of all I create the container document ("sobre" is a local variable, a JAXB root element):

JAXBContext context = JAXBContext.newInstance("org.importe.test");
StringWriter writer = new StringWriter();
Marshaller marshaller = context.createMarshaller();
marshaller.marshal(sobre, writer);
String xml = writer.toString();
Document doc = loadXMLFromString(xml);

and then I add the XMLs to the container:

for (String cfexml : cfexmls) {
  Document cfe = loadXMLFromString(cfexml);
  Node newNode = doc.importNode(cfe.getDocumentElement(), true);
  doc.getElementsByTagName("EnvioCFE").item(0).appendChild(newNode);
}

finally I get the xml from the container document:

TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
StringWriter outputWriter = new StringWriter();
trans.transform(new DOMSource(doc), new StreamResult(outputWriter));
String signedxml = outputWriter.toString();

The point is that I'm getting the child node modified, without namespaces, and so the signature validation of the extract node fails. Here is an excerpt of the XML that I've to add as a child node:

<?xml version="1.0" encoding="UTF-8"?>
<CFE xmlns="http://org.importe.test" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns:ns3="http://www.w3.org/2001/04/xmlenc#" version="1.0">
  <data>
    [...]
  </data>
  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    [...]
  </Signature>
</CFE>

but when the node is imported in the container document it get modified (actually I've noticed that it loose namespace declarations):

<?xml version="1.0" encoding="UTF-8"?>
<EnvioCFE xmlns="http://org.importe.test" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" xmlns:ns3="http://www.w3.org/2001/04/xmlenc#" version="1.0">
  <Header version="1.0">
  </Header>
  <CFE version="1.0">
    <data>
      [...]
    </data>
    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
      [...]
    </Signature>
  </CFE>
</EnvioCFE>

How can I add a node to the container keeping the namespace declaration? More generally can I add it being sure it's added "as is", without any modifications? (I'm using glassfish 4 and Java 7)

Thank you

EDIT:

This is the code of loadXMLFromString:

public Document loadXMLFromString(String xml) throws ParserConfigurationException, SAXException, IOException {
  DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  factory.setNamespaceAware(true);
  DocumentBuilder builder = factory.newDocumentBuilder();
  return builder.parse(new InputSource(new StringReader(xml)));
}
moretti.fabio
  • 1,128
  • 13
  • 32
  • 1
    Can you show the code of `loadXMLFromString`? I suspect the problem is in there. In particular if you're using DocumentBuilderFactory then that is _not namespace aware_ by default, you need to call a setter to turn namespaces on before you create a DocumentBuilder. – Ian Roberts Jul 18 '14 at 21:06
  • of course, see my edit (as you can see I'm using setNamespaceAware). – moretti.fabio Jul 18 '14 at 21:13
  • Hmm, I see what you mean now. The XML serializer is correct to omit those three namespace declarations from the CFE element because they're already in force on its parent. I don't know of any way to override that. I suppose you could try building your DOM trees with namespaces deliberately turned _off_ so that the namespace declarations are just treated as attributes. – Ian Roberts Jul 18 '14 at 21:59
  • Though if you do that you may have to switch to using DOMImplementationLS to do the serializing rather than using a Transformer, I'm not sure how well an XSLT tool will cope with non-namespace-aware DOMs. – Ian Roberts Jul 18 '14 at 22:01
  • @IanRoberts you say: "you could try building your DOM trees with namespaces deliberately turned off", how can I achieve that? – moretti.fabio Jul 18 '14 at 22:19
  • `setNamespaceAware(false)` on the DocumentBuilderFactory (or don't call the method at all but it makes the intention clearer if you do) – Ian Roberts Jul 19 '14 at 08:19
  • It doesn't help at all, result is the same. I didn't find a way to include a signed node in a DOM document, but I refuse to think that's not possible. – moretti.fabio Jul 21 '14 at 14:29

1 Answers1

0

Ok, I've done research and I've found the problem:

  • if I use xalan-2.7.1.jar, xercesImpl-2.9.1.jar, xml-apis-1.3.04.jar and xmlsec-1.5.6.jar for DOM and XML security implementation, it works as I expect: adding a node does not modify the contents, so the digital signature is valid;
  • if I use the standard java libraries not only adding a node change the node itself, but sometimes the digital signature doesn't pass the xmlsec1 check, I imagine for a problem in the transformation from DOM to String.

I hope this can help someone, anyway I don't know why it happens, I'm sure I'm not doing weird things, but I've no time now to going deeply.

Actually I'm stuck to find how tell glassfish to load the DOM implementation I want, or to set a priority: I've found no way to say "load xerces instead of standard lib".

moretti.fabio
  • 1,128
  • 13
  • 32