Richard Sand wrote:
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?

But when you are enveloping an existing Document into the Object element, you get yourself into a problem in that you are asking it to insert the Signature at the top of the Document, but also insert the same Document inside the XML Signature Object element. Thus the DOMException is thrown because it is not possible to do that, since it violates the DOM hierarchy. Unless you have some tight memory constraints, I don't see that creating a new Document to hold the signature is a problem ... I assume it will be quickly serialized and sent over the network anyway.

--Sean

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



Reply via email to