TLS Mutual Auth in GoLang

Golang takes no prisoners.

Don’t use a variable? Your code isn’t going to run!

Import something you don’t use? Nope, no chance.

Realistically I should have expected their attitude to security was just as tough. So implementing TLS mutual auth was never going to be simple. Simply put go does all the checks it quite rightfully should do, but those checks make it a nightmare when you just want to test some TLS work locally.

Strict TLS

There are a few points that trip you up locally, especially since go 1.3 where things got even more strict. When you hit any https endpoint online the certificate is usually backed to a domain name, however when working locally often you use localhost and interchangeably, when doing mutual auth you can’t help but bump into this issue. Since TLS is designed primarily around domains you need to add IP SAN’s. Secondly x.509 certificates have an extension to define the usage of keys in terms of server or client auth, which of course go checks.

Older versions of go used to have options to disable certain checks, but those have long since gone. Its secure, or nothing!

All this boils down to it being a real nightmare to generate the right keys so you can get up and running. However now that I’ve been through that pain, the solution is quite simple.

First up you need to generate your keys with IP SAN’s, to do this get hold of this file which does a great job of making your life easier.

Generate your certificates

To generate the server cert (assuming localhost) run the program with the options:

  • Common Name: localhost
  • DNS or IP Address 1:
  • Number of days: 365 (or whatever you like)

To create the client cert there’s one thing missing. You need the extension for client certs, find the line that reads:

ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},

Change this to:

ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},

If you are being lazy you can also just permanently change it to:

ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},

Copy your previously generated server certs somewhere and run the program again to generate client certs.

This will give you 4 files, a cert and key for the server, the same for the client. The code to use them in mutual auth is pretty simple at this point.

I created 2 projects called secure-server and secure-client, the code looks like this:

Secure Server

Secure Client

Run it

First run the server, which will load its own cert and key, along with adding a client cert for the client application (you can add more if you need to) and then run the client, which loads its own cert and key, along with creating a new root ca pool with just that one server.

The great thing about this setup is once you have gone through the pain of creating your certificates and the code is somewhat trivial, after you have it all figured out.

Hopefully this should save people a bit of time in getting this working.