
|
question
What I am trying to do is to sign a
the BODY element of the XML file (detached form) and insert the signature
inside the <Security> tag.
I am using the apache security package
(1.4.1). I seem to be able to verify the signature on my side but it cannot
be verified on the client side.
One thing I haved noticed is (andI can't
explain);
CanonicalizationMethod
Algorithim is "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
<ds:CanonicalizationMethod
Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
but the
Transform
Algorithm is "http://www.w3.org/2001/10/xml-exc-c14n#"
<ds:Transform
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
Hope someone will be able to help me
out as I am running out of ideas.
Thanks
JC
Below is the output file followed by
the java code and the keystore used. Please comment the code if you wish.
I am new to XML Signature.
Here is the output xml file:
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<s:Header>
<Security s:actor="IntervenantEmetteur"
xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
<ds:Reference URI="#PJC_01"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:Transforms xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
<ds:DigestValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">oNbIWOzgYk4X9634QnN5uA4bTHc=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
pohyKWQgfhSNe1BC/QJbR/CsDP8hSaJyQeoyJJ6TYkDa4xs7UznQV+heP/lK7zQH3jRaGO61OxhB
+rHpIVlYHl2vHRBCp6+dWu+e2/e16DfMOz2zb9K55+24GhOP3wo26riduDWg6BGQeKGCwLxyvn3r
KIe3nU/00hc4f/duh4M=
</ds:SignatureValue>
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Certificate xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
MIIB6jCCAVMCBEeCcWUwDQYJKoZIhvcNAQEEBQAwPDELMAkGA1UEBhMCQ0ExDDAKBgNVBAoTA1BK
QzERMA8GA1UECxMIQ2VudHJlUngxDDAKBgNVBAMTA0pDTDAeFw0wODAxMDcxODM3MjVaFw0wODA0
MDYxODM3MjVaMDwxCzAJBgNVBAYTAkNBMQwwCgYDVQQKEwNQSkMxETAPBgNVBAsTCENlbnRyZVJ4
MQwwCgYDVQQDEwNKQ0wwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOQWVGHiDaV7lcDNWhZy
L2+nR66VAjgryXio6wh4dhuqTU+XSAcSlpTSUh6OBcScTQsKvqci3O3rfUpYh0l6WC6vBOb9M1Rh
MDne6NmUtEx2LP/iJkutob+joO08LKx4g73NMuPgjlYVRMfXvFb92mzgBuxpM0RyctcDeNazayCP
AgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAi216ZxtAIOxZgIpDUfAyElsPTKEt/FKmmX90DgNeQNt4
zGWeJZJKwlnFkxfa0U64puTPw6BZscBCUhkzRUpzPT0Rxc5iPaGnq9xPiYsf8T3Uqx5+bD++em9z
nEKBTfKd7mM6JQAKKq7wlcYsKHcfupsHITRnYmPJ0F+fLVY/B4Y=
</ds:X509Certificate>
</ds:X509Data>
<ds:KeyValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:RSAKeyValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:Modulus xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
5BZUYeINpXuVwM1aFnIvb6dHrpUCOCvJeKjrCHh2G6pNT5dIBxKWlNJSHo4FxJxNCwq+pyLc7et9
SliHSXpYLq8E5v0zVGEwOd7o2ZS0THYs/+ImS62hv6Og7TwsrHiDvc0y4+COVhVEx9e8Vv3abOAG
7GkzRHJy1wN41rNrII8=
</ds:Modulus>
<ds:Exponent xmlns:ds="http://www.w3.org/2000/09/xmldsig#">AQAB</ds:Exponent>
</ds:RSAKeyValue>
</ds:KeyValue>
</ds:KeyInfo>
</ds:Signature></Security>
</s:Header>
<s:Body Id="PJC_01">
Some text to sign. </s:Body>
</s:Envelope>
Java code:
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.signature.XMLSignatureInput;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.Constants;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
public class SignXMLDetached {
/** {@link org.apache.commons.logging}
logging facility */
static org.apache.commons.logging.Log
log =
org.apache.commons.logging.LogFactory.getLog(SignXMLDetached.class.getName());
// Name of the output file.
private static final String
OUTPUT_FILE_NAME = "signature.xml";
// All the parameters for
the keystore (RSA)
private String keystoreType
= "JKS";
private String algoSignature
= XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1;
/**
* This is sample test.
It call the method that will sign an XML
* document represented
as a Striong object.
*
* @param unused Arguments
are for main signature but are not used.
* @throws Exception
If any of the exception are encountered such
*
as file not found, xml parsing errors, xml signature error, etc...
*/
public static void main(String
unused[]) throws Exception {
String keystorePass
= "ab987c";
String privateKeyAlias
= "test";
String privateKeyPass
= "kpi135";
String keystoreFile
= "keystore/pjc.jks";
String xmlStream
=
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"
+"<s:Header>\n"
+" <Security s:actor=\"IntervenantEmetteur\" xmlns=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">\n"
+" </Security>\n"
+"</s:Header>\n"
+"<s:Body Id=\"PJC_01\">\n"
+"Some text to sign."
+" </s:Body>\n"
+"</s:Envelope>\n";
SignXMLDetached
signXml = new SignXMLDetached();
String signedXML
= signXml.signIt(keystoreFile, keystorePass, privateKeyAlias,
privateKeyPass, xmlStream);
FileWriter
out = new FileWriter(OUTPUT_FILE_NAME);
out.write(signedXML);
out.flush();
out.close();
System.out.println("Finished
signing. View file in '"+ OUTPUT_FILE_NAME +"'.");
}
/**
* This method create
an XML document using the given String object.
* Then we transform
(normalize) add key information and sign the XML
* document. Finally
we convert document to a String object that represents the XML document.
* @param keyStorePath
: name and location of the keystore file.
* @param keystorePass
: the password to open keystore.
* @param privateKeyAlias
: the private key and certificate alias as stored inside the keystore.
* @param privateKeyPass
: the private key password needed to retrieve private key.
* @param strXML : A
String object that represents the XML document to sign.
* @return Returns a
String representing the sign XML document.
* @throws Exception
If any of the exception are encountered such
*
as file not found, xml parsing errors, xml signature error, etc...
*/
public String signIt(String
keyStorePath, String keystorePass,
String privateKeyAlias, String privateKeyPass, String strXML)
throws Exception {
org.apache.xml.security.Init.init();
KeyStore ks
= KeyStore.getInstance(keystoreType);
FileInputStream
fis = new FileInputStream(keyStorePath);
// Load the
keystore information.
ks.load(fis,
keystorePass.toCharArray());
// Get the
private key from keystore (will be used for signing).
PrivateKey
privateKey = (PrivateKey) ks.getKey(privateKeyAlias,
privateKeyPass.toCharArray());
// Create a
document factory to build the xml file to sign.
javax.xml.parsers.DocumentBuilderFactory
dbf =
javax.xml.parsers.DocumentBuilderFactory.newInstance();
// XML Signature
needs to be namespace aware
dbf.setNamespaceAware(true);
// Create XML
document using given string (that represents the xml document).
javax.xml.parsers.DocumentBuilder
db = dbf.newDocumentBuilder();
org.w3c.dom.Document
doc = db.parse(new InputSource(new StringReader(strXML)));
NodeList nodeList
= doc.getElementsByTagName("Security");
Node root =
nodeList.item(0);
// Create the
transforms object for the Document/Reference
Transforms
transforms = new Transforms(doc);
// Canonicalized
part of the signature element.
transforms.addTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
// Create an
XML Signature object from the document.
String baseURI
= null;
XMLSignature
sig = new XMLSignature(doc, baseURI, algoSignature);
// Add the
above Document/Reference to signature.
// The signature
is going to be injected inside the root node.
root.appendChild(sig.getElement());
sig.addDocument("#PJC_01",
transforms, Constants.ALGO_ID_DIGEST_SHA1);
// Get the
certificate from keystore. Then add it in the KeyInfo element
// along with
the public key. Note, this could have its own alias but
// we will
considered it to be the same as the private key alias.
X509Certificate
cert =
(X509Certificate) ks.getCertificate(privateKeyAlias);
sig.addKeyInfo(cert);
sig.addKeyInfo(cert.getPublicKey());
sig.sign(privateKey);
// Convert
XML Doc to String.
return xmlToString(doc);
}
/*
* Convert the given
xml Document object to a String object.
* If an error occurs,
log it and return a null object.
*
* @param doc : A Document
object to convert to a String object.
* @return Returns a
String object representing the given Document object.
*/
private static String xmlToString(org.w3c.dom.Document
doc) {
try {
Source source = new DOMSource(doc);
StringWriter stringWriter = new StringWriter();
Result result = new StreamResult(stringWriter);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(source, result);
return stringWriter.getBuffer().toString();
} catch (TransformerConfigurationException
e) {
e.printStackTrace();
} catch (TransformerException
e) {
e.printStackTrace();
}
return null;
}
}
Jean-Charles Laurent
Analyste / Analyst
Le Groupe Jean Coutu (PJC) Inc.
tél: 450-463-1890 (3363)
fax: 450-646-0567
jclaurent@...
AVERTISSEMENT CONCERNANT LA CONFIDENTIALITE
Ce message, incluant ses pieces jointes, est strictement reserve a l'usage de l'individu ou de l'entite a qui il est
adresse et contient de l'information privilegiee et confidentielle. La dissemination, distribution ou copie de cette
communication est strictement prohibee. Si vous n'etes pas le destinataire projete veuillez retourner
immediatement un courrier electronique a l'expediteur et effacez toutes les copies.
CONFIDENTIALITY WARNING
This message, including its attachments, is strictly intended for the use of the individual or the entity to which it is addressed
and contains privileged and confidential information. Disclosure, distribution or copy of this communication is strictly
prohibited. If you are not the intended recipient please notify us immediately by returning the e-mail to the originator and
deleting all copies. |
|

|
Re: question
This is a fairly common issue. If you're signing a document and then
inserting the ds:Signature into another context where it will be
verified (e.g. inside a SOAP Envelope, either Security header or an
enveloped signature in the body), then you pretty much have to use
exclusive canonicalization as the algorithm for the
ds:Signature/ds:CanonicalizatonMethod. This is because if you instead
use inclusive c14n, including it as a subordinate element within
another document will cause the visible namespaces to be included as a
part of the ds:SignedInfo, and this will almost certainly break the
signature on verification. The same is true for the c14n transform of
any same-document References included in signature (assuming the
referent has also been inserted into a new context that has additional
visible namespaces).
The Apache xmlsec lib has various means by which you can set the c14n
method prior to signing, it probably just defaults to inclusive.
--Brent
Jean-Charles Laurent wrote:
What I am trying to do is to sign a
the BODY element of the XML file (detached form) and insert the
signature
inside the <Security> tag.
I am using the apache security
package
(1.4.1). I seem to be able to verify the signature on my side but it
cannot
be verified on the client side.
One thing I haved noticed is (andI
can't
explain);
CanonicalizationMethod
Algorithim is "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
<ds:CanonicalizationMethod
Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
but the
Transform
Algorithm is "http://www.w3.org/2001/10/xml-exc-c14n#"
<ds:Transform
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
Hope someone will be able to help me
out as I am running out of ideas.
Thanks
JC
Below is the output file followed by
the java code and the keystore used. Please comment the code if you
wish.
I am new to XML Signature.
Here is the output xml file:
<?xml version="1.0"
encoding="UTF-8"?>
<s:Envelope
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<s:Header>
<Security
s:actor="IntervenantEmetteur"
xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:CanonicalizationMethod
Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
<ds:SignatureMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
<ds:Reference URI="#PJC_01"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:Transforms
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:Transform
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
</ds:Transforms>
<ds:DigestMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
<ds:DigestValue
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">oNbIWOzgYk4X9634QnN5uA4bTHc=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
pohyKWQgfhSNe1BC/QJbR/CsDP8hSaJyQeoyJJ6TYkDa4xs7UznQV+heP/lK7zQH3jRaGO61OxhB
+rHpIVlYHl2vHRBCp6+dWu+e2/e16DfMOz2zb9K55+24GhOP3wo26riduDWg6BGQeKGCwLxyvn3r
KIe3nU/00hc4f/duh4M=
</ds:SignatureValue>
<ds:KeyInfo
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Certificate
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
MIIB6jCCAVMCBEeCcWUwDQYJKoZIhvcNAQEEBQAwPDELMAkGA1UEBhMCQ0ExDDAKBgNVBAoTA1BK
QzERMA8GA1UECxMIQ2VudHJlUngxDDAKBgNVBAMTA0pDTDAeFw0wODAxMDcxODM3MjVaFw0wODA0
MDYxODM3MjVaMDwxCzAJBgNVBAYTAkNBMQwwCgYDVQQKEwNQSkMxETAPBgNVBAsTCENlbnRyZVJ4
MQwwCgYDVQQDEwNKQ0wwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOQWVGHiDaV7lcDNWhZy
L2+nR66VAjgryXio6wh4dhuqTU+XSAcSlpTSUh6OBcScTQsKvqci3O3rfUpYh0l6WC6vBOb9M1Rh
MDne6NmUtEx2LP/iJkutob+joO08LKx4g73NMuPgjlYVRMfXvFb92mzgBuxpM0RyctcDeNazayCP
AgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAi216ZxtAIOxZgIpDUfAyElsPTKEt/FKmmX90DgNeQNt4
zGWeJZJKwlnFkxfa0U64puTPw6BZscBCUhkzRUpzPT0Rxc5iPaGnq9xPiYsf8T3Uqx5+bD++em9z
nEKBTfKd7mM6JQAKKq7wlcYsKHcfupsHITRnYmPJ0F+fLVY/B4Y=
</ds:X509Certificate>
</ds:X509Data>
<ds:KeyValue
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:RSAKeyValue
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:Modulus
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
5BZUYeINpXuVwM1aFnIvb6dHrpUCOCvJeKjrCHh2G6pNT5dIBxKWlNJSHo4FxJxNCwq+pyLc7et9
SliHSXpYLq8E5v0zVGEwOd7o2ZS0THYs/+ImS62hv6Og7TwsrHiDvc0y4+COVhVEx9e8Vv3abOAG
7GkzRHJy1wN41rNrII8=
</ds:Modulus>
<ds:Exponent
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">AQAB</ds:Exponent>
</ds:RSAKeyValue>
</ds:KeyValue>
</ds:KeyInfo>
</ds:Signature></Security>
</s:Header>
<s:Body Id="PJC_01">
Some text to sign. </s:Body>
</s:Envelope>
Java code:
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.security.KeyStore;
import java.security.PrivateKey;
import
java.security.cert.X509Certificate;
import
javax.xml.parsers.DocumentBuilder;
import
javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import
javax.xml.transform.TransformerConfigurationException;
import
javax.xml.transform.TransformerException;
import
javax.xml.transform.TransformerFactory;
import
javax.xml.transform.dom.DOMSource;
import
javax.xml.transform.stream.StreamResult;
import
org.apache.xml.security.signature.XMLSignature;
import
org.apache.xml.security.signature.XMLSignatureInput;
import
org.apache.xml.security.transforms.Transforms;
import
org.apache.xml.security.utils.Constants;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
public class SignXMLDetached {
/** {@link
org.apache.commons.logging}
logging facility */
static
org.apache.commons.logging.Log
log =
org.apache.commons.logging.LogFactory.getLog(SignXMLDetached.class.getName());
// Name of the output file.
private static final String
OUTPUT_FILE_NAME = "signature.xml";
// All the parameters for
the keystore (RSA)
private String keystoreType
= "JKS";
private String algoSignature
= XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1;
/**
* This is sample test.
It call the method that will sign an XML
* document represented
as a Striong object.
*
* @param unused Arguments
are for main signature but are not used.
* @throws Exception
If any of the exception are encountered such
*
as file not found, xml parsing errors, xml signature error, etc...
*/
public static void main(String
unused[]) throws Exception {
String keystorePass
= "ab987c";
String privateKeyAlias
= "test";
String privateKeyPass
= "kpi135";
String keystoreFile
= "keystore/pjc.jks";
String xmlStream
=
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"
+"<s:Header>\n"
+" <Security s:actor=\"IntervenantEmetteur\"
xmlns=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">\n"
+" </Security>\n"
+"</s:Header>\n"
+"<s:Body Id=\"PJC_01\">\n"
+"Some text to sign."
+" </s:Body>\n"
+"</s:Envelope>\n";
SignXMLDetached
signXml = new SignXMLDetached();
String signedXML
= signXml.signIt(keystoreFile, keystorePass, privateKeyAlias,
privateKeyPass, xmlStream);
FileWriter
out = new FileWriter(OUTPUT_FILE_NAME);
out.write(signedXML);
out.flush();
out.close();
System.out.println("Finished
signing. View file in '"+ OUTPUT_FILE_NAME +"'.");
}
/**
* This method create
an XML document using the given String object.
* Then we transform
(normalize) add key information and sign the XML
* document. Finally
we convert document to a String object that represents the XML document.
* @param keyStorePath
: name and location of the keystore file.
* @param keystorePass
: the password to open keystore.
* @param privateKeyAlias
: the private key and certificate alias as stored inside the keystore.
* @param privateKeyPass
: the private key password needed to retrieve private key.
* @param strXML : A
String object that represents the XML document to sign.
* @return Returns a
String representing the sign XML document.
* @throws Exception
If any of the exception are encountered such
*
as file not found, xml parsing errors, xml signature error, etc...
*/
public String signIt(String
keyStorePath, String keystorePass,
String privateKeyAlias, String privateKeyPass, String strXML)
throws Exception {
org.apache.xml.security.Init.init();
KeyStore ks
= KeyStore.getInstance(keystoreType);
FileInputStream
fis = new FileInputStream(keyStorePath);
// Load the
keystore information.
ks.load(fis,
keystorePass.toCharArray());
// Get the
private key from keystore (will be used for signing).
PrivateKey
privateKey = (PrivateKey) ks.getKey(privateKeyAlias,
privateKeyPass.toCharArray());
// Create a
document factory to build the xml file to sign.
javax.xml.parsers.DocumentBuilderFactory
dbf =
javax.xml.parsers.DocumentBuilderFactory.newInstance();
// XML Signature
needs to be namespace aware
dbf.setNamespaceAware(true);
// Create XML
document using given string (that represents the xml document).
javax.xml.parsers.DocumentBuilder
db = dbf.newDocumentBuilder();
org.w3c.dom.Document
doc = db.parse(new InputSource(new StringReader(strXML)));
NodeList nodeList
= doc.getElementsByTagName("Security");
Node root =
nodeList.item(0);
// Create the
transforms object for the Document/Reference
Transforms
transforms = new Transforms(doc);
// Canonicalized
part of the signature element.
transforms.addTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
// Create an
XML Signature object from the document.
String baseURI
= null;
XMLSignature
sig = new XMLSignature(doc, baseURI, algoSignature);
// Add the
above Document/Reference to signature.
// The signature
is going to be injected inside the root node.
root.appendChild(sig.getElement());
sig.addDocument("#PJC_01",
transforms, Constants.ALGO_ID_DIGEST_SHA1);
// Get the
certificate from keystore. Then add it in the KeyInfo element
// along with
the public key. Note, this could have its own alias but
// we will
considered it to be the same as the private key alias.
X509Certificate
cert =
(X509Certificate) ks.getCertificate(privateKeyAlias);
sig.addKeyInfo(cert);
sig.addKeyInfo(cert.getPublicKey());
sig.sign(privateKey);
// Convert
XML Doc to String.
return xmlToString(doc);
}
/*
* Convert the given
xml Document object to a String object.
* If an error occurs,
log it and return a null object.
*
* @param doc : A Document
object to convert to a String object.
* @return Returns a
String object representing the given Document object.
*/
private static String
xmlToString(org.w3c.dom.Document
doc) {
try {
Source source = new DOMSource(doc);
StringWriter stringWriter = new StringWriter();
Result result = new StreamResult(stringWriter);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(source, result);
return stringWriter.getBuffer().toString();
} catch
(TransformerConfigurationException
e) {
e.printStackTrace();
} catch (TransformerException
e) {
e.printStackTrace();
}
return null;
}
}
Jean-Charles Laurent
Analyste / Analyst
Le Groupe Jean Coutu (PJC) Inc.
tél: 450-463-1890 (3363)
fax: 450-646-0567
jclaurent@...
AVERTISSEMENT CONCERNANT LA CONFIDENTIALITE
Ce message, incluant ses pieces jointes, est strictement reserve a l'usage de l'individu ou de l'entite a qui il est
adresse et contient de l'information privilegiee et confidentielle. La dissemination, distribution ou copie de cette
communication est strictement prohibee. Si vous n'etes pas le destinataire projete veuillez retourner
immediatement un courrier electronique a l'expediteur et effacez toutes les copies.
CONFIDENTIALITY WARNING
This message, including its attachments, is strictly intended for the use of the individual or the entity to which it is addressed
and contains privileged and confidential information. Disclosure, distribution or copy of this communication is strictly
prohibited. If you are not the intended recipient please notify us immediately by returning the e-mail to the originator and
deleting all copies.
|
|

|
Re: question
Well, first off: you can set the boolean system property
"org.apache.xml.security.ignoreLineBreaks" to true to supposedly get it
to not emit most (all?) newlines in the signature output. I haven't
used it personally, not sure if that that gets you what you are asking
for.
However: this really isn't the solution to the problem. If the
signature is valid when you created it (with or without linebreaks),
then it's valid, period. If the remote peer fails to validate it
successfully, then there are several possibilities including: 1) the
signature is getting corrupted prior to the validation, possibly as a
part of the serialization or deserialization process on either side.
The addition or removal of whitespace is a common error here (or
conversion, as in conversion of Unix-style newlines to windows CRLF
form) 2) they aren't using the right key to validate (what was the
exact validation error on their side, if any?) 3) their XML Signature
impl is broken. Specifically, if they expect or require no whitespace
in the SignedInfo or something like that, then that's broken behavior.
--Brent
Jean-Charles Laurent wrote:
Thanks Brent
I was missing the
Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS
parameter in the constructor.
XMLSignature sig = new
XMLSignature(doc,
baseURI, algoSignature, Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
However, it is still not valid at
the
third party's end. Someone here managed to send a valid xml file that
was
generated with dot.net and the only thing that is different (from what
we can see) is that the SignedInfo is on a single line. It seems that
with
dot-net program they used an option that omits white space or something
like that.
Is there something that I can use to
get the complet SignedInfo element on a single line?
Thanks for your help
Note:
they have this on a single line:
<Signature
xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"
/><SignatureMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"
/><Reference
URI="#PJC_01"><Transforms><Transform
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"
/></Transforms><DigestMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"
/><DigestValue>CtRKtN9v0WVA7onJ4OBA9PSaz/U=</DigestValue></Reference></SignedInfo>
where the output with apache is
something
like:
<Signature
xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"
/>
<SignatureMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"
/>
<Reference
URI="#PJC_01">
<Transforms>
<Transform
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
</Transforms>
<DigestMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>CtRKtN9v0WVA7onJ4OBA9PSaz/U=</DigestValue>
</Reference>
</SignedInfo>
Jean-Charles Laurent
Analyste / Analyst
Le Groupe Jean Coutu (PJC) Inc.
tél: 450-463-1890 (3363)
fax: 450-646-0567
jclaurent@...
|

|
Re: question
Jean-Charles Laurent wrote:
Thanks Brent,
I agree, the removel of line break
is
not the perfect solution. My guest would be be some kind
of serialization or deserialization
problem.
That's probably the most common problem with signatures that fail to
validate after being sent to a remote peer.
The xml is signed on a
AS400 (using java), then validated on a
windows PC with BizTalk and dot-net. We dot not have control on the PC
side so we must do with what we have.
Well it sounds like the problem is on their side, not yours, unless you
are corrupting when you serialize. Have you tried signing, writing it
out to a file etc, then rereading and parsing and validating on your
side? If that works, then it's almost certainly a problem on their
side (unless there's a bug in Apache XML Security or something).
Other cies have managed
to sign in
Java (using Bouncy Castle) it seems.
Well, BC just provides the crypto (JCA/JCE support), not XML Signature
support AFAIK, so I doubt that's relevant. You can also configure the
BC JCE and use that with Apache XML Security if you like. I doubt that
is the problem, however.
To set the system property we need
to
do something like this?
System.setProperty("org.apache.xml.security.ignoreLineBreaks",
"true");
Yes, or you can specify as an arg to the JVM with a -D parameter, e.g.
-Dorg.apache.xml.security.ignoreLineBreaks=true
If so when should do this. I'am
doing
it like this:
public String signIt(String
keyStorePath,
String keystorePass,
String privateKeyAlias,
String privateKeyPass, String strXML) throws Exception {
//
System.setProperty("org.apache.xml.security.ignoreLineBreaks",
"true");
org.apache.xml.security.Init.init();
This gets set as a static member variable, so it's only going to get
evaluated once, when the class loads. If you do with
System.setProperty, you'd have to make sure to do very early on in your
code, before the XMLUtils class gets loaded by the classloader. The
safest/surest way is probably just to use a -D arg to your JVM.
org.apache.xml.security.utils.XMLUtils:
private static boolean ignoreLineBreaks = false;
static {
try {
ignoreLineBreaks = Boolean.getBoolean
("org.apache.xml.security.ignoreLineBreaks");
} catch (Exception e) {
// ignore exceptions
}
}
--Brent
|

|
Re: question
(Please hit reply-to-all when you reply so that your email goes to the
list and not just to me).
Jean-Charles Laurent wrote:
Hi Brent,
Yes I did write to a file and I
validate
it with a Java tool (found on the web) or with a Java program that I
got
in the sample directory of xml security package. I am quite sure what
we
are sending is a valid xml signature file. I think this is an issue
with
dot-net.
Well, then ultimately it's not your problem, and if I were you, I
personally would not waste my time trying to work around someone else's
broken code. Ask them to fix it.
Here someone did a
signature with a dot-net program and for it
to validate on the peer side, they needed to use some dot-net parameter
to prevent blanks or newline characters in the signature. We know that
it is not being corrupted on the way (since we can send the dot-net
result
and it is valide). Their resulting sign XML file has the SignedInfo tag
on a single line with no carriage return characters. This is what I am
trying to reproduce with my Java application.
I understand. Good luck. Even if you get the line breaks feature
working, realize this very may not actually fix your problem, given
everything that you've said. I'd be very wary.
Out of curiosity: do you know whether the .NET code that is being used
to validate is some standard .NET XML Signature library, or something
that someone just wrote up for this particular application? If the
former, I'd be interested to know what it is, just for future
reference...
I tried to set the parameter "org.apache.xml.security.ignoreLineBreaks"
and I semm to have no effect on my signature. I must be doing something
wrong. I tried as you suggested via the -D option ("java
-Dorg.apache.xml.security.ignoreLineBreaks=true
..."). To make sure the
parameter
is set correctly, I do a
System.out.println("ignoreLineBreaks="+System.getProperty("org.apache.xml.security.ignoreLineBreaks"));
which displays true.
I haven't personally used this feature, perhaps someone on the Apache
xml security dev team can comment. But one thing is (and sorry I
didn't realize this before): according to SVN the last Java xmlsec
release (1.4.1) was tagged in May 2007, and this ignore line breaks
feature wasn't added until October 2007, so you would have to be
running with a xmlsec jar built from recent source, or perhaps try with
the 1.4.2 beta (or release candidate?) that I believe Sean currently
has out there somewhere.
--Brent
|

|
Re: question
Thanks Brent for all your help and quick
response.
We finaly talk to the client/3rd-party
and convinced them that they were doing something wrong. They finaly admitted
that they were removing carriage returns and blanks spaces in the signed
info.
Jean-Charles Laurent
Analyste / Analyst
Le Groupe Jean Coutu (PJC) Inc.
tél: 450-463-1890 (3363)
fax: 450-646-0567
jclaurent@...
(Please hit reply-to-all when you reply so that your email
goes to the list and not just to me).
Jean-Charles Laurent wrote:
Hi Brent,
Yes I did write to a file and I validate it with a Java tool (found on
the web) or with a Java program that I got in the sample directory of xml
security package. I am quite sure what we are sending is a valid xml signature
file. I think this is an issue with dot-net.
Well, then ultimately it's not your problem, and if I were you, I personally
would not waste my time trying to work around someone else's broken code.
Ask them to fix it.
Here someone did a signature with a
dot-net program and for it to validate on the peer side, they needed to
use some dot-net parameter to prevent blanks or newline characters in the
signature. We know that it is not being corrupted on the way (since we
can send the dot-net result and it is valide). Their resulting sign XML
file has the SignedInfo tag on a single line with no carriage return characters.
This is what I am trying to reproduce with my Java application.
I understand. Good luck. Even if you get the line breaks feature
working, realize this very may not actually fix your problem, given everything
that you've said. I'd be very wary.
Out of curiosity: do you know whether the .NET code that is being used
to validate is some standard .NET XML Signature library, or something that
someone just wrote up for this particular application? If the former,
I'd be interested to know what it is, just for future reference...
I tried to set the parameter "org.apache.xml.security.ignoreLineBreaks"
and I semm to have no effect on my signature. I must be doing something
wrong. I tried as you suggested via the -D option ("java
-Dorg.apache.xml.security.ignoreLineBreaks=true
..."). To make sure the parameter
is set correctly, I do a
System.out.println("ignoreLineBreaks="+System.getProperty("org.apache.xml.security.ignoreLineBreaks"));
which displays true.
I haven't personally used this feature, perhaps someone on the Apache xml
security dev team can comment. But one thing is (and sorry I didn't
realize this before): according to SVN the last Java xmlsec release (1.4.1)
was tagged in May 2007, and this ignore line breaks feature wasn't added
until October 2007, so you would have to be running with a xmlsec jar built
from recent source, or perhaps try with the 1.4.2 beta (or release candidate?)
that I believe Sean currently has out there somewhere.
--Brent
AVERTISSEMENT CONCERNANT LA CONFIDENTIALITE
Ce message, incluant ses pieces jointes, est strictement reserve a l'usage de l'individu ou de l'entite a qui il est
adresse et contient de l'information privilegiee et confidentielle. La dissemination, distribution ou copie de cette
communication est strictement prohibee. Si vous n'etes pas le destinataire projete veuillez retourner
immediatement un courrier electronique a l'expediteur et effacez toutes les copies.
CONFIDENTIALITY WARNING
This message, including its attachments, is strictly intended for the use of the individual or the entity to which it is addressed
and contains privileged and confidential information. Disclosure, distribution or copy of this communication is strictly
prohibited. If you are not the intended recipient please notify us immediately by returning the e-mail to the originator and
deleting all copies. |
|