I\'ve looked at other posts on here regarding this issue and none of them seem to address my situation.
I\'ve been trying to verify a SAML assertion for the last week an
I've spent a lot of time on this issue and then realized that I am not checking the signature with the right certificate.
So I decided to check the certificate I am receiving in the XML response file from Azure:
signedXml.LoadXml((XmlElement)nodeList[0]);
X509Certificate2 serviceCertificate = null;
foreach (KeyInfoClause clause in signedXml.KeyInfo)
{
if (clause is KeyInfoX509Data)
{
if (((KeyInfoX509Data)clause).Certificates.Count > 0)
{
serviceCertificate = (X509Certificate2)((KeyInfoX509Data)clause).Certificates[0];
}
}
}
Then:
bool bTest = signedXml.CheckSignature(serviceCertificate , true);
The bTest
value was finally set to true.
I just had a similar issue and lost a lot of time, maybe this can help someone.
My environment is 100% .Net 4.5, and my code uses only the SignedXml class. But a SAML assertion was accepted at one place and refused at another one.
Turned out that one place was loading the assertion through an XmlDocument instance initialized with PreserveWhitespace = true
, while the other one was not.
And the assertion had been pretty-printed, so it had carriage returns and a lot of indentation spaces. Removing all carriage returns and the indentation spaces fixed my issue.
I dealt with signed XML's a lot in the past. All I can say is that it was a nightmare. Basically, when you sign XML, it goes through a process called canonicalization (C14N). It needs to turn XML text to a byte stream which can be signed. Whitespace & namespace handling, among others, in XML C14N standards are hard to understand, even harder to implement right. There are even multiple types of C14N.
The .NET implementation is very selective about what it accepts. It's quite possible that your other implementation doesn't work in the exact same way as the .NET one. This is very sad indeed. If you can eliminate whitespace and namespaces from your source XML before signing, for example, that could help. Also if you could make sure that both implementations use the same C14N settings.
Otherwise a lot of debugging awaits you. You could debug into the framework, or call its internal methods by hand with reflection, to see how it calculates the XML fragment and the signature. And do the same with the other implementation. Basically you need to see the exact byte streams that are signed in both cases. This is the final step of the conversion before signing. If those byte streams match, then you'll have no problems with the RSA signing part in my experience. If those don't match, as is in your case, at least you'll see where the problem is.
Had a similar issue with Saml as Timores. The Saml needed to be decoded from Base64 but first i used:
var saml = System.Text.Encoding.Default.GetString(Convert.FromBase64String(samlToken))
But this used ASCII decoding and had trouble with special characters. Which means the XML was slightly different from when it was signed and that is why it failed. Changed it to:
var saml = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(samlToken))
and it worked for all cases.
So be sure that you are using the right encoding!