← Knowledge base

Go (crypto/tls)

Is PQC enabled? — quick check

macOS / Linux / Windows

# 1) No-dependency check — identify this machine first.
uname -a 2>/dev/null || true

# 2) Dependency check — prompt before installing anything.
if ! command -v go >/dev/null 2>&1; then
  echo 'Go was not found.'
  printf 'Install or enable Go now? [y/N] '
  read answer
  case "$answer" in
    [Yy]*) echo 'Install Go 1.23+ from your OS package manager or go.dev, then rerun this snippet.' ;;
    *) echo 'Skipping Go-based check.'; exit 1 ;;
  esac
fi

go version

# Quick inline probe — Go 1.23+ negotiates X25519MLKEM768 by default
# when the server offers it. The connection state exposes the group.
cat <<'EOF' | go run -
package main
import ("crypto/tls"; "fmt")
func main() {
  c, err := tls.Dial("tcp", "example.com:443", &tls.Config{ServerName: "example.com"})
  if err != nil { fmt.Println("err:", err); return }
  defer c.Close()
  s := c.ConnectionState()
  fmt.Printf("tls=%x cipher=%s curveID=%d\n",
    s.Version, tls.CipherSuiteName(s.CipherSuite), s.CurveID)
}
EOF

Expected when PQC is ON

go version go1.23.4 darwin/arm64
tls=304 cipher=TLS_AES_128_GCM_SHA256 curveID=4588
# 4588 = 0x11EC = X25519MLKEM768

What you'll see when PQC is OFF

go version go1.22.6 linux/amd64
tls=304 cipher=TLS_AES_128_GCM_SHA256 curveID=29
# 29 = X25519 — Go ≤ 1.22 has no ML-KEM in crypto/tls

Go 1.23 negotiates X25519MLKEM768 automatically. Earlier versions cannot, regardless of GODEBUG flags.

Go 1.23 (Aug 2024) added X25519MLKEM768 to the default TLS 1.3 group list as the highest-priority option. Any HTTP server, gRPC service, database driver, or reverse proxy built on Go 1.23+ negotiates hybrid PQC automatically with capable peers.

Confirm your runtime

if ! command -v go >/dev/null 2>&1; then
  echo 'Go was not found.'
  printf 'Install Go 1.23+ now? [y/N] '; read answer
  case "$answer" in [Yy]*) echo 'Install Go from https://go.dev/dl/ or your OS package manager, then rerun.' ;; *) exit 1 ;; esac
  exit 1
fi
go version
# go version go1.23.x ...

Default behavior

You don't need to set tls.Config.CurvePreferences. The defaults already include X25519MLKEM768 first. If you've explicitly set CurvePreferences, either remove it or include tls.X25519MLKEM768:

cfg := &tls.Config{
    MinVersion: tls.VersionTLS12,
    CurvePreferences: []tls.CurveID{
        tls.X25519MLKEM768,
        tls.X25519,
        tls.CurveP256,
    },
}

GODEBUG knobs

You can disable hybrid PQC for compatibility testing with GODEBUG=tlsmlkem=0 (default 1 since 1.23). The default flips to tlsmlkem=1 permanently in 1.24.

Servers

Caddy, Traefik (Go), MinIO, etcd, Vault, Consul, Tailscale's tsnet, NATS, all current Go reverse proxies and HTTP servers — all inherit hybrid PQC for free with a Go 1.23+ build.

Run the check on your service →