SAML: Why is the certificate within the Signature?

前端 未结 3 1620
南笙
南笙 2020-11-30 18:01

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

相关标签:
3条回答
  • 2020-11-30 18:43

    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.

    0 讨论(0)
  • 2020-11-30 18:55

    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.

    0 讨论(0)
  • 2020-11-30 19:00

    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.
    0 讨论(0)
提交回复
热议问题