Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crypto/tls: EncryptedClientHelloKeys can't be safely rotated when GetConfigForClient is used #71920

Open
mholt opened this issue Feb 24, 2025 · 2 comments
Labels
BugReport Issues describing a possible bug in the Go implementation. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.

Comments

@mholt
Copy link

mholt commented Feb 24, 2025

Go version

go version go1.24.0 linux/amd64

Output of go env in your module/workspace:

AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/matt/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/matt/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1380606169=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/home/matt/Dev/caddyserver/caddy/go.mod'
GOMODCACHE='/home/matt/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/matt/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='on'
GOTELEMETRYDIR='/home/matt/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/lib/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.0'
GOWORK=''
PKG_CONFIG='pkg-config'

What did you do?

I'm attempting to implement the ECH spec with regards to key rotation. It states in 10.10.5:

This design is not forward secret because the server's ECH key is static. However, the window of exposure is bound by the key lifetime. It is RECOMMENDED that servers rotate keys frequently.

The application (Caddy in this case) requires use of GetConfigForClient.

What did you see happen?

The problem is, tls.Config.EncryptedClientHelloKeys is a static field, not a callback like GetCertificate.

This means we have to start a new TLS server with the updated ECH keys, which is complex and can be tricky to do without downtime.

I also realized that GetConfigForClient is not recursive... at first I tried using GetConfigForClient to return a tls.Config populated especially for ECH:

// ECH keys loaded dynamically for the outer SNI, which
// solves the key rotation problem
// ...
return &tls.Config{
	MinVersion:               tls.VersionTLS13,
	GetConfigForClient:       getConfigForClient, // loads config for inner SNI
	EncryptedClientHelloKeys: stdECHKeys,
}, nil

But this results in "no certificates configured", because the returned Config's GetConfigForClient isn't called, and sure enough it has no certs. Relevant code:

https://cs.opensource.google/go/go/+/master:src/crypto/tls/handshake_server.go;l=148-168?q=GetConfigForClient&ss=go%2Fgo&start=11

But we can't return the final tls.Config yet (the one with certificates) because we don't have the inner SNI yet.

What did you expect to see?

I was hoping that GetConfigForClient + EncryptedClientHelloKeys could play well together... in the case of ECH, maybe allow GetConfigForClient to be used to unwrap the outer Hello, and also be used for the inner. (i.e. allow calling it twice, once before once after processing ECH) Or, make a new field, GetEncryptedClientHelloKeys callback function, much like GetCertificate.

  • We can't forfeit the use of GetConfigForClient due to dynamic configuration requirements.
  • But EncryptedClientHelloKeys must be changed after the server has started

Rotating keys is beneficial for security and encouraged by the spec.

Do you have any other suggestions for making this work as-is? Or is this something that can be enhanced?

Thanks again for server-side ECH 💯

@gabyhelp gabyhelp added the BugReport Issues describing a possible bug in the Go implementation. label Feb 24, 2025
@prattmic prattmic added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Feb 24, 2025
@prattmic
Copy link
Member

cc @FiloSottile @rolandshoemaker @golang/security

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BugReport Issues describing a possible bug in the Go implementation. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

3 participants