On ProofTokens

Let's take a break from the visionary stuff (but I'll get back on that, especially now that Jon chimed in) and get some good old WS-* action.

One of the things I didn't cover in the WS-Trust video (I know, it doesn't work right now. I notified the channel9 guys) is how ProofTokens work; and since you are a very attentive audience, I get questions on the matter pretty often. Another video would probably be the best format, as Planky suggested months ago, but let's see if we manage to do something even with a static media.

So, prooftokens. In the most classic case, the prooftoken is what allows the requestor to use a key that's locked in a token encrypted for somebody else. Crystal clear, right? ..NOOT :-) Ok, let's go a step at a time.

Let's say that you have an RP, implemented by a web service. Your RP requires to be invoked via calls secured by a token in SAML1.1 format, issued by STS A and containing the claim https://whatever. Let's express in a picture the situation described.

image

It seems complicated, but in fact it is pretty easy. The picture shows the message that is being sent to the RP. The cyan rectangle encloses the token being used for securing the call:

  • As requested by the RP's policy, the token is signed by STS A: the outermost couple of brackets shows the signature operation, made with STS A's private key (the red triangle key).
  • The inner couple of brackets represent an encryption operation, made with the public key of the RP (blue rectangular key). The token is encrypted with RP key, so that nobody but RP itself can see the token content
  • Inside the token there are the claims (in this case just https://whatever) and a session key, represented by the green diamond key. For the sake of simplicity we use a symmetric key.

The yellow rectangle encloses the body of the message. In practice, what does it mean that the message is secured by the token? It means that the body is secured (signed/encrypted) by the session key contained by the token (the green diamond key).

All right! Now that we've seen what is the message we must be able to produce if we are to comply with RP's requirements, let's work backward to understand what we need to obtain.

Since the token is issued by STS A, the first logical step is asking STS A to issue the token for us. Let's fake for a moment that the idea of prooftoken does not exist, and let's just get the token:

 

image

Here we see the usual procedure for obtaining a token from an STS. The client (stick figure) sends a request for security token (RST) to STS A. The request is signed with the private key of the requestor (round lavender key) and encrypted with the public key of STS A (red triangular key).

If STS A is happy with the request (usually because it likes the signature and what was used for making it) it will send back a request for security token response (RSTR), encrypted with the public key of the requestor and containing the requested token (the same we've seen in the former schema).

Great, now we have a token that matches the requirements of RP. Are we in the position of performing the call as described in the first schema? The answer is a resounding NO. If we would be in the browser case (ie the RP is a web site and the subject uses a browser for interacting with it; what was called until recent times "the passive case") we would be already OK; we'd just send the token as is in a POST. Here (in the "active case") we are requested to do more: just attaching the token to the message is not enough, we need to use the token for securing the message itself. As we have seen, this mean using the session key contained in the token: but if you observe the picture you'll see that the session key is locked inside the token, and the token is encrypted for RP. Only RP can decrypt the token and access the key it contains, hence it is inaccessible for the requestor.

This is the problem that the ProofToken solves. A ProofToken travels together with its relative token in the RSTR, and is used to communicate to the requestor the session key in a format that it can understand. Modifying the picture above for accommodating the ProofToken:

image

The orange circle shows that we are sending in the RTSR the same session key (green diamond key) but encrypted with the public key of the requestor.

At this point we have it all; we can attach the token to our message to RP without having to open it (in fact we can treat it as opaque), and we can secure the message itself by using the key we found in the prooftoken.

This system gives superior guarantees in respect to the passive case. If a man in the middle would be able to acquire the token, this fact alone would not allow him to perform authenticated calls: not only he would have to attach the stolen token to the message, he should also give proof of possession of the associated key by securing the message with it. As you may imagine, that's what gives the name to the ProofToken; it is the token that enables the requestor to exhibit proof of possession of the key.

ProofTokens are actually more complex than that; they may not contain a key, they may contain an asymmetric key, they may collaborate with the client for creating the key... and ws-trust itself is more complex (for example, we could use transport based security here and there); however, the above is more or less the essence & the raison d'etre of the ProofToken. For details, I recommend reading the WS-Trust spec; and of course please do not hesitate to shoot your questions here!