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!
}
}