Repository: go
Issue: net/http: decide how users should use SetSessionTicketKeys with ServeTLS, etc
Labels: NeedsDecision,early-in-cycle

## 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](https://github.com/golang/go/blob/release-branch.go1.9/src/net/http/server.go#L2748) 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! :wink:

## 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:

```go
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)