You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@santuario.apache.org by Jean-Charles Laurent <jc...@jeancoutu.com> on 2008/05/22 23:18:11 UTC

question

I have been trying to sign an XML file using the apache security package. 
I seem to be able to verify the signature on my side but it cannot be 
verified on the client side. What I can explain is why the

        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#"/>

Below is the output file followed by the java code and the keystore used. 
Please comment the code if you wish. I am not quite sure what I am doing 
here

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@jeancoutu.com

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.