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 { /** [EMAIL PROTECTED] 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 [EMAIL PROTECTED] 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.
pjc.jks
Description: Binary data