Create SecurityContextTokens without X509 Certs

So I wanted to roll my own SecurityContextToken (SCT) service.  Not because I want to reinvent the wheel, but because I did not want to have to use X509 certs and because I could not figure out how to issue SCTs using soap.tcp at the server.  All the documentation addresses using IIS web service and ASP.  First a word on SCTs as they can be a bit confusing.

The goal is to authenticate to the server and get a SCT at both sides.  The idea is you can only get a SCT if you authenticate at the server.  The SCTs at both sides have a random 16 byte “secret” key that both sides can use to encrypt the rest of the session (using AES/Rijndael or other.)  This is very similar to how SSL works.  SCTs are a bit more flexible as you don’t have to encrypt all parts of the conversation, only those parts that need encryption, so it is an opt-in model.  The interesting feature is that once the SCT is cached at the server side, you can send messages with only the SCT header in the message and the server can verify you already authenticated so you don’t need to keep sending a UsernameToken (UT).  However, you *should encrypt and/or sign each message with the SCT, so that the server can verify your SCT “knows” the secret key.  Otherwise anyone could construct a SCT using the same SCT.Identifier and can access  your Web method, as only the Identifier string is sent in the header.  At the server, the SCT also maps to an authenticated UsernameToken so that your methods can verify Role memberships and have access to the username, etc.  In WSE, you can use the SecurityContextTokenServiceClient class to request a SCT from a URL.  However this requires a server side X509 certificate.  I wanted a secure solution that did not require a cert, but still used secure PKI to negotiate the SCT.

This method resembles the built-in method, but requires only a standard RSA key pair as created with the RSACryptoServiceProvider class in the .Net framework.  If you sign your assemblies with a strong name (SN), then you already have everything you need.  The server private key needs to be secured as normal.  The client’s public key is already in the assembly for ready access to create an RSA object from it.  This does require that the client calling your web service actually is running your client assembly.  If this is not the case, the client could also get the public key via some prior out-of-band method such as email, diskette, etc.  You don’t want to allow the client to get the public key via a network call as a third party could do a Man-In-Middle attack by returning their own public key to your client.  This is the reason server Certs where created in the first place to prove to the client that you got the correct key and not some other key by an attacker.  As we "know" the server’s public key already, we can avoid having to use Certs for this proof.  If you did want to get Public key using a network call, you would need to return a Cert or have some prior security context setup between the you and the server.  Anyway, here is the process:

1)      Client creates public RSA object from public key of service.
2)      Client generates random entropy (secret) bytes (k1) to be used as part of the shared session key (i.e. the SCT.KeyBytes value).
3)      Client creates a new RSA key pair (i.e. clientRSA) to be used for the key exchange.
4)      Client creates a message containing Key entropy bytes, user name, password, and the public key from clientRSA.  Client encrypts Key, user name, password, and public key fields using server’s public key from step 1.  Request is Signed.
5)      Server method gets message.  Server verifies signature and decrypts all fields to get the clear data.
6)      Server authenticates user using any method desired at the server.  I will use Win32’s LogonUser API to leverage Windows authentication so I don’t need another out-of-band user database.  You could, however, use your own database.  A UsernameToken is created (but not cached.)
7)      The server generates its’ random entropy bytes (k2) and combines them with the client’s “k1” bytes to generate a shared session key (sKey).
8)      The server creates a new SCT and sets the KeyBytes to the sKey.  The SCT is created with the UT passed to the constructor.
9)      The server generates a reply.  It adds “k2”, SCT.Identifier string, Expire date, and UT ID string to the message and encrypts the “k2” bytes using the public RSA key passed in the client request message.  Server also adds a Key Verifier hash so client can verify they both use same key.  The server also signs the reply so the client can verify it came only from the server.  The server also caches the SCT.
10)  The client gets the reply and verifies the signature.  It decrypts the “k2” key and generates “sKey” itself.  It then creates a new SCT using “sKey” and the Identifier passed from the server reply and verifies the KeyVerifier (Note the Identifiers have to match so the server can find the SCT in the cache).
11)  Client can now sign and encrypt future messages using just the new SCT (i.e. no UT required).  The SCT can be used until it expires, however it is probably good practice to get a new SCT for each unique session or set of related method calls.

