Hi all. I need to sign a SOAP message and I need to use JSR105. I've created a message with the following code and is signed without problems. However, I can't validate the signature. As you can see the elements that contains the nodes are OMElement (that are an instance of Node and Element classes). Please, could you tell where is the problem, or if you know a better solution to add a signature for SAML2 assertions with the pregenerated files from a XMLbeans binding.
The error I get is: Exception in thread "main" javax.xml.crypto.dsig.XMLSignatureException: javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID 1 at org.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java :366) at org.jcp.xml.dsig.internal.dom.DOMReference.validate(DOMReference.java :318) at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.validate( DOMXMLSignature.java:230) at SignedSoap.main(SignedSoap.java:272) Caused by: javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID 1 at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference( DOMURIDereferencer.java:84) at org.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java :358) ... 3 more Caused by: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID 1 at com.sun.org.apache.xml.internal.security.utils.resolver.implementations.ResolverFragment.engineResolve(Unknown Source) at com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver.resolve(Unknown Source) at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference( DOMURIDereferencer.java:77) ... 4 more javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID 1 at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference( DOMURIDereferencer.java:84) at org.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java :358) at org.jcp.xml.dsig.internal.dom.DOMReference.validate(DOMReference.java :318) at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.validate( DOMXMLSignature.java:230) at SignedSoap.main(SignedSoap.java:272) Caused by: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID 1 at com.sun.org.apache.xml.internal.security.utils.resolver.implementations.ResolverFragment.engineResolve(Unknown Source) at com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver.resolve(Unknown Source) at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference( DOMURIDereferencer.java:77) ... 4 more My code is as follows import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.Provider; import java.security.SecureRandom; import java.util.Calendar; import java.util.Collections; import javax.xml.crypto.dsig.*; import javax.xml.crypto.dom.*; import javax.xml.crypto.dsig.dom.*; import javax.xml.crypto.dsig.keyinfo.*; import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec; import javax.xml.soap.*; import javax.xml.parsers.*; import javax.xml.transform.*; import javax.xml.transform.dom.*; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.*; import org.apache.axiom.om.OMAttribute; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.OMNamespace; import org.apache.axiom.om.impl.dom.factory.OMDOMFactory; import org.apache.xmlbeans.impl.piccolo.xml.XMLStreamReader; import org.w3c.dom.*; import org.w3c.dom.Node; import org.xml.sax.InputSource; //import org.xmlsoap.schemas.soap.encoding.DateTime; /** * Construct a SOAP message, sign it and then validate the signature. * This implementation follows the * <a ref="http://www.w3.org/TR/SOAP-dsig/"> * W3C Note on digital signatures in SOAP messages * </a>. * The validating key is included in the signature. * DOM Level 2 is used throughout. * * The following SOAP message is signed: * <pre><code> * * <?xml version="1.0" encoding="UTF-8"?> * <soap-env:Envelope * xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"> * <soap-env:Header> * <SOAP-SEC:Signature * mustUnderstand="1" * xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12"/> * </soap-env:Header> * <soap-env:Body id="Body"> * <m:GetLastTradePrice xmlns:m="http://wombats.ztrade.com"> * <symbol>SUNW</symbol> * </m:GetLastTradePrice> * </soap-env:Body> * </soap-env:Envelope> * * </code></pre> */ public class SignedSoap { private static boolean debug = false; public static void main(String[] args) throws Exception { int argc = args.length; if (argc == 1) { if (args[0].equalsIgnoreCase("-help")) { System.out.println("Usage: SignedSoap [-debug]"); System.out.println(" -debug\tactivates debug messages"); return; } debug = args[0].equalsIgnoreCase("-debug"); } // Create the SOAP message OMDOMFactory omfact=new OMDOMFactory(); //Node nodo1=fd.newDomNode(options); OMNamespace namespace=omfact.createOMNamespace(" http://schemas.xmlsoap.org/soap/security/2000-12", "soapenv"); OMNamespace namespace2=omfact.createOMNamespace(" http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "wsu"); OMAttribute attr=omfact.createOMAttribute("mustUnderstand",namespace,"1"); OMAttribute id=omfact.createOMAttribute("id",namespace,"1"); OMAttribute id2=omfact.createOMAttribute("id",namespace,"2"); OMElement sec=omfact.createOMElement("Security", " http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd ","wsse"); OMElement timestamp=omfact.createOMElement("Timestamp",namespace2); OMElement created=omfact.createOMElement("Created",namespace2); OMElement expires=omfact.createOMElement("Expires",namespace2); created.setText("12122007"); expires.setText("12122008"); timestamp.addAttribute(id); timestamp.addChild(created); timestamp.addChild(expires); sec.addChild(timestamp); System.out.println("Generating the DOM tree..."); // Get input source org.w3c.dom.Node security = (Node)sec; //if (debug) { // dumpDOMDocument(root); //} // Generate a DSA key pair System.out.println("Generating the DSA keypair..."); KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA"); kpg.initialize(1024, new SecureRandom("not so random".getBytes())); KeyPair keypair = kpg.generateKeyPair(); // Assemble the signature parts System.out.println("Preparing the signature..."); String providerName = System.getProperty ("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI"); XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(providerName).newInstance()); Reference ref = sigFactory.newReference("#1", sigFactory.newDigestMethod(DigestMethod.SHA1, null)); SignedInfo signedInfo = sigFactory.newSignedInfo( sigFactory.newCanonicalizationMethod( CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, (C14NMethodParameterSpec) null), sigFactory.newSignatureMethod(SignatureMethod.DSA_SHA1, null), Collections.singletonList(ref)); KeyInfoFactory kif = sigFactory.getKeyInfoFactory(); KeyValue kv = kif.newKeyValue(keypair.getPublic()); KeyInfo keyInfo = kif.newKeyInfo(Collections.singletonList(kv)); XMLSignature sig = sigFactory.newXMLSignature(signedInfo, keyInfo); // Insert XML signature into DOM tree and sign System.out.println("Signing the SOAP message..."); // Find where to insert signature Element ts = getFirstChildElement(envelope); DOMSignContext sigContext = new DOMSignContext(keypair.getPrivate(), sec); // Need to distinguish the Signature element in DSIG (from that in SOAP) sigContext.putNamespacePrefix(XMLSignature.XMLNS, "ds"); // register Body ID attribute getNextSiblingElement( sigContext.setIdAttributeNS (ts, "http://schemas.xmlsoap.org/soap/security/2000-12","id"); sig.sign(sigContext); if (debug) { dumpDOMDocument(envelope); } // Validate the XML signature // Locate the signature element Element sigElement = getNextSiblingElement(ts); // Validate the signature using the public key generated above DOMValidateContext valContext = new DOMValidateContext(keypair.getPublic(), sigElement); // register Body ID attribute getNextSiblingElement( valContext.setIdAttributeNS (ts, "http://schemas.xmlsoap.org/soap/security/2000-12","id"); boolean isValid = sig.validate(valContext); System.out.println("Validating the signature... " + (isValid ? "valid" : "invalid")); } /* * Outputs DOM representation to the standard output stream. * * @param root The DOM representation to be outputted */ private static void dumpDOMDocument(org.w3c.dom.Node root) throws TransformerException, TransformerConfigurationException { System.out.println("\n"); // Create a new transformer object Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); // Dump the DOM representation to standard output transformer.transform(new DOMSource(root), new StreamResult(System.out)); System.out.println("\n"); } /** * Returns the first child element of the specified node, or null if there * is no such element. * * @param node the node * @return the first child element of the specified node, or null if there * is no such element * @throws NullPointerException if <code>node == null</code> */ private static Element getFirstChildElement(org.w3c.dom.Node node) { org.w3c.dom.Node child = node.getFirstChild(); while (child != null && child.getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) { child = child.getNextSibling(); } return (Element) child; } /** * Returns the next sibling element of the specified node, or null if there * is no such element. * * @param node the node * @return the next sibling element of the specified node, or null if there * is no such element * @throws NullPointerException if <code>node == null</code> */ public static Element getNextSiblingElement(org.w3c.dom.Node node) { org.w3c.dom.Node sibling = node.getNextSibling(); while (sibling != null && sibling.getNodeType() != org.w3c.dom.Node.ELEMENT_NODE) { sibling = sibling.getNextSibling(); } return (Element) sibling; } } Thanks in advance
