Hi, My XML signature breaks when I convert the signed DOM to String and back again to DOM. I'm using jdk1.5.0_06 with -Xbootclasspath/p:xalan-2.7.0.jar:xercesImpl-2.7.1.jar:xml-apis-2.0.2.jar:serializer-2.7.0.jar The following JUnit test demonstrates the issue. Anyone any idea what I'm doing wrong here?
Thanks in advance, Frank package test.unit.signature; import java.io.StringReader; import java.io.StringWriter; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import junit.framework.TestCase; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.xml.security.Init; import org.apache.xml.security.algorithms.MessageDigestAlgorithm; import org.apache.xml.security.c14n.Canonicalizer; import org.apache.xml.security.signature.XMLSignature; import org.apache.xml.security.transforms.Transforms; import org.apache.xml.security.transforms.params.XPathContainer; import org.apache.xml.security.utils.Constants; import org.apache.xml.security.utils.XMLUtils; import org.apache.xpath.XPathAPI; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; public class SignatureTest extends TestCase { private static final Log LOG = LogFactory.getLog(SignatureTest.class); public void testSignature() throws Exception { // create a document DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory .newInstance(); documentBuilderFactory.setNamespaceAware(true); javax.xml.parsers.DocumentBuilder documentBuilder = documentBuilderFactory .newDocumentBuilder(); org.w3c.dom.Document testDocument = documentBuilder.newDocument(); Element rootElement = testDocument.createElementNS("urn:namespace", "tns:document"); /* * XXX: Doing 'tns:document' here makes the verification to fail. With * just 'document' it's OK, but then the namespace gets lost. */ testDocument.appendChild(rootElement); // generate keys KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); // init xml-security Init.init(); // create and add signature element XMLSignature signature = new XMLSignature(testDocument, null, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512, Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS); Element signatureElement = signature.getElement(); rootElement.appendChild(signatureElement); // add co-sign reference Transforms transforms = new Transforms(testDocument); XPathContainer xpath = new XPathContainer(testDocument); xpath.setXPathNamespaceContext("ds", Constants.SignatureSpecNS); xpath.setXPath("not(ancestor-or-self::ds:Signature)"); transforms.addTransform(Transforms.TRANSFORM_XPATH, xpath .getElementPlusReturns()); transforms.addTransform(Transforms.TRANSFORM_C14N_WITH_COMMENTS); signature.addDocument("", transforms, MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA512); // add public key signature.addKeyInfo(publicKey); // sign the document signature.sign(privateKey); // go from DOM to string Source source = new DOMSource(testDocument); StringWriter stringWriter = new StringWriter(); Result result = new StreamResult(stringWriter); Transformer xformer = TransformerFactory.newInstance().newTransformer(); xformer.transform(source, result); String strSignedDocument = stringWriter.getBuffer().toString(); LOG.debug("signed document: " + strSignedDocument); // go from string to DOM DocumentBuilderFactory domFactory = DocumentBuilderFactory .newInstance(); domFactory.setNamespaceAware(true); javax.xml.parsers.DocumentBuilder domBuilder = domFactory .newDocumentBuilder(); StringReader stringReader = new StringReader(strSignedDocument); InputSource inputSource = new InputSource(stringReader); org.w3c.dom.Document signedDocument = domBuilder.parse(inputSource); // verify original test document NodeList signatureElems = XPathAPI.selectNodeList(testDocument, "//ds:Signature", XMLUtils.createDSctx(testDocument, "ds", Constants.SignatureSpecNS)); signatureElement = (Element) signatureElems.item(0); XMLSignature signatureToVerify = new XMLSignature(signatureElement, null); boolean signOrigResult = signatureToVerify .checkSignatureValue(publicKey); assertTrue(signOrigResult); // verify from string loaded document signatureElems = XPathAPI.selectNodeList(signedDocument, "//ds:Signature", XMLUtils.createDSctx(signedDocument, "ds", Constants.SignatureSpecNS)); signatureElement = (Element) signatureElems.item(0); signatureToVerify = new XMLSignature(signatureElement, null); boolean signResultLoaded = signatureToVerify .checkSignatureValue(publicKey); assertTrue(signResultLoaded); // XXX: bang! } }