You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@santuario.apache.org by Frank Cornelis <fc...@telenet.be> on 2006/02/03 13:11:56 UTC
XML signature breaks
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!
}
}
Re: XML signature breaks
Posted by Sean Mullan <Se...@Sun.COM>.
Frank Cornelis wrote:
> 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?
Yes.
You have to explicitly add a namespace attribute to the element that
first defines the namespace:
Element rootElement = testDocument.createElementNS("urn:namespace",
"tns:document");
// add this line
rootElement.setAttributeNS(Constants.NamespaceSpecNS, "xmlns:tns
", "urn:namespace");
This did not appear as a namespace attribute until you serialized to a
String and converted back to DOM. Hence the signature validation
failure. (I don't know all the exact details as to why it has this
behavior but maybe someone else on this list does). In any case the
above fix should work.
--Sean
>
> 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!
> }
> }
>
>
>
>
>