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

Reply via email to