126

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 part of a sample SAML from our partner company (asserting party):

<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
 <ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
  <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
  <ds:Reference URI="#_2152811999472b94a0e9644dbc932cc3" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
   <ds:Transforms xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
     <ec:InclusiveNamespaces PrefixList="ds saml samlp xs" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    </ds:Transform>
   </ds:Transforms>
   <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
   <ds:DigestValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">bW1Os7+WykqRt5h0mdv9o3ZF0JI=</ds:DigestValue>
  </ds:Reference>
 </ds:SignedInfo>
 <ds:SignatureValue xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
cgrAN4T/UmobhrkkTi3miiRfbo0Z7aakSZjXuTWlZlu9jDptxPNbOFw8ZbYKZYyuW544wQqgqpnG
gr5GBWILSngURjf2N45/GDv7HMrv/NRMsRMrgVfFsKbcAovQdLAs24O0Q9CH5UdADai1QtDro3jx
nl4x7HaWIo9F8Gp/H1c=
 </ds:SignatureValue>
 <ds:KeyInfo>
  <ds:X509Data>
   <ds:X509Certificate>MIIElzCCA3+gAwIBAgIQNT2i6HKJtCXFUFRB8qYsZjANBgkqhkiG9w0BAQUFADB3MQswCQYDVQQG
    EwJGUjEOMAwGA1UEBxMFUGFyaXMxDDAKBgNVBAoTA3BzYTEgMB4GA1UECxMXY2VydGlmaWNhdGUg
    YXV0aG9yaXRpZXMxKDAmBgNVBAMTH0FDIFBTQSBQZXVnZW90IENpdHJvZW4gUHJvZ3JhbXMwHhcN
    MDkwODE5MDcxNTE4WhcNMTEwODE5MDcxNTE5WjCBhjELMAkGA1UEBhMCZnIxHzAdBgkqhkiG9w0B
    CQEWEHBhc3NleHRAbXBzYS5jb20xGDAWBgoJkiaJk/IsZAEBEwhtZGVtb2IwMDEMMAoGA1UEChMD
    cHNhMREwDwYDVQQLEwhwcm9ncmFtczEbMBkGA1UEAxMSVGVzdCAtIFBBU1NFWFQgREVWMIGfMA0G
    CSqGSIb3DQEBAQUAA4GNADCBiQKBgQCuY1nrepgACvDSTLWk5A1cFOJSwDbl6CWfYp3cNYR0K3YV
    e07MDZn+Rv4jo3SusHVFds+mzKX2f8AeZjkA3Me/0yiS9UpS9LQZu9mnhFlZRhmUlDDoIZxovLXN
    aOv/YHmPeTQMQmJZu5TjqraUq7La1c187AoJuNfpxt227N1vOQIDAQABo4IBkTCCAY0wDgYDVR0P
    AQH/BAQDAgWgMB8GA1UdIwQYMBaAFLceWtTfVeRuVCTDQWkmwO4U01X/MAwGA1UdEwEB/wQCMAAw
    gbYGA1UdIASBrjCBqzCBqAYKKoF6ARfOEAEBBDCBmTBBBggrBgEFBQcCARY1aHR0cDovL3JldW5p
    cy5pbmV0cHNhLmNvbS9hdXRvcml0ZS9QQy1BQy1Qcm9ncmFtcy5wZGYwVAYIKwYBBQUHAgIwSDAK
    FgNwc2EwAwIBARo6UG9saXRpcXVlIGRlIENlcnRpZmljYXRpb24gQUMgUFNBIFBldWdlb3QgQ2l0
    cm9lbiBQcm9ncmFtczBcBgNVHR8EVTBTMFGgT6BNhktodHRwOi8vaW5mb2NlcnQucHNhLXBldWdl
    b3QtY2l0cm9lbi5jb20vQUMtUFNBLVBldWdlb3QtQ2l0cm9lbi1Qcm9ncmFtcy5jcmwwHQYDVR0l
    BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBYGA1UdDgQPBA1BVVRPX0dFTkVSQVRFMA0GCSqGSIb3
    DQEBBQUAA4IBAQCvRtP6bFkOUEHcqc6yUX0Q1Gk2WaAcx4ziUB0tw2GR9I0276JRJR0EGuJ/N6Fn
    3FhLQrSPmS97Xvc9XmiI66fQUdg64g9YqBecdiQlUkR20VLgI6Nq8pldQlWjU2iYlkP15U7VF4Qr
    0Pb2QiIljZUCKdv3qdED2Ri33za46LfykrlwZB0uhTVUxI/AEtjkKVFaZaqanJg+vJyZI5b30z7g
    Ff8L3ht4Z7SFKdmY3IQSGzElIAAUfduzTJX0cwnGSU9D4BJu1BS8hWnYPwhk+nBJ7OFhXdwYQFWq
    fhpBLq+ciJti9OMhcdCSIi0PbrOqzqtX7hZUQOvfShhCTJnl5TJJ</ds:X509Certificate>
  </ds:X509Data>
 </ds:KeyInfo>
