Using encrypted private keys with Golang HTTPS server

Image for post
Image for post
Yes, this is an Owl, protecting my traffic

Coming from a Java world (I am embarrassed enough), this hit me like a wall. Default golang http.Server does not have a way to accept private keys that are protected by a passphrase. If you look up the documentation for server.ListenAndServerTLS, it needs 2 parameters, the certFile and keyFile strings, that represent the location of PEM encoded format for certificate and private key. There is no option to supply the password !!

Another weird thing I saw is there is field in the http.Server struct, it has a tls.Config parameter that too has a field to configure the tls.Certificate object and that is not just for Certificates but for PrivateKey as well. I thought, why does it need the parameters in server.ListenAndServerTLS when it already has it. I got into the messy part because I can’t read documentation.

It is first checking the TLSConfig that we might have supplied, if not then it would use the supplied cert and key file names.

It occurred to me, why not we try to build the tls.Config.Certificate with the encrypted key file that we have.

Let’s get to some action

How do you load a plain cert and key files to build a Certificate Object

tls.LoadX509KeyPair(certFile, keyFile string) or tls.X509KeyPair(certPEMBlock, keyPEMBlock []byte)

The first one takes file names and second one takes PEM encoded blocks. First is no use, as it is the same as the Server interface. The second one looks interesting. Let’s try to get the private key as a PEM block.

But first, What is PEM encoding. There is a very interesting and intimidating thing called ASN.1 that can be used to serialise structures and cryptographic implementation uses the DER encoding rules to store the ASN.1 structures.

A basic guide for layman can be found here: ASN.1 and surprisingly here: DER encoding for ASN.1

For now just think of those as serialization techniques and know that DER is a binary encoding scheme or it produces binary output. Which is ok to store on disk. But when you have to transfer it over emails, for which PEM (Privacy enhanced mails) was originally built, which is plain text, you need to make it a little simpler.

Here comes the base64 cannon. Another encoding scheme on top of an encoding scheme (I know, right !!). It can represent any binary data as printable characters. eg:

Yay ! So now you can transmit binary data in a printable format.

PEM is the fancy name for this base64 encoding of DER format. Try this for fun, it’s pure pleasure :D

Look at both of the outputs, They are the same, with a better formatting though. And the

part is according to the RFC which tells about the type of the PEM block.

Coming back to our problem,

If we can get golang a PEM block that has the private key unencrypted, bingo. First let us get the PEM block in golang Native structs.

encoding/pem has a useful function: Decrypt(data []bytes)(p *pem.Block, rest []byte). This function goes through the bytes and tries to find the marker of the PEM block and returns the first block as a pointer to pem.Block

Let’s try to see how to write this thing.

Not bad, but we still haven’t reached the magic yet.

Another amazing function, a pair actually, that golang’s crypto library provides is

Check if a PEM block is encrypted, if yes, decrypt it. Yes, it’s that awesome.

All you need now is check if the detected Private key block is encrypted, If yes, decrypt it.

And, that was it.

If you would have seen the signature of the tls.X509KeyPair(certPEMBlock, keyPEMBlock []byte) all they need is a PEM block as bytes. And pem.Block already has a Block.Byte Value. What’s this for ?

This is the DER encoding of the ASN.1 structure and we just don’t need bytes in the function, but a well formed PEM block with all the markers and headers (yes, that took me a couple of hours and some facepalms to find out, as I read documentation as carefully as people think about their passwords.)

Now, how do you protect the password to the encrypted private key, is another problem altogether and my face already has enough finger marks.

Software Engineer — infosec @WalmartlabsIndia

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store