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 >