Can't figure out why SAMLMessageSignature.Verify is returning false

I have setup one of our cleint as an IdP, using their SSL public key. They are using their private key to sign SAML responses. The message signature verification always returns false, even when I copy their cert to file directory to test directory and load that as a X509Certificate2 object, passing that in:
bool retVal = SAMLMessageSignature.Verify(samlResponseXml, x509Certificate); // is false
It even returns false when I pass no second param in, using the key info included with the signature to perform the verification:
bool retVal = SAMLMessageSignature.Verify(samlResponseXml); // is false
I can’t figure out why this verification is failing. I’ve uploaded a SAML response that is posted back from Shibboleth (formatted by FOXE but otherwise unchanged) here:
<urn:Response Version=“2.0”
ID=“P.m.dCCjsJZYqvkpkWYTK0jOM.t”
IssueInstant=“2016-07-08T20:53:10.137Z”
InResponseTo=“_fea56162-69f5-411f-8674-b3b2ac175c85”
xmlns:urn=“urn:oasis:names:tc:SAML:2.0:protocol”
>
<urn1:Issuer xmlns:urn1=“urn:oasis:names:tc:SAML:2.0:assertion”>https://XXX.com</urn1:Issuer>
urn:Status
<urn:StatusCode Value=“urn:oasis:names:tc:SAML:2.0:status:Success” />
</urn:Status>
<saml:Assertion ID=“LUQbxc2wXL1vSfN7oT7X4CLvmjj”
IssueInstant=“2016-07-08T20:53:10.225Z”
Version=“2.0”
xmlns:saml=“urn:oasis:names:tc:SAML:2.0:assertion”
>
saml:Issuerhttps://XXX.com</saml:Issuer>
<ds:Signature xmlns:ds=“”>http://www.w3.org/2000/09/xmldsig#“>
ds:SignedInfo
<ds:CanonicalizationMethod Algorithm=”<a href=“http://www.w3.org/2001/10/xml-exc-c14n#”“>http://www.w3.org/2001/10/xml-exc-c14n#” />
<ds:SignatureMethod Algorithm=“<a href=“http://www.w3.org/2000/09/xmldsig#rsa-sha1"”>http://www.w3.org/2000/09/xmldsig#rsa-sha1” />
<ds:Reference URI=“#LUQbxc2wXL1vSfN7oT7X4CLvmjj”>
ds:Transforms
<ds:Transform Algorithm=“<a href=“http://www.w3.org/2000/09/xmldsig#enveloped-signature””>http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<ds:Transform Algorithm=“<a href=“http://www.w3.org/2001/10/xml-exc-c14n#””>http://www.w3.org/2001/10/xml-exc-c14n#“ />
</ds:Transforms>
<ds:DigestMethod Algorithm=”<a href=“http://www.w3.org/2000/09/xmldsig#sha1"”>http://www.w3.org/2000/09/xmldsig#sha1" />
ds:DigestValueode76HiV7wV8cvLQP0lgai435+Y=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
ds:SignatureValue
XXXXXXXXXX
</ds:SignatureValue>
ds:KeyInfo
ds:X509Data
ds:X509Certificate
XXXXXXXXXX
</ds:X509Certificate>
</ds:X509Data>
ds:KeyValue
ds:RSAKeyValue
ds:Modulus
XXXXXXXXXX
</ds:Modulus>
ds:ExponentAQAB</ds:Exponent>
</ds:RSAKeyValue>
</ds:KeyValue>
</ds:KeyInfo>
</ds:Signature>
saml:Subject
<saml:NameID Format=“urn:oasis:names:tc:SAML:2.0:nameid-format:entity”>43569</saml:NameID>
<saml:SubjectConfirmation Method=“urn:oasis:names:tc:SAML:2.0:cm:bearer”>
<saml:SubjectConfirmationData Recipient=“<a href=“https://XXX.com/ssosp/saml2/post/loggedin””>https://XXX.com/ssosp/saml2/post/loggedin"
NotOnOrAfter=“2016-07-08T20:58:10.226Z”
InResponseTo=“_fea56162-69f5-411f-8674-b3b2ac175c85”
/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore=“2016-07-08T20:48:10.226Z”
NotOnOrAfter=“2016-07-08T20:58:10.226Z”
>
saml:AudienceRestriction
saml:Audiencehttps://XXX.com/ssosp/</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement SessionIndex=“LUQbxc2wXL1vSfN7oT7X4CLvmjj”
AuthnInstant=“2016-07-08T20:53:10.225Z”
>
saml:AuthnContext
saml:AuthnContextClassRefurn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
saml:AttributeStatement
<saml:Attribute Name=“Email”
NameFormat=“urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified”
>
<saml:AttributeValue xsi:type=“xs:string”
xmlns:xs=“<a href=“http://www.w3.org/2001/XMLSchema””>http://www.w3.org/2001/XMLSchema"
xmlns:xsi=“<a href=“http://www.w3.org/2001/XMLSchema-instance””>http://www.w3.org/2001/XMLSchema-instance"
>steve.smith@XXX.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name=“Last Name”
NameFormat=“urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified”
>
<saml:AttributeValue xsi:type=“xs:string”
xmlns:xs=“<a href=“http://www.w3.org/2001/XMLSchema””>http://www.w3.org/2001/XMLSchema"
xmlns:xsi=“<a href=“http://www.w3.org/2001/XMLSchema-instance””>http://www.w3.org/2001/XMLSchema-instance"
>Smith</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name=“First Name”
NameFormat=“urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified”
>
<saml:AttributeValue xsi:type=“xs:string”
xmlns:xs=“<a href=“http://www.w3.org/2001/XMLSchema””>http://www.w3.org/2001/XMLSchema"
xmlns:xsi=“<a href=“http://www.w3.org/2001/XMLSchema-instance””>http://www.w3.org/2001/XMLSchema-instance"
>Steve</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</urn:Response>