</ds:Signature>

What I just don't understand is, why is the certificate within the signature?

I mean usually I get a certificate from the company in a secure kind of way, so I know the certificate is from them. And when the verification of the signature succeeds, I know our partner company has signed it.

But when the certificate is within the signature of the SAML-Response, anyone could have sent it! The only thing I know is that the response hasn't been falsified. But the point is, I have no idea who sent the SAML.

Can anyone explain to me, how that works?

Marc-Andre
  • 912
  • 1
  • 15
  • 34
Dante
  • 1,261
  • 2
  • 9
  • 3
  • 4
    The public key only allows for verification. You can't sign text with the public cert that's included. – AaronF Nov 19 '21 at 23:46

4 Answers4

71

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:

  1. The tamper check is quicker than the identity check, and can be isolated if the public key is known.
  2. Multiple identities are much easier to support if the key is in the assertion.
Marc-Andre
  • 912
  • 1
  • 15
  • 34
Keith
  • 150,284
  • 78
  • 298
  • 434
  • What about encryption part of story? Should IDP encrypt response with SP public key? In that way SP could decrypt incoming response. – svlada Feb 13 '13 at 08:36
  • 3
    @svlada the SAML assertion doesn't need it's own encryption, as the text itself can be sent over SSL - the whole user session should be HTTPS. Given that verification that the known, trusted sender signed the assertion and that it hasn't been tampered with is enough. – Keith Feb 13 '13 at 08:55
  • But in case there is no SSL, messages must be encrypted? – svlada Feb 13 '13 at 09:04
  • 6
    @svlada no HTTP-based authentication (of any kind) should ever be done without SSL. Encrypting the certificate will stop a man in the middle (MitM) from reading it, but it won't stop them from re-using it in a similar way to a cookie based MitM attack. – Keith Feb 13 '13 at 09:45
  • Do you know any resource where I can read more about saml message exchange process and best practices? OASIS standard doesnt talk much about signing messages. The best resource I have found is: https://spaces.internet2.edu/display/InCCollaborate/Metadata+Administration. – svlada Feb 13 '13 at 09:53
  • 10
    SAML responses do **not** require including the public key for that signature. Section 5.4.5 of the SAML2 spec states "XML Signature defines usage of the element. SAML does not require the use of , nor does it impose any restrictions on its use. Therefore, MAY be absent." You can verify the signature if the public key has been provided to you through other means, e.g. stored in your local certificate store prior to implementing the SAML consumer. – Sam Rueby Nov 05 '14 at 16:01
  • 3
    @Sam.Rueby ah, I will correct it. Every implementation I've seen has included the key. – Keith Nov 10 '14 at 10:56
  • 1
    Shouldn't `signNode` by taken from `responseNode` rather than `assertionNode`? I've tested both and only the first one returned true from `CheckSignature`. – jahu Dec 18 '14 at 09:51
  • This answer is confusing as hell. "You need an additional check that the message has come from someone that you trust. Normally this will be a list of public keys that you would accept SAML responses from." - but later: "You could already have the public key, meaning that the signature shouldn't need to include the public key again" - wait. You just said that you will normally have a list of public keys you will accept SAML responses from, so why do you say you COULD already have the public key? Surely you MUST already have the public key. – Jez Feb 06 '15 at 11:57
  • 6
    @Jez this whole protocol is as confusing as hell. Basically the assertion is self contained - you can check that it hasn't been tampered with since the private key signed it. You can do this without having that public key yourself (so I know this assertion has come from Dave, and that nobody has tampered with it since Dave signed it, but I might have no idea who Dave is or whether I can trust him). Then, after verifying that, I can check the public key is one I trust. I think this is because there might be a delay on that final check (while I go ask about the office whether anybody knows Dave) – Keith Feb 12 '15 at 10:13
  • 1
    I think the question was a bit different - anyone can tamper the whole message including their own key and sign the response with it. The answer below is more to the point. – Nikolay Dimitrov Jul 10 '16 at 02:24
  • 2
    @gubble yes, and (assuming that they did it correctly) that message would pass the _tamper check_ but fail the _identity check_ , unless they were someone you trusted too. There are real world cases for that pattern, for instance there might be some kind of proxy that is allowed to change the response (for instance, allowing the NSA to snoop on a private message) but where the client would still accept the new signature. So: this message is signed by Bob and we trust Bob, this other message from Bob was intercepted, redacted and signed by the NSA and we trust them too. – Keith Aug 01 '17 at 10:14
  • Where did GetFirstX509Certificate() method come from? Cannot find it. – vkelman May 30 '18 at 20:39
  • @vkelman see the comment above it - it's just `signedXml.KeyInfo[0].Certificates[0]` but with added casting. – Keith May 30 '18 at 21:23
  • Not understanding the significance of the delay of the identity check if it has to be done anyway. 1. The key in the message can be used to verify the message was not tampered with since it was signed. 2. Ok, but we don't who signed it or if we trust them. 3. So we now have to go look up the public key for who the sender claims to be to either verify the public key matches the one in the message. So why not just look up the public key and validate the signature in the first place if we have to do that in the end either way? Because if it was tampered with, we can skip that and save some work? – xr280xr Jun 22 '20 at 17:08
  • @xr280xr in part because yes, if the message was tampered with we can skip the (more expensive) trusted senders check, but also we probably have _many_ trusted senders (so a lot of public keys to check). You might also have a chain - you don't trust this new sender yet, but you trust some other authority and they trust the new sender (out of a huge database). If you had just one trusted sender (or a pre-agreed unique key for each sender in your DB) you wouldn't need this, but that would be a much narrower solution than SAML is aiming to meet. – Keith Jun 22 '20 at 17:28
