We have been dealing with a "Signed XML" project for a while.We are required to send and receive SOAP messages by signing and veryfiying the XML documents by XAdes-T format. We are also required to use Enveloped XML Signing format. Here is my XML:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-SEC="http://schemas.xmlsoap.org/soap/security/2000-12">
<s:Header>
<SOAP-SEC:Signature>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="#SignedSoapBodyContent">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>1ZUrFu2GIYqMMKvO62NM8vapTxk=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>...</SignatureValue>
<KeyInfo>
.
. =>All the relevant parts
.
</KeyInfo>
<Object>
.
. =>All the relevant parts
.
</Object>
<Signature>
<SOAP-SEC:Signature>
</s:Header>
<s:Body SOAP-SEC:id="SignedSoapBodyContent">
<MainTag xmlns="http://...">
<A>.........</A>
<B>.........</B>
</MainTag >
</s:Body>
</s:Envelope>
So as to find the DigestValue referenced in Reference URI tag,we are required to first apply the "XmlDsigEnvelopedSignatureTransform" transform algorithm to the body node and then get the hash value to put it into the digest value. The problem is that whatever i tried the digest value has not become to be the true value as it has to be!! What i did Is below and i asked 2 questions below,can u please at least help with this:
private byte[] TransformAndGetHash(XmlDocument xDocin)
{
//xDocin is my whole SOAP message , i am taking only the body part
XmlNode bodyNode = xDocin.SelectSingleNode("/*/*[local-name() = 'Body']");
//Loading the outer XML into an XML document => (2 QUESTIONS: 1)HERE SHOULD I LOAD THE INNER XML?, 2)WHEN WE GET THE BODY NODE OUT NAMESPACES COME AS WELL,IS IT OK?
XmlDocument xml2LoadInEnv = new XmlDocument();
xDoc.PreserveWhitespace = true;
xml2LoadInEnv.LoadXml(bodyNode.OuterXml);
//Creating the enveloped signature transform object and applying it to the xml2LoadInEnv Document
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
env.Algorithm = SignedXml.XmlDsigEnvelopedSignatureTransformUrl;
env.LoadInput(xml2LoadInEnv);
//Getting the putput of the document after transform:
xDoc= (XmlDocument)env.GetOutput(typeof(XmlDocument));
string output = xDoc.OuterXml
//Getting the hash and converting it to base64 string to reach the DIGEST VALUE
byte[] dataToBeHashed = Encoding.GetEncoding(1254).GetBytes(output);
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] hashedData = sha.ComputeHash(dataToBeHashed);
string digestValue = Convert.ToBase64String(hashedData);
}
Post by IguanaHi!
How can i calculate DigestValue for Reference to signature ( ...
uri="#signatureId" ...)?
xmlElement - signature from xml file;
SignedXml signature = new SignedXml();
signature.LoadXml((XmlElement)xmlElement);
Transform t = new
System.Security.Cryptography.Xml.XmlDsigC14NTransform();
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.LoadXml(signature.GetXml().OuterXml);
System.IO.Stream s = null;
t.LoadInput(doc);
SHA1 sha1 = SHA1.Create();
byte[] digestValue = t.GetDigestedOutput(sha1);
MessageBox.Show(Convert.ToBase64String(digestValue));
Calculated digestValue is not the same, which is in reference
digestValue in countersignature after signing.
Can anyone help me calculate this digestValue?
Iguana
Post by Valery PryamikovHi,
are you verifying signature created with .Net or with some other
framework?
the reason I'm asking is that .Net XmlDsigC14NTransform class is not
conformant.
If signature was created with .Net (same version), then you should not
have any problems, however
if this is other thirdparty library that creates signature, then you
may have problems.
According to spec. all whitespaces, significant or not, must be
preserved during serialization.
All open source or Java implementations of XML signatures follows this
rule and preserve all witespaces.
However .Net XmlDsigC14Transform never preservers insignificant
whitespaces, because no Microsoft
XML API reports insignificant whitespaces to the XML processors.
It is easy to check if you are experiencing this problem. Check if
input contains insignificant
whitespaces, and if it does, then it probably it.
-Valery.
Post by Valery PryamikovAnother problem with your code could be the use of OuterXml in case if
it also returns xml header (ie. <?xml version...).
In that case you'll have problems verifying signature created anywhere
- you are trying to verify hash of child node and that can never
contain xml header which is only alllowed to be placed before
rootElement.
-Valery.
Post by IguanaHi!
I have create signatures with csharp (vc 2005) and net 2.0.
I think preserwe white spaces is not a problem in my code - this works
fine (with my code I verify signature have generated in java -
verification works good).
read from xml document all tag <Signature ... </Signature> and put
this to new XmlDocument.
// get signature to countersign
XmlNodeList signs =
existingXmlDocument.GetElementsByTagName("Signature",
SignedXml.XmlDsigNamespaceUrl);
XmlElement el = signs[0]; // in my test code I have only one signature
to countersign
SignedXml sig = new SignedXml();
sig.LoadXml((XmlElement)el);
XmlDocument doc = new XmlDocument(); //new empty xmlDocument - without
header and any attributes
doc.PreserveWhitespace = true;
// load obj - sognature to countersign to new created XmlDocument
System.Security.Cryptography.Xml.DataObject obj = new
System.Security.Cryptography.Xml.DataObject();
obj.LoadXml(sig.GetXml());
doc.LoadXml(obj.GetXml().OuterXml); // this load to new created
XmlDocument signature xml text
Transform t1 = new
System.Security.Cryptography.Xml.XmlDsigC14NTransform(); // my
reference have not transforms - only SignedINfo have connonicalization
transform
t1.LoadInput(doc);
System.IO.Stream s1 = (System.IO.Stream)t1.GetOutput();
// calculate hash after transform
SHA1 sha1 = SHA1.Create();
MessageBox.Show(string.Format("{0}",
Convert.ToBase64String(sha1.ComputeHash(s1))));
This is my first test
Transform t2 = (Transform)CryptoConfig.CreateFromName("http://
www.w3.org/2001/10/xml-exc-c14n#WithComments");
t2.LoadInput(t1); // transform on transformed signature
System.IO.Stream s2 = (System.IO.Stream)t2.GetOutput();
MessageBox.Show(string.Format("{0}",
Convert.ToBase64String(sha1.ComputeHash(s2))));
This is what i do.
DigestValue is wrong (in code with two transformation - I have
DigestValue on t1 and t2 the same always!)
I have no more idea... but must calculate this DigestValue before i
call SignedXml.ComputeSignature and show DigestValue to my application
user.
Any other idea?
Iguana
Post by Valery PryamikovAs i told you in one of my prev. letters - check what you get from
OuterXml. It will most probably give you xml header as well.
-Valery
Submitted via EggHeadCafe
SQL Server Best Practices
http://www.eggheadcafe.com/tutorials/aspnet/56efb426-550b-48cc-b52a-eca25b6cd427/sql-server-best-practices.aspx