Can anyone tell me why the Verify method might always be returning false?
I can’t figure out why this verification is failing. Can anyone tell me why Verify might always be returning false?

Thanks!!!

How did you set the samlResponseXml parameter?
Was it returned by one of our APIs or did you load it from a file?
Could you include a section of your code showing how samlResponseXml is set?
If you load it from a file etc then use must ensure XmlDocument.PreserveWhitespace is set to true to ensure the .NET API doesn’t format the XML.
If you’re receiving the XML through our API, please enable SAML trace and send the generated log file as an email attachment to our support email mentioning your forum post.
http://www.componentspace.com/Forums/17/Enabing-SAML-Trace

[quote]
ComponentSpace - Tuesday, August 2, 2016
How did you set the samlResponseXml parameter?
Was it returned by one of our APIs or did you load it from a file?
Could you include a section of your code showing how samlResponseXml is set?
If you load it from a file etc then use must ensure Xmldocument.PreserveWhitespace is set to true to ensure the .NET API doesn't format the XML.
If you're receiving the XML through our API, please enable SAML trace and send the generated log file as an email attachment to our support email mentioning your forum post.
http://www.componentspace.com/Forums/17/Enabing-SAML-Trace
[/quote]

Client captured response using SAML tracer. I saved that response as XML file and used below code to validate.

XmlDocument samalResponse = new XmlDocument();
samalResponse.PreserveWhitespace = false;
samalResponse.Load(samlResponseFilePath);

//Get the response xml
XmlElement responseXml = samalResponse.DocumentElement;
SAMLResponse response = new SAMLResponse(responseXml);
XmlElement assertionXml = (XmlElement)response.Assertions[0];

X509Certificate2 x509Certificate = new X509Certificate2();
//make sure it exists
if (File.Exists(sslCertFilePath))
{
x509Certificate = new X509Certificate2(sslCertFilePath, sslCertPassword, X509KeyStorageFlags.MachineKeySet);
}

bool isSigned = SAMLAssertionSignature.IsSigned(assertionXml);
Console.WriteLine(isSigned); //This is returned as TRUE

bool isValidMessageSignature = SAMLMessageSignature.Verify(assertionXml);
Console.WriteLine(isValidMessageSignature); //This is returned as FALSE

