SAML: Why is the certificate within the Signature? - certificate

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?

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:
The tamper check is quicker than the identity check, and can be isolated if the public key is known.
Multiple identities are much easier to support if the key is in the assertion.

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.

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.

Related

How to set the KeyIdentifier in the SecurityTokenReference to the Assertion ID with WSS4j

I'm a bit of a Noob with WSS4J so I'm hoping I'm missing something simple. I'm trying to create a Security header for an outbound SOAP message using WSS4j and CXF. As per the requirements the Assertion and the Timestamp have to be signed. The Assertion is done in a SAMLCallback and the Timestamp with the properties for the WSS4JOutInterceptor. All of that is straight forward. The hitch is instead of embedding the KeyInfo information for the Timestamp signature in the Signature, I need to reference the Assertion, which has the KeyInfo for it's Signature within it. So the Signature for the Timestamp's KeyInfo should look like this:
<ds:KeyInfo>
<wsse:SecurityTokenReference TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0">
<wsse:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID">3a4edd62-458e-4c3f-adc0-a9b505cb6284</wsse:KeyIdentifier>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
Note how the KeyIdentifier points to and ID which is the ID of the Assertion. I've tried all the different WSHandlerConstants.SIG_KEY_ID options for the WSS4JOutInterceptor but all of them populate the KeyInfo element with the information from the certificate. I'm hoping there is some straightforward solution within the WSS4J framework for this. Otherwise I'm looking at writing an interceptor to hack up the SOAP header.
Thanks In Advance.
Yes it's possible, here's a test I pushed to CXF to show how it can be done:
https://github.com/apache/cxf/commit/5504cad08be5f2eb8396410618da68cb732b80e0

Securing OpenSecureChannel messages and X509IdentityToken?

Kindly clarify on the following queries about the OPC UA specification Part 4 Services,
From my understanding after the GetEndpoints Service messages, the client sends a OpenSecureChannel request to the server which means the request is signed or signed & encrypted according the security policy in the desired endpoint. I saw the following lines in the specification Part 4 Services, pg.no 33,
The OpenSecureChannel request and response Messages shall be signed
with the sender’s Certificate. These Messages shall always be
encrypted. If the transport layer does not provide encryption, then
these Messages shall be encrypted with the receiver’s Certificate.
In this it is mentioned that the messages shall always be encrypted. How does it rely on transport layer ?
And I also see another description in the OPC Unified Architecture Book by Wolfgang Mahnke, Stefan-Helmut Leitner, Matthias Damm as follows,
If the certificate is considered as trustworthy, then as the second
step an OpenSecureChannel request secured in accordance to the
Security Policy and the Security Mode is sent to the selected Session
Endpoint of the server. (Chapter 7, pg.no:213)
Here, it highlights that the message is secured in accordance to the Security Policy and Security Mode, so I request a clarification on the scenario if the security mode is sign?
Will the message be encrypted also?
In general, when the MessageSecurityMode is None then the SecurityPolicy ‘must’ be None? What is the exact usage of 'Invalid' MessageSecurityMode?
X509IdentityToken specification Part 4 Services section 7.35.4
This token shall always be accompanied by a signature in the
userTokenSignature parameter of ActivateSession if required by the
SecurityPolicy. The Server should specify a SecurityPolicy for the
UserTokenPolicy if the SecureChannel has a SecurityPolicy of None.
In the first line it is mentioned that ‘if required by the SecurityPolicy’, what is context of ‘if required’ when the userTokenSignature is a required field for X509IdentityToken ? In the second line it is mentioned that a explicit Security Policy is required if the SecureChannel has a SecurityPolicy of None, where ‘None’ means no certificates are exchanged and so X509IdentityToken cannot be used, referring to the following lines in the same specification (Section 5.6.3 ActivateSession, pg.no: 40)?
If the token is an X509IdentityToken then the proof is a signature
generated with private key associated with the Certificate. The data
to sign is created by appending the last serverNonce to the
serverCertificate specified in the CreateSession response.
For your kind information I use the specification released on November 2015 to study. Please clarify.
For the first question, the specification continues with "These requirements for OpenSecureChannel only apply if the securityPolicyUri is not None". So the answer is that a SecureChannel will both sign and encrypt the OpenSecureChannelRequest/Response for any MessageSecurityMode, except MessageSecurityMode.None.
For the second question, if MessageSecurityMode is None, then the Security policy is none. There is no usage of MessageSecurityMode.Invalid as far as I can find.
For the third question, if the securityPolicyUri is None, then no application certificates are exchanged. The client can provide a UserIdentity by a X509IdentityToken. The token consists of a X509Certificate and a signature. The signature is generated by appending the server nonce to the server certificate and signing with the user certificate's private key.

