Keegan Carruthers-Smith for the GopherCon Liveblog on August 29, 2018
Presenter: Liz Rice
Liveblogger: Keegan Carruthers-Smith
Title graphic: Amy Chen
A practical guide to what is happening under the covers when applications or users need to identify themselves, or need a secure channel for communications.
The motivation of the talk is to understand what is happening with these certificates and keys, how they are used to setup these secure connections.
The talk aims to answer:
TLS is used to identify and encrypt connections. The code for the tutorial is at github.com/lizrice/secure-connections. It contains hooks into tls.Config to help illustrate what the client and server do when establishing a TLS connection. Additionally it illustrates how mutually authenticating TLS works (mTLS).
Establishing identity online is critical. For example when you online deposit money into your bank account, you want to ensure you are talking to your bank. Additionally the messages and amount of money you deposit should be encrypted in case traffic is intercepted.
Note: You often see TLS and SSL mentioned. TLS is the newer name for the protocol that used to be called SSL.
Go's TLS implementation exposes hooks into the TLS handshake:
Public/Private key encryption:
You can also use the private key to sign a message. The public key is then used to verify the signature. You have message + signature.
In TLS you send your public key and identify yourself. The server does not know who you are, so to establish identity it relies on a third-party it trusts called a Certificate Authority (CA). The CA will sign your certificate, which the server can verify.
A certificate is a X.509 certificate. X.509 is just the name of the standard. It contains:
Subject is who you are trying to identify. The CA is someone who you both trust.
Your certs should use a Subject Alternative Name (SAN). Common Name was
deprecated in 2000! You can ignore in Go 1.11 with GODEBUG
setting
x509ignoreCN=1
.
You use a trusted certificate authority. This is something like Let's Encrypt. Trusted certificate authorities have certificates on your computer and/or browser. Those certificates are used to validate certificates for public-facing domains. It is not for internal components in a distributed system.
If you want a signed certificate you create a Certificate Signing Request
(CSR) and send it to the CA. For example you can create a CSR with openssl
:
openssl req -key private-key -new -out csr
The Certificate Authority then validates your identity. For example Lets Encrypt has challenges like asking you to change a DNS setting to prove you have control over what it will sign.
openssl
doesn't easily support SANs. There are several alternatives:
cfssl
, mkcert
, minica
. Minica's usecase is easy generation of key and
certs. Also it is only 300 lines of Go code, so if you want to create
certificates yourself progmatically you can just look at minica's source.
minica -domains liz-server
Will create keys, etc for the host liz-server
in a new directory called
liz-server
. You will need to add liz-server
to your /etc/hosts
to point
to localhost.
These keys are then used to demonstrate TLS in the example code at github.com/lizrice/secure-connections. Try it out yourself.
Normally the client only validates the identity of the server, but the server
doesn't validate the identity of the client. mTLS is adding the validation to
the TLS handshake. In the server-side tls.Config
you set ClientAuth:
tls.RequireAndVerifyClientCert
. You then need to create a certificate for the
client and get it signed by a CA the server trusts. tls.Config
will need to
contain the CA's for client certificates ClientCAs
.
Note: tls.Config
is used by both clients and servers. Most fields are
shared, but some fields are specific to client and server. So take care to
read a fields documentation when using it.
The file extension used is inconsistent.
.crt
for certificate, .key
for private key....pem
PEM files are Base64-Encoded and they will contain a header saying if it is a key, certificate, etc. You can understand the contents of the file with openssl
:
openssl x509 -text -in cert.pem -noout