65

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.

Govind Rai
  • 14,406
  • 9
  • 72
  • 83
jbindel
  • 5,535
  • 2
  • 25
  • 38
  • 16
    I think this is an important point, that the certificate in the response must match the certificate in the metadata. Otherwise, I could sign the response with whatever certificate I wanted and send its public key for verification. – dana Jun 04 '13 at 19:24
  • 9
    I think this is the best answer, it seems to me the other ones are missing the point that checking the message against the key declared in the message itself isn't giving you any security... You must still check the key in the message is right! (in this case, you must ensure it's in trusted metadata). – Romain Champourlier Jan 29 '15 at 14:59
  • 5
    Totally agree with the above comments - the certificate passed in the message is *worthless* by itself because the whole point of signing is to verify that the message is trustworthy. If the message isn't trustworthy, then nor are the bundled certificates. – Jez Feb 06 '15 at 12:04
  • @jbindel - thank you! I have a newby question if possible: Does this SAML certificate have to match the current physical certificate, or is it only used to achieve a metadata match? I ask this as I am concerned about the operational impact of an IdP rekeying their certificate - at which point presumably it gets out of sync with the metadata key. If the 2 are tied, then I am concerned re. the operational impact ie. that until both SP and IdP have manually updated the SAML2 key, all SSO will fail, and the consequent impact on SSO users if imperfect technical comms. (apologies if stupid question) – Pancho Feb 10 '16 at 11:41
  • The SP metadata must include the certificate, but the SP metadata can specify both the old and new IdP certificates. If the IdP is updating its certificate, then that can be added to the SP metadata. Once the IdP is supposed to be done using the old certificate, you can remove it from the SP metadata. Does that address what you are asking? I know this works perfectly well on Shibboleth SP. The SP metadata file just needs to have `` elements for the IdP certificates that will be accepted by the SP. – jbindel Feb 10 '16 at 15:50
  • @jbindel, could you please tell me if there exists an official SAML documentation directing how the certificate included in a signature should be validated together with certificates in metadata as you summarized as following: > If the key supplied with the signature is not trusted (not specified in the Metadata in this case), then the SAML system must generate an error when validating the signature. – Sam D. Feb 05 '19 at 09:42
  • We, as SP, have currently got a new certificate due to the expiry of the old one, but we forgot to inform one of our IdPs of the new one. The new certificate is really used in the AuthnRequest for signing our SAML request to that IdP, but what surprised me is that the SAML SSO still works as before. The same issue was also observed by [ others] (https://serverfault.com/questions/382966/purpose-of-the-x509-certificate-in-metadata-files-on-the-idp-side-sso-structure) – Sam D. Feb 05 '19 at 09:50
  • @jbindel I updated your answer: I made the metadata example easier to read (It took me a few passes to understand that there was more than one cert specified, so I made the example more compact). I also included more information on being able to trust the cert in the SAML response and a bit more on the metadata file itself which has been mentioned throughout the answer but one may not know what it is/how it relates (it certainly took a while for me to understand the concept). I'd appreciate you verifying my updates as this answer was gold for me and I think there is potential in the updates :) – Govind Rai Sep 08 '20 at 23:59
9

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.

blowdart
  • 55,577
  • 12
  • 114
  • 149
  • 2
    "Without the certificate how could you tell where the token came from, and how could you validate it?" - what are you talking about? In order to trust a signature in a SAML message, you must *already* have a list of trusted public certificates. You could use the `Issuer` element and store that issuer's certificate against that, and pick that certificate against which to check the signature for this message. – Jez Feb 06 '15 at 12:00
  • 2
    Not true at all Jez. You can trust a certificate issuer, like a CA, without having to trust the individual certificates it issues and without having to keep local copies of every certificate. – blowdart Feb 17 '15 at 18:23
  • 5
    blowdart that means you are trusting the saml token signed by any other valid cert issued by CA. It is not impossible to buy one! To ensure your token is coming from the correct source as @Jez mentioned you should already have a list of trusted public certificates. – Sun Jun 19 '15 at 12:03
  • 2
    @Sun, incorrect. That's like saying Wells Fargo can impersonate Bank of America if they have the same CA. An X509 certificate has a Subject DN that can be validated for the correct identity. – Paul Draper May 11 '16 at 22:43
  • +1 especially for identifying that this is part of the XML digital signature specification, something that is less than obvious for a novice and crucial for understanding how the messages are actually processed, as pretty much every SAML implementation relies on an XML library to do the heavy lifting. – BryKKan Apr 04 '19 at 19:10
0

Identity provider signed the saml response using its own private key. and while registration/SAML metadata exchange phase, Both parties share their public key certificate with each other. Any party can have multiple signing certificate and it is free to use one of them. Corresponding public key already shared with relying party so sharing public key in SAML response is just notification(use this certificate while digital verification) to relying party.

Dalip Choudhary
  • 546
  • 5
  • 18