Hi Sean, I guess I'm confused. I thought the whole point of the enveloping technique was that the signature would become part of the original document? Really what I want to do is sign the soap body (id=Body) and then put the resulting signature into the soap header.
Am I better off trying to do a detached signature instead? Then create a new blank document, add the body from the original, add a new node for the soap header, and put the detached signature content on that? Best regards, Richard A. Sand, CEO Skyworth TTG USA, Inc. +1 (866) 9-TRIPOD http://www.skyworthttg.com/us -----Original Message----- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] Sent: Wednesday, October 08, 2008 5:08 PM To: security-dev@xml.apache.org Subject: Re: problem enveloping a soap body I believe it is because of this line: // Create a DOMSignContext, specifying the PrivateKey and the document > // location of the XMLSignature > DOMSignContext domSignContext = new DOMSignContext(privateKey, doc.getDocumentElement()); I think this is because you are trying to create an enveloping signature over the Document that you parsed, but then also trying to insert the Signature element as a child element of the root element of the same document. You really should create a brand new Document object to insert the Signature in and then pass the root Element of that document to the DOMSignContext above. --Sean Richard Sand wrote: > Hi Sean, > > Thanks for the prompt reply! Actually I had tried that as well- it also fails > but I get a different error message and stacktrace. Maybe this sheds some > light on what's happening? > > org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR: An attempt was made to > insert a node where it is not permitted. > at org.apache.xerces.dom.ParentNode.internalInsertBefore(Unknown Source) > at org.apache.xerces.dom.ParentNode.insertBefore(Unknown Source) > at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.marshal(Unknown Source) > at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign(Unknown Source) > at TestClass2.signDocument(TestClass2.java:125) > at TestClass2.main(TestClass2.java:75) > > Best regards, > > Richard A. Sand, CEO > Skyworth TTG USA, Inc. > +1 (866) 9-TRIPOD > http://www.skyworthttg.com/us > > > -----Original Message----- > From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] > Sent: Wednesday, October 08, 2008 9:31 AM > To: security-dev@xml.apache.org > Subject: Re: problem enveloping a soap body > > You are trying to import a Document node which is illegal according to > Document.importNode. Try changing the following line: > > XMLStructure content = new DOMStructure(doc); > > to: > > XMLStructure content = new > DOMStructure(doc.getDocumentElement()); > > --Sean > > > Richard Sand wrote: >> Hi all, >> >> I'm sure this has been encountered before... I'm trying to use the XML >> security API to sign a SOAP request. For various reasons I'm not using >> WS-Security, only XML security. >> >> I've gone through the sample code provided with the API and I can see that >> the enveloping sample does not load the XML from an existing stream (such as >> a file), but rather instantiates the XML document programmatically. When I >> build my Document using any sort of stream, I get a DOMException upon >> signing, presumably because the Document cannot be altered. >> >> org.w3c.dom.DOMException: NOT_SUPPORTED_ERR: The implementation does not >> support the requested type of object or operation. >> at org.apache.xerces.dom.CoreDocumentImpl.importNode(Unknown Source) >> at org.apache.xerces.dom.CoreDocumentImpl.importNode(Unknown Source) >> at org.jcp.xml.dsig.internal.dom.DOMUtils.appendChild(Unknown Source) >> at org.jcp.xml.dsig.internal.dom.DOMXMLObject.marshal(Unknown Source) >> at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.marshal(Unknown Source) >> at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign(Unknown Source) >> at TestClass2.signDocument(TestClass2.java:125) >> at TestClass2.main(TestClass2.java:75) >> >> My apologies for the elementary question, but how should I generate the >> Document such that DOMXMLSignature.sign() doesn't have this problem with >> importNode? >> >> Thanks for any help! FYI I'm using Sun JDK 1.5.0_12 and building with only >> the libraries provided with xmlsec-1.4.2. >> >> My source code is here for reference. FWIW I had a heck of a time loading an >> encrypted private key, I had to scour the net for that code too, so if >> that’s useful for anyone please help yourselves. :-) >> >> import java.io.ByteArrayInputStream; >> import java.io.File; >> import java.io.FileInputStream; >> import java.io.IOException; >> import java.security.AlgorithmParameters; >> import java.security.InvalidAlgorithmParameterException; >> import java.security.InvalidKeyException; >> import java.security.Key; >> import java.security.KeyFactory; >> import java.security.NoSuchAlgorithmException; >> import java.security.PrivateKey; >> import java.security.Provider; >> import java.security.PublicKey; >> import java.security.cert.Certificate; >> import java.security.cert.CertificateException; >> import java.security.cert.CertificateFactory; >> import java.security.spec.InvalidKeySpecException; >> import java.security.spec.InvalidParameterSpecException; >> import java.security.spec.PKCS8EncodedKeySpec; >> import java.util.Collections; >> >> import javax.crypto.BadPaddingException; >> import javax.crypto.Cipher; >> import javax.crypto.EncryptedPrivateKeyInfo; >> import javax.crypto.IllegalBlockSizeException; >> import javax.crypto.NoSuchPaddingException; >> import javax.crypto.SecretKeyFactory; >> import javax.crypto.spec.PBEKeySpec; >> import javax.xml.crypto.XMLStructure; >> import javax.xml.crypto.dom.DOMStructure; >> import javax.xml.crypto.dsig.CanonicalizationMethod; >> import javax.xml.crypto.dsig.DigestMethod; >> import javax.xml.crypto.dsig.Reference; >> import javax.xml.crypto.dsig.SignatureMethod; >> import javax.xml.crypto.dsig.SignedInfo; >> import javax.xml.crypto.dsig.Transform; >> import javax.xml.crypto.dsig.XMLObject; >> import javax.xml.crypto.dsig.XMLSignature; >> import javax.xml.crypto.dsig.XMLSignatureFactory; >> import javax.xml.crypto.dsig.dom.DOMSignContext; >> import javax.xml.crypto.dsig.keyinfo.KeyInfo; >> import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory; >> import javax.xml.crypto.dsig.keyinfo.KeyValue; >> import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec; >> import javax.xml.crypto.dsig.spec.TransformParameterSpec; >> import javax.xml.parsers.DocumentBuilderFactory; >> >> import org.w3c.dom.Document; >> >> public class TestClass2 { >> >> /** >> * @param args >> */ >> public static void main(String[] args) { >> String xmlStr = "<?xml version=\"1.0\" >> encoding=\"UTF-8\"?><soapenv:Envelope >> xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"><soapenv:Body >> Id=\"body\"><ns2:getGoKartAll >> xmlns:ns2=\"http://soa.examples.ttg.com\"><ns2:model>1</ns2:model><ns2:width>33</ns2:width><ns2:length>66</ns2:length><ns2:tires>6</ns2:tires><ns2:color>Dark >> Red</ns2:color></ns2:getGoKartAll></soapenv:Body></soapenv:Envelope>"; >> // String xmlStr = >> // >> "<getGoKartAll><model>1</model><width>33</width><length>66</length><tires>6</tires><color>Dark >> Red</color></getGoKartAll>"; >> // String xmlStr = "<Object>Some stuff</Object>"; >> String X509cert = "c:\\gkconfig.der"; >> String privateKey = "c:\\gkconfig_key.pk8"; >> String password = "password"; >> >> try { >> // Create a builder factory >> ByteArrayInputStream is = new >> ByteArrayInputStream(xmlStr.getBytes()); >> DocumentBuilderFactory factory = >> DocumentBuilderFactory.newInstance(); >> factory.setNamespaceAware(true); >> factory.setValidating(false); >> >> // Create the builder and parse the input >> Document doc = factory.newDocumentBuilder().parse(is); >> >> // Sign and output >> signDocument(doc, "body", privateKey, password, >> X509cert); >> String signed = doc.toString(); >> System.out.println("Signed: " + signed); >> >> } catch (Exception e) { >> e.printStackTrace(); >> } >> } >> >> public static void signDocument(Document doc, String reference, String >> privateKeyFile, String password, String x509certFile) throws Exception { >> String providerName = System.getProperty("jsr105Provider", >> "org.jcp.xml.dsig.internal.dom.XMLDSigRI"); >> XMLSignatureFactory xmlSigFactory = >> XMLSignatureFactory.getInstance("DOM", (Provider) >> Class.forName(providerName).newInstance()); >> >> // Create a Reference to a same-document URI that is an Object >> // element and specify the SHA1 digest algorithm >> // Reference ref = xmlSigFactory.newReference(reference, >> // xmlSigFactory.newDigestMethod(DigestMethod.SHA1, null)); >> >> // also specify the SHA1 digest algorithm and the ENVELOPED >> Transform. >> Reference ref = xmlSigFactory.newReference("", >> xmlSigFactory.newDigestMethod(DigestMethod.SHA1, null), >> Collections.singletonList(xmlSigFactory >> .newTransform(Transform.ENVELOPED, >> (TransformParameterSpec) null)), null, null); >> >> // Create the SignedInfo >> SignedInfo si = >> xmlSigFactory.newSignedInfo(xmlSigFactory.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, >> (C14NMethodParameterSpec) null), >> xmlSigFactory.newSignatureMethod(SignatureMethod.DSA_SHA1, null), >> Collections.singletonList(ref)); >> >> // Create the XML object from the document >> XMLStructure content = new DOMStructure(doc); >> XMLObject xmlobj = >> xmlSigFactory.newXMLObject(Collections.singletonList(content), "body", null, >> null); >> >> // Load the public and private keys >> Certificate certs[] = loadX509CertificateChain(x509certFile); >> if (certs.length < 1) >> return; >> PublicKey publicKey = certs[0].getPublicKey(); >> PrivateKey privateKey = loadPKCS8PrivateKey(privateKeyFile, >> password); >> >> // Create a KeyInfo from the public key >> KeyInfoFactory kif = xmlSigFactory.getKeyInfoFactory(); >> KeyValue kv = kif.newKeyValue(publicKey); >> KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv)); >> >> // Create the XMLSignature (but don't sign it yet) >> XMLSignature signature = xmlSigFactory.newXMLSignature(si, ki, >> Collections.singletonList(xmlobj), null, null); >> >> // Create a DOMSignContext, specifying the PrivateKey and the >> document >> // location of the XMLSignature >> DOMSignContext domSignContext = new DOMSignContext(privateKey, >> doc.getDocumentElement()); >> >> // Lastly, generate the enveloping signature using the >> PrivateKey >> signature.sign(domSignContext); >> } >> >> /** >> * Loads the DER-encoded X509 certificate chain >> * >> * @param certificateChainFileName >> * @return >> * @throws IOException >> * @throws CertificateException >> */ >> public static Certificate[] loadX509CertificateChain(String >> certificateChainFileName) throws IOException, CertificateException { >> FileInputStream certificateStream = new >> FileInputStream(certificateChainFileName); >> CertificateFactory certificateFactory = >> CertificateFactory.getInstance("X.509"); >> java.security.cert.Certificate[] chain = {}; >> chain = >> certificateFactory.generateCertificates(certificateStream).toArray(chain); >> certificateStream.close(); >> >> return chain; >> } >> >> /** >> * Loads the DER-encoded, encrypted PKCS8 private key >> */ >> public static PrivateKey loadPKCS8PrivateKey(String privateKeyFile, >> String password) throws InvalidKeyException, InvalidParameterSpecException, >> IllegalBlockSizeException, >> InvalidAlgorithmParameterException, NoSuchPaddingException, >> BadPaddingException, IOException, InvalidKeySpecException, >> NoSuchAlgorithmException { >> File keyFile = new File(privateKeyFile); >> byte[] encodedKey = new byte[(int) keyFile.length()]; >> FileInputStream is = new FileInputStream(keyFile); >> is.read(encodedKey); >> is.close(); >> >> byte[] decryptedKey = decryptPrivateKey(encodedKey, >> password.toCharArray()); >> KeyFactory rSAKeyFactory = KeyFactory.getInstance("RSA"); >> PrivateKey privateKey = rSAKeyFactory.generatePrivate(new >> PKCS8EncodedKeySpec(decryptedKey)); >> return privateKey; >> } >> >> /** >> * Decrypts an encrypted RSA private key >> * >> * @param instream >> * @param password >> * @return >> * @throws InvalidKeyException >> * @throws InvalidAlgorithmParameterException >> * @throws IllegalStateException >> * @throws IllegalBlockSizeException >> * @throws BadPaddingException >> * @throws NoSuchAlgorithmException >> * @throws NoSuchPaddingException >> * @throws InvalidKeySpecException >> * @throws InvalidParameterSpecException >> * @throws IOException if the key is unencrypted >> */ >> public static byte[] decryptPrivateKey(byte[] instream, char[] >> password) throws InvalidKeyException, InvalidAlgorithmParameterException, >> IllegalStateException, >> IllegalBlockSizeException, BadPaddingException, >> NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, >> InvalidParameterSpecException, IOException { >> >> EncryptedPrivateKeyInfo epki = new >> EncryptedPrivateKeyInfo(instream); >> //System.out.println("Encrypted private key info's algorithm >> name is '" + epki.getAlgName() + "'"); >> >> AlgorithmParameters params = epki.getAlgParameters(); >> if (params == null) >> throw new IllegalStateException("The private key info's >> algorithm parameters are (null). The algorithm is probably not supported!"); >> //PBEParameterSpec pbeParams = (PBEParameterSpec) >> (params.getParameterSpec(PBEParameterSpec.class)); >> >> SecretKeyFactory sf = >> SecretKeyFactory.getInstance(epki.getAlgName()); >> PBEKeySpec keySpec = new PBEKeySpec(password); >> Key key = sf.generateSecret(keySpec); >> keySpec.clearPassword(); >> >> byte[] privateKeyInfoStream = null; >> Cipher cipher = Cipher.getInstance(epki.getAlgName()); >> cipher.init(Cipher.DECRYPT_MODE, key, params); >> >> privateKeyInfoStream = cipher.doFinal(epki.getEncryptedData()); >> return privateKeyInfoStream; >> } >> } >> >> Best regards, >> >> Richard A. Sand, CEO >> Skyworth TTG USA, Inc. >> +1 (866) 9-TRIPOD >> http://www.skyworthttg.com/us >> >