SSPI Negotiation; NTLM and Kerberos clients and servers

I’ve been working on a library that works in a similar way to our SChannel code and allows the use of the Microsoft “Negotiate” Security Support Provider Interface (SSPI) to provide NTLM and Kerberos support (see SPNEGO for more details). Things are going well and, in general, using Negotiate or NTLM or Kerberos is easier than using SChannel and the structure that was originally born to work with OpenSSL and then adapted for SChannel works well with the new security providers. It has also been especially useful to have all of the various high level tests that I developed for the SChannel code which deal with the mundane issues of negotiation and data flow using the ‘async connector’ model. This model was originally developed for the OpenSSL code; but I didn’t have tests back then; although the tests all needed to be adapted to work with the new SSPIs it was relatively painless and having all of that in place already has helped to speed up the development work.

One thing that I found interesting with this new development was that whilst the SChannel SSPI was geared up to handle an unpredictable byte stream and incomplete messages via SEC_E_INCOMPLETE_MESSAGE error code, the Negotiate, NTLM and Kerberos SSPIs were not. I’m guessing that this is mostly down to the fact that SChannel (basically SSL/TLS etc) is, by design, network stream based and has all of the appropriate message framing built in to the messages. That said, SChannel was different to OpenSSL in that with OpenSSL the library provided incomplete data accumulation and buffering and you just kept shoving data in until the OpenSSL library had a complete message or two at which point it pushed some cleartext out at you. With SChannel you’re told that there’s not enough data to provide a complete message via the SEC_E_INCOMPLETE_MESSAGE error return and you have to buffer this data yourself and add further data to it when it arrives and then retry the operation. With Negotiate, etc, you have to go one step further and provide your own framing of the messages and perform your own accumulation so that you can present complete messages to the SSPIs for processing; they simply fail if you provide incomplete messages. This wasn’t a great problem as much of the message accumulation code had been written for the SChannel code. The only difference being that this time I manage the framing as well rather than relying on the SSPI to inform me of incomplete messages by SEC_E_INCOMPLETE_MESSAGE. In general it makes the whole Negotiate/Kerberos/NTLM method more versatile.

The Negotiate servers are also slightly different to the SSL/TLS servers in terms of authentication and message protection. With Negotiate you have two levels of message protection; you can either ‘seal’, that is encrypt, or ‘sign’, which just generates a message authentication code to prevent tampering. You can decide which method of protection you need on a per message basis so that you can send most messages as signed messages and then sent particularly sensitive data encrypted. The ‘async connector’ model works reasonably well with this; you can specify which method of protection you want to be the default for the connection; none, sign or seal, and then any data sent in the ‘usual way’ with socket.Write(). I’ve then added some functions at the ‘socket server’ or ‘connection manager’ level to provide for sending data with another protection level where you pass the socket and the data and the required protection level to the function and it does the right thing for you. At the other end we just do the right thing as the kind of message protection in use is included in the message framing and so the remote end knows what to do with the data. From an authentication point of view SSL gives the ability to verify the server and the option of requiring verification for the client. NTLM provides a guarantee of client authentication for the server but only Kerberos provides authentication of the server for the client.

Finally the Negotiate security providers give the server the opportunity to impersonate the authenticated client. You can do this with SChannel if you set the system and certificates up properly but it’s much more straight forward with the Negotiate protocols; mainly due to the fact that Windows uses these internally for file server access, etc.

These changes will be included in the 6.1 release of The Server Framework which currently has no scheduled release date; they’ll be a separately licensable option.