I have to implement SSO with SAML for my company\'s website (as the relying party). An essential part off course is the verification of the signature. Here is the signature
The reason a public key is specified in the SAML response is because the metadata for an identity provider can specify multiple public keys. This allows the identity provider (asserting party) to specify to the service provider (relying party) the correct public key to use to verify the signature in the SAML response.
For example, the asserting party's Metadata could look like the following:
<KeyDescriptor>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>BQUAMCMBgN...XerfXHHEZYZs=</ds:X509Certificate>
</ds:X509Data>
<ds:X509Data>
<ds:X509Certificate>H24a88h7zl...2zo28hH5DK78=</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</KeyDescriptor>
Although SAML 2.0 does not mandate that the public key be included, I haven't come across any identity providers who do not include the public key in their SAML response. If the public key is not specified with the assertion, then it should be inferable via the identity provider's metadata.
In terms of trusting the public key being sent in the response, the public key must match one that is defined in the identity provider's metadata. These metadata details are usually provided by your customers who want to use SSO to access your application--you will know exactly what public key(s) to be looking for (i.e. you will probably request them to provide you their identity provider's metadata url so you can fetch their metadata and pull down relevant information such as public keys, issuer endpoint, etc).
If the public key supplied with the signature is one that is not specified in the metadata, then the SAML system must generate an error when validating the signature.
The public part of the signing certificate is in the SAML message. This is used to check the signature for the token itself, and of course to allow receivers to tell who issued the token and treat it accordingly.
The fact that it's in there is part of the XML digital signature specs, it's not really anything SAML specific. Without the certificate how could you tell where the token came from, and how could you validate it?
XmlDSig does specify other methods, you can identify the signing key by a subject, serial number, hash etc., but this assumes that the receiving party has the public certificate. For SAML this may not be the case, hence the embedding of the public part of the X509 cert.
SAML responses come with a signature and a public key for that signature.
You can use the public key to verify that the content of the SAML response matches the key - in other words - that response definitely came from someone who has the matching private key to the public key in the message, and the response hasn't been tampered with.
I don't know what tech you're working with, but in .Net you can check it like this:
// load a new XML document
var assertion = new XmlDocument { PreserveWhitespace = true };
assertion.LoadXml("The SAML XML that you were sent");
// use a namespace manager to avoid the worst of xpaths
var ns = new XmlNamespaceManager(assertion.NameTable);
ns.AddNamespace("samlp", @"urn:oasis:names:tc:SAML:2.0:protocol");
ns.AddNamespace("asrt", @"urn:oasis:names:tc:SAML:2.0:assertion");
ns.AddNamespace("dsig", @"http://www.w3.org/2000/09/xmldsig#");
// get nodes down to the signature
var responseNode = assertion.SelectSingleNode("/samlp:Response", ns);
var assertionNode = responseNode.SelectSingleNode("asrt:Assertion", ns);
var signNode = assertionNode.SelectSingleNode("dsig:Signature", ns);
// load the XML signature
var signedXml = new SignedXml(assertion.DocumentElement);
signedXml.LoadXml(signNode as XmlElement);
// get the certificate, basically:
// signedXml.KeyInfo[0].Certificates[0]
// ...but with added casting
var certificate = GetFirstX509Certificate(signedXml);
// check the key and signature match
bool isSigned = signedXml.CheckSignature(certificate, true);
That just checks that the message is from who it says it is. You need an additional check that the message has come from someone that you trust, and this check is slower - it needs to include revocation and may need to verify a whole chain of certificates.
Normally this will be a list of public keys that you would accept SAML responses from.
Then you can check that this message hasn't been tampered with, and is from someone that you trust, so you can authorise the user details supplied in the SAML attributes supplied.
You could already have the public key, meaning that the signature shouldn't need to include the public key again, but you could also have multiple possible known senders, or even a chain of known senders.
For instance you may have two trusted providers - in either case you check that the message has not been tampered with before checking whether you trust either provider. If the key isn't in the signature the assertions can be a little smaller, but now you have to know in advance which identity provider the assertion has come from.
So, really, there are two main reasons that the public key is in the signature: