I have a response from a 3-rd party web service. I load an XmlDocument with that response.
string txt = readStream.ReadToEnd();
response = new XmlDocument();
response.PreserveWhitespace = true;
response.LoadXml(txt);
return response;
Now I would like to verify that the respones is signed using the certificate. I have a VerifyXmlDoc(XmlDocument xmlDoc)
method which I have found on msdn.
I know that the message is correct.
public bool VerifyXmlDoc(XmlDocument xmlDoc)
{
SignedXml signed = new SignedXml(xmlDoc);
XmlNodeList signatureNodeList = xmlDoc.GetElementsByTagName("Signature");
signed.LoadXml((XmlElement)signatureNodeList[0]);
X509Certificate2 serviceCertificate = null;
foreach (KeyInfoClause clause in signed.KeyInfo)
{
if (clause is KeyInfoX509Data)
{
if (((KeyInfoX509Data)clause).Certificates.Count > 0)
{
serviceCertificate = (X509Certificate2)((KeyInfoX509Data)clause).Certificates[0];
}
}
}
bool result = signed.CheckSignature(serviceCertificate, true);
return result;
}
If I set target framework of my project to .NET 3.5 or .NET 3, or .NET 2 it works great. Result is true. But if I change target framework to .NET 4 result is false. (And I have to use .NET 4)
Any ideas on how to solve this problem?
I had the same problem but none of those answers helped me. In this case it works or not depending on the operative system I used, not on the .Net version.
I've enabled the SignedXML log by adding this code in the app.config to see what happened behind:
It wrote this particular line:
I found this Microsoft Support article which tries to fix an error introduced by the security update 3141780: https://support.microsoft.com/en-us/kb/3148821
Into that article, in Scenario 2 section, there are 2 solutions, I fixed the problem applying the registry key related to the XPath Transform Method: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft.NETFramework\Security\SafeTransformMethods@XmlDsigXPathTransform=http://www.w3.org/TR/1999/REC-xpath-19991116
In order to check the signature on NET 4.0+ you have to change the context of your CanonicalizationMethod, therefore you have to initialize your signedXml object in the following way:
I solved this problem adding same namespace from Signature tag to SignedInfo. Like this:
Before:
After:
This is a known issue. The Canonicalization implementation between .NET 3.5 and .NET 4.0 has changed.
I don't know if this works on all XML signatures but the following works from the testing that I've done.
Add the following C14N Transform class to your project:
Register the class using the CryptoConfig.AddAlgorithm method.
That should do it.
Try explicitly setting the Canonicalization method for the SignedInfo property of the SignedXml class.. It appears there has been a change in default behaviour here between .Net 2.0 and .Net 4.0
Reference:
This answer