Introduction

This post is a walkthrough on how to use Cloudflare’s fork of Go, combined with the Caddy reverse proxy, to use post-quantum encryption for your website today.

Background to Post-Quantum Cryptography

Post-quantum cryptography refers to public key crypto which is resistant to cryptanalysis on a quantum computer. In ‘23, about 98% of TLS handshakes used elliptic curve cryptography to encrypt a symmetric block cipher key, which then encrypts the payload. The current post-quantum offering is an asymmetric cipher called Kyber, against which a quantum computer is thought to have no particular advantage over silicon-based classical architecture.

Why Now?

A common question asked about post-quantum cryptography (PQC) is, ‘why now?’ Quantum computers being in their infancy, isn’t it simply too soon to bother safeguarding against codebreaking attacks now?

The answer lies in the store-now-decrypt-later threat model. This means that an attacker could intercept and store a TLS handshake and the payload, then revisit the content in years to come, when better codebreaking technology becomes available. We may be 5 to 25 years away from such an attack being practical (it’s hard to be precise), but some of what we say today must stay secret tomorrow.

Tutorial

Follow these steps to get a working webserver using post-quantum encryption for TLS

Requirements

You will need docker compose and Chrome to follow this tutorial.

Docker Compose Setup

In your project root, create a file [root]/docker-compose.yml. Initially, give it the following contents:

services:

  vanilla:
    build:
      context: "./01-vanilla/"
      dockerfile: "./01-vanilla/Dockerfile"
    command: "caddy file-server --root /var/www/html/public/ --domain localhost"
    ports:
      - "7143:443"

Dockerfile for Basic Go Server

The Dockerfile needs to install Go, and download and install Caddy. Put it at [root]/01-vanilla/Dockerfile, and give it this contents:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
FROM ubuntu:latest

# Install dependencies
RUN apt-get update && apt-get install -y \
    curl \
    git \
    gcc \
    golang

# Set up Go environment
ENV GOPATH /go
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH

# Clone and compile Caddy
RUN git clone https://github.com/caddyserver/caddy.git /go/src/github.com/caddyserver/caddy
WORKDIR /go/src/github.com/caddyserver/caddy/
RUN go get -v ./...
RUN go build ./...
ENV PATH $PATH:/go/src/github.com/caddyserver/caddy/cmd/caddy

# Set up a static site
RUN mkdir -p /var/www/html/public/
RUN echo 'Hello, world!' > /var/www/html/public/index.html

# Expose HTTPS port
EXPOSE 443

Running the Vanilla Webserver

To run the basic webserver, type:

  • docker compose build
  • docker compose up -d

Navigate to https://localhost:7143 in Chrome, and reassure it that you want to proceed despite the fact of the certificate being self-signed. You should see your ‘hello world’ content. Check out the encryption like this:

  • Right-click anywhere on the page
  • ‘Inspect’
  • ‘Security’ tab

You should see a section like this:

Google Chrome developer tools saying that the encryption is X25519

Note that it’s saying the encryption is X25519 - elliptic curve cryptography.

Adding CFGo to Get Post-Quantum Cryptography

CFGo (Github) is Cloudflare’s fork of Go. It includes features added by Bas Westerbaan, who also added the contributions to Caddy we will be discussing later. CFGo adds, amongst other features, the X22519Kyber768Draft00 key exchange mechanism (KEM). This uses elliptic curve cryptography and Kyber PQC. This means even if some problem were to be discovered that makes Kyber susceptible to codebreaking on classical architecture, you still at least get the same protection you would with a normal TLS connection.

Let’s create a container to test it on, by adding this to the bottom of our docker-compose.yml file:

10
11
12
13
14
15
16
17
  
  cloudflare:
    build:
      context: .
      dockerfile: "./02-cloudflare/Dockerfile"
    command: "caddy file-server --root /var/www/html/public/ --domain localhost"
    ports:
      - "7243:443"

And we can create a Dockerfile at [root]/02-cloudflare/Dockerfile for it to use. It can start off as a copy of the previous Dockerfile, so from our project root directory let’s do:

  • mkdir ./02-cloudflare
  • cp ./01-vanilla/Dockerfile ./02-cloudflare/Dockerfile

Now we want to change [root]/02-cloudflare/Dockerfile to make go mean CFGo on the second container, so we need to apply the highlighted edits to the new Dockerfile:

 8
 9
10
11
12
13
14
15
16
17
    golang

# Set up Go environment
ENV GOPATH /go
RUN git clone https://github.com/cloudflare/go.git /go/src/github.com/cloudflare/go
WORKDIR /go/src/github.com/cloudflare/go/src/
RUN ./make.bash
ENV PATH /go/src/github.com/cloudflare/go/bin:$GOPATH/bin:$PATH

# Clone and compile Caddy

Our new container is now installing Cloudflare’s fork of Go before using it to compile Caddy.

Checking for PQC in the Cloudflare Go Container

Bounce the containers:

  • docker compose kill
  • docker compose rm -f
  • docker compose build
  • docker compose up -d

Now, simply navigate to localhost on the new port number in Chrome: https://localhost:7242, accept the self-signed certificate, and right click > ‘Inspect’ > ‘Security’:

some alt text

Our browser is now telling us that the X25519Kyber768Draft00 standard is being used in securing the TLS connection. Your connection is now quantum safe!

Summary

Cloudflare are already offering post-quantum cryptography for Caddy -> upstream, and they are saying browser -> Caddy will be next. Google Chrome is perfectly comfortable speaking in post-quantum lattices, and there are plans to add a similar feature to vanilla Go shortly, although you can get stuck in straight away with Cloudflare’s own dialect if you wish. Other post-quantum adopters include Signal, Whatsapp, and most lately iMessages. We may be in an early stage right now, but the rollout of post-quantum cryptography is well underway.