bool isValidAssertionSignature = SAMLAssertionSignature.Verify(assertionXml, x509Certificate);
Console.WriteLine(isValidAssertionSignature ); //This is returned as FALSE


I used below code to check if assertion as valid cert or not and it worked and showed me that cert that I have is the same cert signed in response.

X509Certificate2 responsecert = SAMLMessageSignature.GetCertificate(assertionXml);
bool result = x509Certificate.Equals(responsecert);
Console.WriteLine(result); //This is returned as TRUE



You need to set PreserveWhitespace to true.
If you don’t then the signature will be invalidated by the whitespace formatting characters adding by the .NET framework.

[quote]
ComponentSpace - Tuesday, August 2, 2016
You need to set PreserveWhitespace to true.
If you don't then the signature will be invalidated by the whitespace formatting characters adding by the .NET framework.
[/quote]

I did this and still same result. Only IsSigned is TRUE

It may be that the XML in the file has been modified after signing.
If you’d like to send the XML file as an email attachment to our support I can take a look.

[quote]
ComponentSpace - Tuesday, August 2, 2016
It may be that the XML in the file has been modified after signing.
If you'd like to send the XML file as an email attachment to our support I can take a look.
[/quote]

Could you please let me know the email address?

support@componentspace.com

[quote]
ComponentSpace - Tuesday, August 2, 2016
[/quote]

I just emailed you the XML file.

Thank you

Thanks.
If you open the file in Notepad you’ll see it includes formatting (ie whitespace characters such as new lines and indentation).
This is perfectly valid as long as this formatting occurred prior to signing.
Typically when we see formatting and signature failure it’s because the formatting occurred after signing. These whitespace characters will affect the XML signature.
I recommend checking with the client to see if they can supply a version without formatting and whose signature will verify.
For example, it would be better to capture the base-64 encoded SAMLResponse string and decode this to XML.
The SAML tracer they’re using mustn’t be preserving whitespace characters.

[quote]
ComponentSpace - Tuesday, August 2, 2016
Thanks.
If you open the file in Notepad you'll see it includes formatting (ie whitespace characters such as new lines and indentation).
This is perfectly valid as long as this formatting occurred prior to signing.
Typically when we see formatting and signature failure it's because the formatting occurred after signing. These whitespace characters will affect the XML signature.
I recommend checking with the client to see if they can supply a version without formatting and whose signature will verify.
For example, it would be better to capture the base-64 encoded SAMLResponse string and decode this to XML.
The SAML tracer they're using mustn't be preserving whitespace characters.
[/quote]

I am doing following in code. Currently I am not setting "PreserveWhitespace" to "true" I will add that and see if it works. I am also logging decoded response, so I will take that and run it through my console app and see what the outcome is. Let me know if you see any issue in this code.

public ActionResult LoggedIn(FormCollection formCollection)
{
//Get the response
string response = formCollection["SamlResponse"];
string state = formCollection["RelayState"];

state = Base64Encoder.Decode(state.Replace(" ", "+"), Encoding.UTF8);
response = Base64Encoder.Decode(response, Encoding.UTF8);

this._logger.Info("Decoded the POST response form data. SamlResponse: {0} RelayState: {1}", response, state);

XmlDocument doc = new XmlDocument();

//Load the xml
doc.LoadXml(samlResponse);

You’ll need to set XmlDocument.PreserveWhitespace to true.
If you’re receiving an HTTP Post with the SAMLResponse and still have issues, please enable SAML trace and send the generated log file as an email attachment to support.
That way I can check the SAML response being received and whether the XML signature verifies.

[quote]
ComponentSpace - Tuesday, August 2, 2016
You'll need to set Xmldocument.PreserveWhitespace to true.
If you're receiving an HTTP Post with the SAMLResponse and still have issues, please enable SAML trace and send the generated log file as an email attachment to support.
That way I can check the SAML response being received and whether the XML signature verifies.
[/quote]

This fixed my issue.

Thank you

Thanks for the update. I’m glad that resolved the issue.