Now that client has its new SecurityContextToken, it should keep it for the rest of the session and *only use the SCT or a DerivedKeyToken (DKT) derived from the SCT.  The UT is not needed or desired.  The client should also *always encrypt or, at a minimum, sign all outgoing messages with the SCT or DKT.  This is because the server can only verify you know the SCT shared key, if you sign or encrypt the message.  We don’t need to keep attaching the UT in the Soap header because that would be redundant and just overhead.   The SCT is already authenticated, so use that.  We can also add consistency and security to all our web method if we always *require a SCT in the header.  That way WSE automatically verifies the SCT, any hash, or decryption for us.  We do, however, still need to assert in our methods (or in Policy) that a SCT was attached, and the body was signed (or encrypted as needed).  As a rule, I would always require a body signature was attached.  As noted, after we get our SCT, we can forget about any UTs.  We don’t need to send them and should not (unless you have some specific need.)  If you do need to attach a UsernameToken to a Soap header – always encrypt it using the SCT.  The protocol summary is as follows:

C->S
    {K1, Username, password, C’s public key}S’s public key
    {digest[K1, Username, password, Mod1, Mod2, Exp]}C’s private key

C<-S
   
{K2}C’s public key
   
UT.ID
   
SCT.Identifier
   
SCT.Expires
    KeyVerifier
   
{digest[K2, UT.ID, SCT.Identifier, SCT.Expires, KeyVerifier]}S’s private key

Client (C) sends K1, Username, password, and C’s public key to Server (S).  All elements are encrypted with S’s public key.  Server creates SCT with generated sKey and returns K2, UT.ID, SCT.Identifier, SCT.Expires, KeyVerifier and Signature.  K2 is encrypted with C’s public key.  All elements are hashed and then signed using S’s private key.  Client can then verify all elements have not been changed and message sent by S.  Client generates sKey and SCT.

That is about it.  We now have a way to securely pass user credentials to the server and get a SCT in reply using soap.tcp and PKI.  UsernameTokens are then out of the picture so we don’t have to worry about SendPlainText or SendHash stuff anymore.  To keep this post ~short, I will show the implementation at Get SecurityContextToken C# Code .  Also note, this implementation is updated at Updated Get SecurityContextToken in C#. Cheers!


William

Advertisements
This entry was posted in WSE. Bookmark the permalink.

