Hi Roedy, I've actually done this a lot: See below for an answer to
your questions. First though, allow me to post some code. (The
enveloped signature comments have since been fixed by the xmlsec
project).
public static boolean sign(Document doc, X509Certificate cert,
PrivateKey privateKey, boolean debug) throws WSSecurityException
{
try
{
//Add SecurityHelper.class header to the SOAP message if it does
not exist
String soap_header = "
http://schemas.xmlsoap.org/soap/envelope/";
org.apache.xml.security.Init.init();
/******************* XML SIGNATURE INIT ***********************
Append the signature element to proper location before signing
***************************************************************/
// Look for the SOAP header
Element headerElement = null;
NodeList nodes = doc.getElementsByTagNameNS (soap_header,
"Header");
//No nodes are expected to be found (length of zero) - add
//header here.
if(nodes.getLength() == 0)
{
headerElement = doc.createElementNS (soap_header, "Header");
nodes = doc.getElementsByTagNameNS (soap_header, "Envelope");
if(nodes != null)
{
Element envelopeElement = (Element)nodes.item(0);
headerElement.setPrefix(envelopeElement.getPrefix());
envelopeElement.appendChild(headerElement);
}
}
else
{
//This shouldn't happen unless explicity done elsewhere
Fwlog.debug(SecurityHelper.class, Fwlog.WI, "Unexpectedly Found
" + nodes.getLength() + " SOAP Header elements... probably ok but not
tested");
headerElement = (Element)nodes.item(0);
}
//
http://xml-security is the base-uri, which needs to be
//unique within document
XMLSignature sig = new XMLSignature(doc, "
http://xml-security",
XMLSignature.ALGO_ID_SIGNATURE_DSA);
// Add SOAP Body to XML Signature
headerElement.appendChild(sig.getElement());
// Due to the bug in the Apache security lib, it does not allow
// us to sign whole message and make "enveloped-signature"
// transform - strictly part of the specification.
// Only sign the body - IT IS NOT CONFORMED TO THE SPEC!!!!!!
//
// Neat trick: since the XMLSignature is actually a part of the
// SOAP XML document, the SOAP body is referenced as a URI
// fragment
sig.addDocument("#Body");
/******************* END XML SIGNATURE INIT
*********************/
/****************** SIGN THE FUCKER *******************/
sig.addKeyInfo(cert);
sig.addKeyInfo(cert.getPublicKey());
// Sign the XML Signature document with our private key
sig.sign(privateKey);
/****************** FUCKER SIGNED *********************/
Fwlog.debug(SecurityHelper.class, Fwlog.WI, "SecurityHelper::sign
-- tudo bem...");
return true;
}
catch (Exception e)
{
Fwlog.error(SecurityHelper.class, Fwlog.WI, "SecurityHelper::sign
-- Exception: ");
Fwlog.error(SecurityHelper.class, Fwlog.WI, e);
throw new WSSecurityException("Could not digitally sign SOAP
message", e);
}
}
/**
Verifica a assinatura do documento XML
@param doc documento XML
@return boolean true se tem succeso, false no contrário
*/
public static boolean verify(Document doc) throws WSSecurityException
{
try
{
org.apache.xml.security.Init.init();
// must match baseURI
String baseURI = "
http://xml-security";
CachedXPathAPI xpathAPI = new CachedXPathAPI();
Element nsctx = doc.createElement("nsctx");
nsctx.setAttribute("xmlns:ds", Constants.SignatureSpecNS);
Element signatureElem = (Element) xpathAPI.selectSingleNode(doc,
"//ds:Signature", nsctx);
// Check to make sure that the document claims to have been
signed
if (null == signatureElem)
{
throw new IllegalStateException ("SOAP Document not digitally
signed - missing element: //ds:Signature");
}
XMLSignature sig = new XMLSignature (signatureElem, baseURI);
boolean verify = sig.checkSignatureValue
(sig.getKeyInfo().getPublicKey());
if (true == verify)
{
Fwlog.debug(SecurityHelper.class, Fwlog.WI,
"SecurityHelper::verify -- tudo bem, returning true...");
return true;
}
}
catch (Exception e)
{
Fwlog.error(SecurityHelper.class, Fwlog.WI,
"SecurityHelper::verify -- Exception: ");
Fwlog.error(SecurityHelper.class, Fwlog.WI, e);
throw new WSSecurityException("Could not verify digitally signed
SOAP message", e);
}
// signature verification failed -
//do not forward request to SOAP Service.
return false;
}
See below:
Roedy Green escreveu:
I was trying to make sense of the standard. Perhaps you have digested
it .
1. does it require you to manually embed a private ? public? key in
the xml file or will it work with ordinary code-signing certs.
You embed the keys.
2. it is up to you to compute the digests, or is that the function of
the various algorithms you specify.
Its dependant on your arguments to 'keytool' for example, ie, how you
create your PrivateKey.
3. How do they specify algorithms in a platform independent way? Are
these java code?
You can use triple des, aes etc. There's a xmlsec dependency of 'bouncy
hunter' - you might look there for more info.
I am working on an idea to improve PAD file submission. These are
descriptions of shareware. The submission sites work hard to
discourage automated submission, trying to discourage spam. My idea to
fix this revolves around programmers and distribution sites having
digital certificates and everything having globally unique ids. To do
it requires a scheme for adding digital signatures to PAD files which
are a flavour of XML.
For globally unique ids - don't forget about java.util.UUID
Sounds kool, good luck!
HTH,
iksrazal
http://www.braziloutsource.com/