IDP Initialized SSO, how to configure when dont have the pwd for PrivateKey

I am using spring-security saml extension to implement the IDP initiated SSO for my application. I am using https protocol and signature/encryption is ON. I dont need SLO/SP-Initiated SSO.
On the transport layer's encryption/decryption (because using HTTPS protocol), I am fine as My web container (SP one) is going to take care of the decryption part. And this certificate could be different then SP's certifiate.
At the SP end, I need the IDP's public key to verify the signature on SAMLAuthResponse Msg, which I have as part of the IDP's metadata file...so no issues here.
Couple of qns:
For decryption of the SAMLAuthResponse Msg, Do I need SP's
certificate's private key?
And If I need the private key, how to
create the bean definition for keyManager when I have the jks file,
jks-pwd, alias, but no pwd for privatekey? Can I pass the empty string (as "") in the password field in the alias-password value pair.
You can skip usage of private key in this case. You can find detail on how to use Spring SAML without keystore in the manual chapter 8.1:
In case your application doesn't need to create digital signatures
and/or decrypt incoming messages, it is possible to use an empty
implementation of the keystore which doesn't require any JKS file -
org.springframework.security.saml.key.EmptyKeyManager. This can be the
case for example when using only IDP-Initialized single sign-on.
Please note that when using the EmptyKeyManager some of Spring SAML
features will be unavailable. This includes at least SP-initialized
Single Sign-on, Single Logout, usage of additional keys in
ExtendedMetadata and verification of metadata signatures. Use the
following bean in order to initialize the EmptyKeyManager:
<bean id="keyManager" class="org.springframework.security.saml.key.EmptyKeyManager"/>

Adding SOAP implicit headers to WSDL