15 Responses to Create SecurityContextTokens without X509 Certs

  1. Unknown says:

    Hi,Do you have used LCDs, second hand LCDs, used flat screens and used LCD monitors? Please go here:www.sstar-hk.com(Southern Stars).We are constantly buying re-usable LCD panels and working for LCD recycling.The re-usable panels go through strictly designed process of categorizing, checking, testing, repairing and refurbishing before they are re-used to make remanufactured LCD displays and TV sets.Due to our recent breakthrough in testing and repairing technology of LCD, we can improve the value for your LCD panels.
    website:www.sstar-hk.com[cibfeadcadajbcf]

  2. Unknown says:

    wow gold!All wow gold US Server 24.99$/1000G on sell! Cheap wow gold,wow gold,wow gold,Buy Cheapest/Safe/Fast WoW US EU wow gold Power leveling wow gold from the time you wWorld of Warcraft gold ordered!

    wow power leveling wow power leveling power leveling wow power leveling wow powerleveling wow power levelingcheap wow power leveling wow power leveling buy wow power leveling wow power leveling buy power leveling wow power leveling cheap power leveling wow power leveling wow power leveling wow power leveling wow powerleveling wow power leveling power leveling wow power leveling wow powerleveling wow power leveling buy rolex cheap rolex wow gold wow gold wow gold wow gold -49656975148254

  3. William says:

    "The Utils class doesn\’t have RijndaelDecrypt and other relevant method. Can you post it or send it to me. "Sure. Posted at new blog entry here:http://spaces.msn.com/members/staceyw/Blog/cns!1pnsZpX0fPvDxLKC6rAAhLsQ!303.entry–William

  4. Rajeev says:

    William,Thanks for posting the code. The Utils class doesn\’t have RijndaelDecrypt and other relevant method. Can you post it or send it to me. Thanks,mohan

  5. William says:

    –Matt: "Do you know of a simple way in which we can hook back into the wse UsernameToken authentication mechanism at the point the UsernameToken is created on the server? "In my example, not sure what that would provide (please expand the need). As you get the clear password, you can auth or not auth anyway you like. Plus, I don\’t think you want to cache the UT, just the SCT, and the custom UTM would cache it. This does not stop you, however, from having a custom UsernameToken manager installed, to handle any requests that just have UsernameTokens. However I think I would *require all SCT tokens to keep a better box around security and add consistency. As for policy, you could just require all methods are signed by a authenticated SCT and the only way to get one is via your one server method (i.e. the *only method that does not require a SCT token signature.) Maybe I did not understand your need. If so, please post back and I can chew on it some more. Cheers :-)– William

  6. Unknown says:

    Many thanks for this – cured more than a few headaches! We currently have your scheme running with no problems using http and policy for SCT usage. In order for policy to work, we did have to add the following to the server code at the point the SCT is created: sct.TokenIssuer = HttpContext.Current.Request.Url;and the following to the client at the point the SCT is created: sct.TokenIssuer = new Uri(wseTokenService.Url);where wseTokenService is a standard VS generated web service proxy. It may be that these changes needed because of <wssp:TokenIssuer>http://…</wssp:TokenIssuer> elements in the policy, but I haven\’t tested for that.Do you know of a simple way in which we can hook back into the wse UsernameToken authentication mechanism at the point the UsernameToken is created on the server? This would allow a custom UsernameToken manager to specified in the .config file rather than the authentication logic being part of the sct generation flow…

  7. William says:

    I played with Diffie-Hellman and SRP for key exchanges using WSE and got code working. The problem with DH is that to prevent the man-in-the-middle attack, you need std PKI or Cert. Then you probably need two 2-way exchanges. As long as we need PKI, we may as well do it this way with one request/reply. SRP is great, but requires a seperate DB to store the verifier/username. Not bad if that is all you want, but if you wanted WinLogon, then you have to have both DB and Windows User DB. You could use SRP just for the key exchange with a default account just for key exchange, but not sure I like that.My method could be easily modified to use a default user/pw just to create an un-authenticated shared key token. Then you could use that with normal WSE to encrypt and sign the next message pair. I am thinking more on that as an addition option. As the SCT would be cached but not authenticated, you would need to watch that you don\’t allow any SCT into your Web Methods, only Authenticated ones. –William

  8. William says:

    Thanks to both. I have this implemented in c# today. Was just looking it over (and over) to find weakness. I am going to update a bit with Signature on Request using Client\’s private key. As it stands right now, a man in the middle could get *half the key but not all. I think the client sig will not allow even half the key. He would still need the username, password and the other half of the random key. So it is still pretty good as it. I will hope to post code today sometime. Please feel free to comment on any code/protocol weakness. Cheers!

  9. Unknown says:

    Like the previous commenter, I too have been planning on trying this out (I\’ve seen other applications doing this). I want to keep the logistics and problems associated with distributing certificates to a minimum.I look forward to seeing your code for this!

  10. Softwaremaker says:

    Ahhh…You beat me to it 🙂 I knew something like that would be very useful and there are tons of requests out there for the use of SCT without X.509 because of cost issues or the server admin doesnt want to install them for whatever reasons.I was on my way to implementing it, then I took some time off to look at the specifications for the exchange of entropy values, then I got derailed by some work committments and after that I just got lost…It is so good for you to come up with this. It is excellent. I would have to try it and feedback. Many people will thank you for it.

Comments are closed.