SAML Signature verification failed

25,272

Solution 1

This worked when we didn't decode the base64 encoded SAML generated but directly tried to validate it. However, still not sure why the ComponentSpace methods reported differently for the decoded string.

Solution 2

I know this is an old post, but I ran into the same issue and was dissatisfied with the non-answer. For those who are running into this issue and find this page from an internet search as being one of the only results for failed signature validation of Salesforce SAML using ComponentSpace, the issue likely isn't within SAML signature verification itself, but how you're decoding the base-64 encoded SAML Response payload.

Note that the SAMLServiceProvider.ReceiveSSO() method that takes an HttpRequest does not suffer from this issue. I've found that it's specifically when manually decoding the payload that can trigger this issue, depending on the format of the XML when the IdP signed the response.

Since this is an older post and the pastebin link is long gone, let's assume that the original code might have looked like the following. (Also assuming that the X.509 cert is embedded in the payload, but the fix is ultimately the same.)

var str = Encoding.UTF8.GetString(Convert.FromBase64String(samlResponse));
XmlDocument xdoc = new XmlDocument();
xdoc.LoadXml(str);
var xcert = SAMLMessageSignature.GetCertificate(xdoc.DocumentElement);
var isSigned = SAMLMessageSignature.IsSigned(xdoc.DocumentElement);
var isValid = SAMLResponse.IsValid(xdoc.DocumentElement);
var isVerified = SAMLMessageSignature.Verify(xdoc.DocumentElement);

In the case of Salesforce (and likely others), xcert will be non-null, isSigned and isValid set to true, but isVerified will be false. The simple, elusive fix for the above code? xdoc.PreserveWhitespace = true;

The reason is because the signature is generated based on the raw XML structure (or some sub-section of it). If the IdP has whitespaces in their original SAML XML it is included in the signature generation, even if whitespaces can normally be ignored in an XML. This is why IsValid will still return true, while the signature verification fails.

One last handy note, buried in ComponentSpace's sample code, the full safe XmlDocument conversion is:

XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
xmlReaderSettings.DtdProcessing = DtdProcessing.Ignore;
xmlReaderSettings.XmlResolver = null;

XmlDocument xmlDocument = new XmlDocument();
xmlDocument.PreserveWhitespace = true;
xmlDocument.XmlResolver = null;

using (XmlReader xmlReader = XmlReader.Create(new StreamReader(fileName), xmlReaderSettings))
{
    xmlDocument.Load(xmlReader);
}

For our scenario, we didn't need to include the DtdProcessing.Ignore in the extra step of using XmlReaderSettings, but including it in this solution to cover all use cases.

Solution 3

An XML signature verification fails either because the XML has been modified after signing or the wrong certificate is being used to verify the signature. The most likely scenario is that the wrong certificate is being used.

Salesforce signs the SAML response using their private key. Using the Salesforce admin console you can download the corresponding public key/certificate which should be used to perform the signature verification.

When calling SAMLMessageSignature.Verify, you can specify the X509Certificate to use to perform the verification which is typically what you should do.

However, the base-64 encoded X.509 certificate is also embedded in the XML signature. You can use this embedded certificate to check whether the signature verifies.

To do this, don't pass in an X509Certificate to SAMLMessageSignature.Verify.

For example: SAMLMessageSignature.Verify(samlXml, null);

If that works but specifying a certificate down't work then this confirms that the wrong certificate is being used.

You can call SAMLMessageSignature.GetCertificate to retrieve the X.509 certificate from the XML signature to compare it with the certificate being used.

Also, as a side note, XML signatures apply to XML. They cannot be directly verified using the base-64 encoded SAML response sent in the HTTP Post data. The post data must be decoded to XML prior to attempting to verify the XML signature.

Share:
25,272
Vid L
Author by

Vid L

Salesforce.com wannabe architect. Full-time husband. I do coding and other technical stuff for a living. I love to talk and think philosophy

Updated on July 09, 2022

Comments

  • Vid L
    Vid L almost 2 years

    Our IdP is a Salesforce.com org. The SP is a third party .Net application. During development, the 3rd party reported that they're unable to validate the SAML response sent.

    We decided to try validating on our end using ComponentSpace to validate the SAML response. Below is what we tried:

    // Load the certificate from the file: certInFile
    // Load the SAML in an XMLElement: samlXml
    // Retrieve the certificate from the SAML: certInSaml
    
    Console.WriteLine("SAML is valid ? " + SAMLResponse.IsValid(samlXml));
    Console.WriteLine("Is SAML signed? " + SAMLMessageSignature.IsSigned(samlXml));
    Console.WriteLine("Certificate found in SAML is same as certificate file? " + certInFile.Equals(certInSaml));
    Console.WriteLine("Validated SAML with certificate found in SAML" + SAMLMessageSignature.Verify(samlXml, certInSaml));
    Console.WriteLine("Validated SAML with certificate file" + SAMLMessageSignature.Verify(samlXml, certInFile));
    

    I'm getting true for everything above, except the last two. So:

    1. The SAML is valid
    2. The SAML has a valid signature
    3. The public key certificate in the SAML is the same as the certificate file we have
    4. The SAML is signed with the private key of neither the certificate file nor the public key sent in the SAML

    From 3,4 can we conclude that Salesforce is signing but with a different certificate but sending the wrong public key in the response?!

    Edit: Sample SAML is here http://pastebin.com/J8FTxnhJ

    What am I missing?

  • friggle
    friggle over 10 years
    With what method did you "directly try to validate it"? SAMLMessageSignature.Verify() only accepts an XmlElement.
  • MLowijs
    MLowijs over 9 years
    I'd like to know this too. Some online services validate my base64 encoded data perfectly fine but the ComponentSpace toolkit only seems to be able to validate XmlElements.
  • truongnm
    truongnm over 4 years
    I got an error on signature validation too. Thanks so much for your hint about white space. I modified the original SAML Response (reindent, pretifier) and the result is that signature got wrong. So newline, and whitespace does matter