.Net: SignedXml - Signing xml with transform algorithm exc-c14n

Mahmoud picture Mahmoud · Dec 6, 2012 · Viewed 9.3k times · Source

I'm trying to sign Xml (actually SOAP xml) in C# using the SignedXml class, the signing stage passes successfully, but when I try to verify the signature it tells me that it is not valid. The only change I have done from the example in MSDN that I used XmlDsigExcC14NTransform instead of the transform XmlDsigEnvelopedSignatureTransform. If I use XmlDsigEnvelopedSignatureTransform I will get a valid signature.

Here is my signing code:

 private static XmlDocument SignXml(XmlDocument doc)
             {
                 SignedXml signedXml = new SignedXml(doc);
                 signedXml.SigningKey = Certificate.PrivateKey;
    
                 Reference reference = new Reference();
                 reference.Uri = "";
                 
                 XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
                 //XmlDsigExcC14NTransform env = new XmlDsigExcC14NTransform();

                 reference.AddTransform(env);
    
                 signedXml.AddReference(reference);
                 signedXml.ComputeSignature();
    
                 XmlElement signature = signedXml.GetXml();
                 doc.DocumentElement.AppendChild(signature);
                 doc.Save(SignedXmlPath);
                 return doc;
             }

The above code will give me a valid signature, but if I use

XmlDsigExcC14NTransform env = new XmlDsigExcC14NTransform();

instead of

XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();

I will get an invalid signature.

Here is my verification code:

private static bool Verify(XmlDocument doc)
        {
            SignedXml signedDoc = new SignedXml(doc);
            XmlNodeList nodeList = doc.GetElementsByTagName(Constants.SignatureElement);

            signedDoc.LoadXml((XmlElement)nodeList[0]);
            return signedDoc.CheckSignature((RSA)Certificate.PublicKey.Key);
        }

Can anyone tell me how can I sign with transform algorithm of http://www.w3.org/2001/10/xml-exc-c14n#

Thanks in advance.

Answer

Jan-Peter Vos picture Jan-Peter Vos · Dec 6, 2012

You are gonna need the XmlDsigEnvelopedSignatureTransform in your case because you are adding the signature inside the element you are signing.

XmlDsigEnvelopedSignatureTransform will tell the SignedXml class to remove the signature from the signature node itself before testing it's validity. This is needed because you added that element after calculating the signature.

You can add more then one transform by calling the AddTransform again like this:

XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
XmlDsigExcC14NTransform c14n = new XmlDsigExcC14NTransform();

reference.AddTransform(env);
reference.AddTransform(c14n);

However i think what you actually want to do instead of my example above is set the CanonicalizationMethod to c14n:

signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/2001/10/xml-exc-c14n#";
 - or - 
signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;