A small irritation with Go's crypto/tls package

October 20, 2019

I generally like Go's TLS support in the crypto/tls package, to the small extent that I've used it; things pretty much work in straightforward ways as I'd expect and it's easy to use. But I do have one issue with it, and that is that it doesn't supply a .String() method for any of the TLS related constants and types it provides.

The obvious problem is that this leads to duplicated work for everyone who wants to report or log the ciphers, TLS version information, and so on used in connections (and you should capture this information). Unless you want to log the raw hex bytes and throw everyone to the wolves to decode it later, you're going to be converting things to strings yourself, and everyone does it (well, lots of people at least).

So, lots of people create the obvious thing that looks something like this:

var tlsVersions = map[uint16]string{
   tls.VersionSSL30: "SSLv3",
   tls.VersionTLS10: "TLS1.0",
   tls.VersionTLS11: "TLS1.1",
   tls.VersionTLS12: "TLS1.2",
   tls.VersionTLS13: "TLS1.3",
}

Congratulations, you now have three problems. The first problem is that this code doesn't build on older versions of Go, because their older version of crypto/tls doesn't have the tls.VersionTLS13 constant. This issue has been encountered by real code out there in the world. The second problem is that this is going to generate deprecation warnings about the use of tls.VersionSSL30 on modern versions of Go, and may someday fail to build entirely in a future version.

(It's not clear if the Go authors will consider the removal of the VersionSSL30 constant to be an API breakage that is prevented by the Go 1.0 compatibility rules. Similar questions apply for SSL and TLS ciphers that Go drops support for.)

The third problem is that this code will fail to handle new TLS versions that are added in future versions of Go, and which it may encounter when it's compiled under those Go versions and makes connections using those new TLS versions; similar things can happen if you try to have a list of TLS ciphers and names for them. In entirely realistic code (as in, respected programs have done it), this can lead to the program panicing.

In Go programs today, your best option is to ignore those temptingly convenient crypto/tls constants and define them yourself, either as raw numbers (in a tlsVersions map or your equivalent) or as painfully recreated constants of your own that are under your control. Perhaps you can use 'go generate' to automate this from some sort of list.

All of this could be avoided if crypto/tls would convert these to strings for you. Unfortunately it's probably too late to really make this convenient by providing .String() methods, because the relevant types are fixed in stone by the Go 1.0 compatibility promise. However, the package could still provide functions to provide string names for TLS versions and TLS ciphers that are supported by it.

PS: In case you think I'm picking on one specific program here, my own code has this issue too with TLS versions (I was already using raw hex values for my mapping from TLS ciphers to names for them). I'll probably be converting it to use raw hex values for TLS versions, which of course makes it more opaque.

Written on 20 October 2019.
« Ubuntu LTS is (probably) still the best Linux for us and many people
Filesystem size limits and the complication of when errors are detected »

Page tools: View Source, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Sun Oct 20 22:36:29 2019
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.