My question is similar to this. How To Pass Soap Header When WSDL Doesn't Define It? But is different.
For a web service I use, all methods need authentication which is sent in cleartext inside a SOAP header. However, my WSDL doesn't include any soap header information. I have a custom platform tool which I must use to generate code from the WSDL. Since the header info is not available, am unable to use the generated class directly - I do not want to manually modify the code to accommodate the header.
I tried specifying the SOAP header in the WSDL but I failed to get the correct namespaces. The WSDL is here https://stage.totalcheck.sensis.com.au/service/webservice?wsdl and the SOAP header is as follows:
<soapenv:Header>
<wsse:Security>
<wsse:UsernameToken>
<wsse:Username>username</wsse:Username>
<wsse:Password>password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
Can someone help me? Thanks!
From a conceptual point of view, WSDL is not supposed to define headers. WSDL is only for defining the functional aspects of a service, like operations, messages, binding and endpoints. Messages and bindings define how the payload of messages should be encoded and formatted.
The headers of SOAP messages however do not belong to the payload. They are typically used for configuring non-functional properties of a SOAP processor. Security is such a non-functional property. The functional aspect of the payload is not affected. It is only assured that the communication is secured and the WS tool stack, not the service implementation, should take care of that.
So the missing piece is now a standard that allows for attaching some non-functional requirements to WSDL services, so that code generators can automatically derive which headers need to be sent and/or understand in order to fulfill the non-functional property as desired -- without having to manually deal with header fields. This standard exists and is called WS-Policy. A policy contains typically a set of alternatives that expose a set of requirements that both, provider and consumer should be able to fulfill. When two services are supposed to interact with each other, both policies are taken and a so called "effective policy" is calculated. It defines the common non-functional requirements. Using this information, provider and consumer can configure themselves to add required headers, like the WS-Security headers. WS-SecurityPolicy also defines a set of policies that can be used. WS-PolicyAttachment defines how such policies can be attached to a WSDL.
There are code generators that can deal with WS-Policies, e.g. Metro or Axis2
You can add soap header information to method calls by decorating the methods in the proxy class generated from the wsdl with the SoapHeader attribute.
For example wsdl.exe will generate client proxy class Reference.cs for the web service reference when you "Add Web Reference". In the link mentioned above https://stage.totalcheck.sensis.com.au/service/webservice?wsdl there is a message suggestAddress which will translate to a method in the generated reference.cs client proxy code file when you add a web reference from visual studio. By default when this method is called there will be no Header in the soap envelope. To add a SoapHeader to the envelope for this request add a [SoapHeader("Security")] attribute to the top of the SuggestAddress method in the Reference.cs generated class, where "Security" is a class that inherits from SoapHeader base class.
Example for the above required Security SoapHeader you would create the following classes,
public partial class Security : SoapHeader
{
public UserNameToken UserNameToken { get; set; }
}
public partial class UserNameToken
{
public string UserName { get; set; }
public string Password { get; set; }
}
Then you would decorate the SuggestAddress method in the reference.cs like followed,
[SoapHeader("Security")]
public suggestAddressesResult suggestAddresses([System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)] addressSearch search) {
object[] results = this.Invoke("suggestAddresses", new object[] {search});
return ((suggestAddressesResult)(results[0]));
}
This will ensure that every envelope created when method suggestAddress is invoked contains a security header that looks like the one mentioned above,
<soapenv:Header>
<wsse:Security>
<wsse:UsernameToken>
<wsse:Username>username</wsse:Username>
<wsse:Password>password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
Key for me in using this question to help myself was recognizing (as some pointed out) that the headers in question are those of WS-Security standard.
If your proxy generating tool is "custom" it seems logical that you might have a switch to automatically add the headers for WS-Security. However, if you're using WSDL.exe ("Add Web Reference" in Visual Studio), consider svcutil.exe instead ("Add Service Reference").
If you use a WCF proxy, you can override the given config and allow WCF to add the headers for you:
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
From there you can specify the password:
RemoteSvcProxy.TheirClient client = new RemoteSvcProxy.TheirClient();
client.ClientCredentials.UserName.UserName = "uname";
client.ClientCredentials.UserName.Password = "pwd";
I don't know what your custom tool is, but perhaps the framework it's based on also has similar configuration options.

Are attributes allowed in a SAML authentication request?

Is it possible to send attributes in a SAML authentication request?
<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="aaf23196-1773-2113-474a-fe114412ab72"
Version="2.0"
IssueInstant="2004-12-05T09:21:59Z"
AssertionConsumerServiceIndex="0"
AttributeConsumingServiceIndex="0">
<saml:Issuer>https://sp.example.com/SAML2</saml:Issuer>
<samlp:NameIDPolicy
AllowCreate="true"
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
</samlp:AuthnRequest>
Technically, yes, it is possible, since AuthnRequest can contain an Extensions element, which can contain anything - see the SAML 'core' spec: AuthnRequest (section 3.4.1) is derived from RequestAbstractType (section 3.2.1) which has an optional Extensions. The sender and recipient would have to agree on the syntax and semantics of data sent this way.
I can't see a more 'conventional' way to do this, since Attributes are usually in Assertions, rather than AuthnRequests.
There is a case where attributes are to be part of auth request.
so that we can get that attribute name from request to construct response assertion with the same.
because service provider validates the response by comparing the attribute names.we can take the example of Salesforce as service provider, where the same happens.