Skip to content

Restrict TLS cipher suites to GCM/CHACHA20 and bump Go to 1.26.3 for SHA-1 removal#430

Open
pzeinlinger wants to merge 2 commits into
mjl-:mainfrom
pzeinlinger:tls-cipher-suites-hardening
Open

Restrict TLS cipher suites to GCM/CHACHA20 and bump Go to 1.26.3 for SHA-1 removal#430
pzeinlinger wants to merge 2 commits into
mjl-:mainfrom
pzeinlinger:tls-cipher-suites-hardening

Conversation

@pzeinlinger
Copy link
Copy Markdown

@pzeinlinger pzeinlinger commented May 9, 2026

Fixes #409.

Summary

Internet.nl's mail-server check flagged my mox instance for two TLS issues that boil down to Go's default TLS 1.2 configuration:

  1. Insufficient cipher suites: Go's default cipher list still includes TLS_ECDHE_ECDSA_WITH_AES_{128,256}_CBC_SHA, which NCSC-NL rates as insufficient (crypto/tls: Disable CBC Ciphers by default golang/go#13385 is open and unplanned).
  2. SHA-1 in key exchange: Go's TLS 1.2 server advertised SHA-1 as a supported signature algorithm — fixed in Go 1.25 per RFC 9155 (crypto/tls: disable SHA-1 signature algorithms in TLS 1.2 golang/go#72883), can be re-enabled with GODEBUG=tlssha1=1.

Changes

  • mox-/config.go: Explicitly set CipherSuites on Config, ConfigFallback, and ACMEConfig (right where MinVersion is already set) to only allow GCM and CHACHA20-POLY1305 suites that NCSC-NL rates as Sufficient. TLS 1.3 cipher suites remain non-configurable in Go and are always secure.
  • go.mod: Bump from 1.24.0 to 1.26.3 so the SHA-1 signature algorithm change from Go 1.25 takes effect.
  • docker-compose-integration.yml (separate commit): Pebble moved off Docker Hub, so the image reference is updated to ghcr.io/letsencrypt/pebble. Pinned to v2.6.0 — newer pebble releases contain breaking changes for our integration setup. The v2.6.0 image is distroless (no shell, no netstat), so pebble args are passed directly instead of via sh -c, the netstat-based healthcheck is dropped, and dependents now wait via service_started.

Allowed cipher suites after this change

TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

Test plan

  • go build ./... succeeds with Go 1.26.3
  • Cross-compiled GOOS=linux GOARCH=arm64 go build and ran ./mox version on Linux/aarch64
  • Re-ran https://internet.nl/mail/ against an instance built from this branch — 100% score, both "Cipher suites" and "Hash function for key exchange" subtests pass
  • make test-integration passes against the updated pebble image
  • Verified with a real test mail and a Thunderbird IMAP/SMTP connection — no client regressions

Notes

Happy to split the pebble change into a separate PR if preferred. Also happy to make the cipher suite list configurable via the TLS config struct rather than hardcoded, if you'd like to give operators an escape hatch.

The new distroless pebble image runs the binary as its entrypoint and
has
no shell or netstat. Pass pebble args directly and drop the
netstat-based
healthcheck; dependents now wait via service_started.
…SHA-1 removal

Internet.nl flagged the mail server as supporting insufficient TLS 1.2 cipher
suites (TLS_ECDHE_ECDSA_WITH_AES_{128,256}_CBC_SHA) and SHA-1 as a key
exchange hash. Explicitly set CipherSuites on the Config, ConfigFallback and
ACMEConfig to only allow GCM and CHACHA20-POLY1305 suites that NCSC-NL rates
as Sufficient. Bump go.mod to 1.26.3, which disables SHA-1 signature
algorithms in TLS 1.2 handshakes by default per RFC 9155.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Setting stricter TLS cipher suite

1 participant