-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
Short version:
Using tls.Config.SetSessionTicketKeys
does not work with http.Server.ServeTLS
(and all methods that build on it, like ListenAndServeTLS
).
Problem arises because tls.Config
gets cloned inside ServeTLS
and there seems to be no way to reference the new one from "outside". If this behavior can't be changed, at least a mention in the docs might be nice! 😉
Long version:
What version of Go are you using (go version
)?
1.9 (but problem seems to be present starting with 1.5)
Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (go env
)?
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/costela/go"
GORACE=""
GOROOT="/usr/lib/go-1.9"
GOTOOLDIR="/usr/lib/go-1.9/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build167108121=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
PKG_CONFIG="pkg-config"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
What did you do?
Attempt to use tls.Config.SetSessionTicketKeys
on a running server, which is explicitly mentioned as possible in the docs:
httpsServer := &http.Server{
Addr: "localhost:https",
TLSConfig: &tls.Config{
SessionTicketKey: [32]byte{...some hard-coded key...}
},
}
go func() {
keys := make([][32]byte, 1)
for t := range time.Tick(10 * time.Second) {
bytes, _ := t.MarshalBinary()
copy(keys[0][:], bytes)
tlsConfig.SetSessionTicketKeys(keys) // yes, I'm aware this is highly insecure ;)
}
}()
log.Fatal(httpsServer.ListenAndServeTLS("some.crt", "some.key"))
And then checked to see if session-resumption works with:
$ openssl s_client -connect localhost:443 -sess_out session.tmp -quiet
$ openssl s_client -connect localhost:443 -sess_in session.tmp | grep Reused
What did you expect to see?
- session being reused in the first 10 seconds (using the hard-coded initial key)
- session being reused "inside" a 10 second tick (using the same time-based key)
- session not being reused "between" two 10 second ticks (using different time-based keys)
What did you see instead?
Session was reused in all scenarios, consistent with what would be expected because of the tls.Config
cloning mentioned in the "short" explanation above.
Why is this a problem?
Because there is no mention in the docs (or did I miss something?) that using ServeTLS
and friends will cause your reference to tls.Config
to become "useless", in the sense that it doesn't reflect the running server's state. Workaround would be to create your own net.Listener
, but that means a lot of boilerplate code, e.g. replicating tcpKeepAliveListener
, etc.
I think I understand why the clone might be necessary (I imagine it has to do with not changing it because it might be reused), but I can't think of a reason to not update the pointer in the http.Server
struct to point to the new clone. Am I missing something obvious?
But even if I am, it would be nice to mention this "gotcha" in the docs (I'd be happy to prepare a small PR for that if there are no objections)