Introduction
In the first part of this article, we have analyzed the request message of an RST/RSTR exchange between Cardspace and my own implementation of a Secure Token Service (STS) also known as Identity Provider. In this second part, we are going to dig into the response message sent back by the STS in response to the request message that we analyzed previously.
As for the first part, we only focus on the Secure Conversation protocol that protects the RST/RSTR data. This protocol is used to transport many type of exchanges in the new Web Services specifications. I will eventually write another article about the RST/RSTR that is used to transport the SAML token from the STS to the requestor.
Background
This article doesn't use any coding, however it assumes a good knowledge of XML and some understanding of basic cryptography like using symmetric and asymmetric algorithms for encryption and signature purposes. I just attached a small tool that helps understand the basics of cryptography used in this article.
If you haven't read the Part 1 of this article, I encourage you to do so because we are going to use concepts that were detailed in the first part.
Part 2: Response SOAP message containing the RSTR (RequestSecurityTokenResponse)
Structure of the SOAP message
You can refer to the same chapter of Part 1 to get the description of the structure of a SOAP message. As for the request message, a lot of useful information to analyze the whole message is contained in the Security
element of the header. We are going to see first how to decrypt the encrypted content of the Security
element.
Decrypting the encrypted elements of the header
As for the request message, we must get the list of encrypted data in the whole message. This is given by the ReferenceList
element in Security
. This element is shown below.
<e:ReferenceList xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:DataReference URI="#_3" />
<e:DataReference URI="#_6" />
</e:ReferenceList>
In this message, we have two encrypted elements. Let's first focus on the element with Id
="_6", which is the one in the Security
element. As we have seen in the first part, the EncryptedData
contains a KeyInfo
that will help to find the key used to encrypt the data. The whole EncryptedData
element is described listing 1.
Listing 1
<e:EncryptedData
Type="http://www.w3.org/2001/04/xmlenc#Element" Id="_6"
xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:EncryptionMethod
Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<o:SecurityTokenReference>
<o:Reference URI="#_4" />
</o:SecurityTokenReference>
</KeyInfo>
<CipherData xmlns="http://www.w3.org/2001/04/xmlenc#">
<CipherValue>L9uCbEDhVjcB4gTBqC3GtyaiGGY8P7...
oDJ7pB21bAA48xoLzk2ks</CipherValue>
</CipherData>
</e:EncryptedData>
If we look at the EncryptionMethod
element, we get to know that the data has been encrypted using a symmetric AES algorithm with a key of 128 bits. So the fist thing we have to do is find the key that was used for the encryption in order to decrypt the data. This information is given by the KeyInfo
element. This element references an element that has the Id
="_4". Looking up in the Security
element, we can find that it points to the following DerivedKeyToken
element:
<sc:DerivedKeyToken u:Id="_4"
xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-
200401-wss-wssecurity-utility-1.0.xsd"
xmlns:sc="http://schemas.xmlsoap.org/ws/2005/02/sc">
<o:SecurityTokenReference>
<o:KeyIdentifier
ValueType="http://docs.oasis-open.org/wss/oasis-
wss-soap-message-security-1.1#EncryptedKeySHA1">
UbPUL5eLKdw25Xptln4DOGN3YLI=
</o:KeyIdentifier>
</o:SecurityTokenReference>
<sc:Offset>0</sc:Offset>
<sc:Length>16</sc:Length>
<sc:Nonce>i2uYqtgSQCE/KE7C4E86UQ==</sc:Nonce>
</sc:DerivedKeyToken>
This type of an element has been seen previously in the Part 1 of this article. A DerivedKeyToken
element contains information to compute a derived key. The algorithm used to compute this key is a PSHA1 that takes a master key, a nonce, and a label. The label value is fixed by Microsoft to the string value "WS-SecureConversationWS-SecureConversation". The SecurityTokenReference
is used to get the Master Key value. In the request message, the master key was referenced as an EncryptedKey
. This master key is in fact shared by both messages. The response message is to be handled by the requestor which was the one that created the request message, and by the way knows the master key as it generated it.
The purpose of the SecurityTokenReference
is to give a way to the requestor to check that the key that was used by the STS is the one that was generated by the requestor itself.
The SecurityTokenReference
contains a KeyIdentifier
with the attribute ValueType
indicating that the reference to the key we are looking for is an EncryptedKeySHA1
. It means that the base64 value UbPUL5eLKdw25Xptln4DOGN3YLI= represents the SHA1 of the encrypted key value that was sent in the request message. If you refer to Part 1, this value was XsApZde4j3w35HGt…YVHkbY0MFZIg=. The requestor must have kept this encrypted data and mapped it to the master key value. As when using RSA encryption, a cipher is always different for the same data, the requestor cannot encrypt the master key another time to get the encrypted value. Of course, to do the computation, you must first get the binary values of the Base 64 data.
To check this, you can use the tool I provided with the first part of this article.
With the master key, it is now possible to compute the derived key and use it to decrypt the data from the encrypted element. After applying the decryption, you should get the data of listing 2. These data are ASCII values that are in fact a Signature
element for the message.
Listing 2
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<SignatureMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1" />
<Reference URI="#_0">
<Transforms>
<Transform
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>cf8q2Vw2rW5blihu0xWaxCdU4QA=</DigestValue>
</Reference>
<Reference URI="#_1">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>LDb2+mKJ9h0YUEQ2IILUtKjSWGg=</DigestValue>
</Reference>
<Reference URI="#uuid-8346502e-ebb7-b631-0704-403dd21ca6ec-1">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>fJ9Jk5L5Du0pY6FSIQnuBRKtVmI=</DigestValue>
</Reference>
<Reference URI="#_5">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>SjeSg51ZvqDFfu46wsHK2+QmZEo=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>7ddH6wlhQNJPw6VRMORxP6eD37Q=</SignatureValue>
<KeyInfo>
<o:SecurityTokenReference
xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-
200401-wss-wssecurity-secext-1.0.xsd">
<o:Reference URI="#_4" />
</o:SecurityTokenReference>
</KeyInfo>
</Signature>
Decrypting the Body encrypted data
Now that we have decrypted the Signature
element, decrypting the body will be a peace of cake! The EncryptedData
element of the Body
is given below:
<e:EncryptedData
Type="http://www.w3.org/2001/04/xmlenc#Content"
Id="_3" xmlns:e="http://www.w3.org/2001/04/xmlenc#">
<e:EncryptionMethod
Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<o:SecurityTokenReference
xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-
200401-wss-wssecurity-secext-1.0.xsd">
<o:Reference URI="#_4" />
</o:SecurityTokenReference>
</KeyInfo>
<CipherData xmlns="http://www.w3.org/2001/04/xmlenc#">
<CipherValue>83suvxZAJ+4hOeo/baEFfdu20yKkU4unm1QJ4N9
WrUVOa...BVNOKR5yumvi/aQ==</CipherValue>
</CipherData>
</e:EncryptedData>
If we take a look at the KeyInfo
, we can see that it references the same key, which means that we just need to use the derived key that we computed to decrypt the Signature
. Running the AES128 decryption algorithm on the data will give us some ASCII data that is the XML element RequestSecurityTokenResponse
. This element has been constructed by the STS in response to the RST that was decrypted in the Body
of the request message.
The next step that has to be done, is to verify the integrity of the message that the requestor receives. Previously, we decrypted a Signature
element. This element contains information that shall be used to verify this.
Verifying the Signature
If you refer to the Signature
element we had in the request message and that has been analyzed in the Part 1 of this article, you can see that the structure of this one is totally similar. As there is no further interest to detail again the verification process of the Signature
, you would find it in the Part 1 of this article.
Points of Interest
We have seen in those two parts quite a lot of concepts and information. WCF totally hides the WS-* protocols, and makes the use of security features as simple as a line of XML in a configuration file. However, you can see that a lots of things happen under the hood. It is particularly important to understand what really goes on when you activate the security feature, when you have to deal with interoperability like I have to do.
So I hope that with this article, you will have been interested to learn a bit about the security protocols that are used in WCF. Of course, this is just the study of a particular case of interoperability, but I think that it can help you understand better how to use security in WCF as it helped me make my mind clearer about those features by writing this article.