santuario-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Richard Sand" <Richard.S...@skyworthttg.com>
Subject RE: problem enveloping a soap body
Date Wed, 08 Oct 2008 14:06:47 GMT
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: Sean.Mullan@Sun.COM [mailto:Sean.Mullan@Sun.COM] 
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
> 

Mime
View raw message