We recently started using Let’s Encrypt SSL certificates. These certificates have a validity of only 90 days, and we wanted a way to easily check the expiry dates of all our certificates.

Turns out, it’s really easy to do this with Go.

The crypto/tls Package

The crypto/tls package provides a TLS 1.2 implementation. Among other things, you can use it to establish a TLS connection and examine certificates. Connect to a host, like google.com, is as simple as:

conn, err := tls.Dial("tcp", "google.com:443", nil)

The Dial succeeds only if the server presents a valid certificate (self-signed certificates will not work). Verifying that the name matches is another step, which can be done like this:

err := conn.VerifyHostname("google.com")

This checks if the given name matches the Common Name or the Subject Alt Names specified in the certificate. And finally, the certificate chain itself is available as conn.ConnectionState().PeerCertificates. The server’s certificate contains the expiry date we are interested in.

Here is a snippet (sans error checking) which can be used to get the expiry date of the certificate of an https site:

conn, _ := tls.Dial("tcp", "google.com:443", nil)
err := conn.VerifyHostname("google.com")
expiry := conn.ConnectionState().PeerCertificates[0].NotAfter

Not bad for 3 lines of code!

Rolling it into a command-line tool

We threw in error checking, timeouts and a couple of useful tidbits:

  • Read the list of server names to check for from a file and as command-line arguments
  • “Humanize” the expiry date with the nifty go-humanize
  • ASCII art table

and rolled this into a command-line tool we named certchk. Here’s certchk in action:

$ go get github.com/rapidloop/certchk

$ certchk
Usage: certchk [-f file] servername ...
  -f file
    	read server names from file

$ certchk mail.google.com facebook.com
         Server | Certificate status
----------------+----------------------------------------------------------------
mail.google.com | valid, expires on 2016-05-31 (2 months from now)
   facebook.com | valid, expires on 2016-12-30 (9 months from now)

$ cat /tmp/names
# this is a comment
www.netlanders.net
www.facebook.com
ttybuy.com

$ certchk -f /tmp/names mail.google.com
            Server | Certificate status
-------------------+-------------------------------------------------------------
www.netlanders.net | x509: certificate signed by unknown authority
  www.facebook.com | valid, expires on 2016-12-30 (9 months from now)
        ttybuy.com | x509: certificate is valid for SV100, not ttybuy.com
   mail.google.com | valid, expires on 2016-05-31 (2 months from now)

That’s it! The code is available on GitHub, and you can go get it with:

$ go get github.com/rapidloop/certchk

Feel free to send us your feedback, suggestions and PRs!