Introducing ntlmclient

May 6, 2018

I’d like to announce ntlmclient, a new open source library that I built. Usually I'd be announcing it proudly and encouraging you to use my code — but this time, I’d ask you to please not use it.

See, this new library is a library that performs NTLM2 authentication. And, to be honest, I’d like to ask you to not perform NTLM2 authentication at all. But — if you really must use NTLM2 — then I suppose that this new library will do the job.

I intend to add this to libgit2, the Git library that backs clients like GitKraken and gmaster. Because regrettably, we really must use NTLM2. Many people still use NTLM2 with their on-premises Team Foundation Server instances, and we’d like all the tools that use libgit2 to be able to talk to their Git repositories hosted in TFS.

At the moment, libgit2 can already speak NTLM2 on Windows clients; using this library will enable Unix platforms to speak NTLM2 as well.

A bit of background

My first experience with NTLM was way back in 2006, when I was working at Teamprise. We were building cross-platform tools to talk to Microsoft Team Foundation Server; we had a plug-in for the Eclipse IDE, a standalone GUI tool, and a command-line client for Windows, Mac, Linux and a bunch of legacy Unix platforms.

(Today these tools live on as Microsoft Team Explorer Everywhere.)

We faced a lot of challenges reimplementing Microsoft’s tools — and one of those early features that we needed to implement was the NTLM2 authentication protocol. Since we were building a plug-in for the Eclipse IDE, we built our entire client suite in Java. And — regrettably — our HTTP stack didn’t support NTLM2 at the time, only the older LM and NTLM protocols.

But LM and NTLM are truly ancient algorithms, so modern systems disable them both, in favor of the slightly less ancient NTLM2 algorithm. So at Teamprise, we were forced to learn about, and ultimately implement, NTLM2 ourselves.

That was over a decade ago, and it certainly hasn’t gotten any better with age.

How NTLM2 works

Many people still have their Windows servers — and some of the applications on them — to use NTLM2. That’s because it’s not without its advantages: it’s the simplest way to enable "single sign-on". When you sign in to your local computer, it hashes your password and stores that hash in memory. This is the same hash that the server — or your Active Directory server — has stored. Later, when you communicate with a server that wants you to authenticate with NTLM2, you encrypt a shared random value that the server gives you using that hash. Then you send that encrypted value to the server — it will encrypt the same value with it’s hash and if they match, it will prove that you have entered the same password without actually having to transmit the password itself, or even keep it in memory in plaintext.

This is a clever way to allow you to authenticate to a remote server without having to type your password. But there’s a better way.

Alternatives

Kerberos also enables single sign-on, but instead of relying on ciphers like RC4 and HMAC-MD5, Kerberos is built on modern ciphers. Microsoft Active Directory is built around Kerberos, so it’s obviously well-supported on Windows, but Kerberos is also an industry standard. There are great implementations available including MIT’s and Heimdal.

However, the reality is that Kerberos requires some additional configuration on Windows servers. And this configuration is absolutely worth it on a production machine. If you want to support single sign-on, you should probably be using Kerberos in production. But if you’re just spinning up a test server, it’s sometimes worth it to just use NTLM2. And the reality is that NTLM2 over an encrypted connection like TLS is still a reasonable solution.

Fundamentally, a lot of people still use it.

So I created a new NTLM2 client library. It’s basically a port of Team Explorer Everywhere’s NTLM2 code that’s been used in production for over a decade — but it’s a port to C, with minimal dependencies. It only requires a cryptography library for the underlying cipher support. On macOS, ntlmclient will use Common Crypto, the system’s cryptography libraries. On Linux, ntlmclient uses either OpenSSL or mbedTLS, whichever library you have on your system.

So, please, don’t use NTLM2. If you need single sign-on support, you're probably best off using Kerberos. And if you don't need single sign-on support, just use Basic authentication over TLS.

But if you do need to support NTLM2 — like if you need to talk to an on-premises Team Foundation Server that wasn’t configured with an SPN for Kerberos — then I hope my new ntlmclient library helps.