Repository: go
Issue: proposal: crypto/tls: support TLS 1.3 post-handshake authentication
Labels: Proposal,Proposal-Hold,Proposal-Crypto

### What version of Go are you using (`go version`)?
<pre>
$ go version 
go version go1.14.5 darwin/amd64
</pre>

### Does this issue reproduce with the latest release?
Yes

### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/felix/Library/Caches/go-build"
GOENV="/Users/felix/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/felix/workspace/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/Cellar/go/1.14.5/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.14.5/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/felix/workspace/tests/go-tls-pha/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/gr/j517787d56s73w50gnpv08gr0000gn/T/go-build528430427=/tmp/go-build -gno-record-gcc-switches -fno-common"
</pre></details>

### What did you do?
I use the Go TLS client to implement a client for an endpoint that requires authentication with client certificates. The endpoint decides if client authentication is needed based on the path in the HTTP request. Therefore, the server can only decide if client authentication is needed after the TLS connection has been fully set up. 

With TLS 1.3, the server would achieve the authentication with client certificates using post-handshake authentication. However, the Go TLS client does not support post-handshake authentication.

For reproduction of the issue, one can use the Apache httpd (I tested with version 2.4) with the config including the snippet below and a small go program like the one below.

#### httpd.conf snippet
```apache
<VirtualHost *:443>
    LogLevel debug

    SSLEngine on
    SSLCertificateFile /usr/local/apache2/conf/server.crt
    SSLCertificateKeyFile /usr/local/apache2/conf/server.key

    SSLVerifyClient none
    SSLCACertificateFile /usr/local/apache2/conf/ca.crt
    <Location "/test-cert.html">
        SSLVerifyClient require
        SSLVerifyDepth 1
    </Location>
</VirtualHost>
```

#### client.go
```go
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"time"

	"go.etcd.io/etcd/pkg/transport"
)

func main() {
	f, err := os.Create("./tls.keylog")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	tlsInfo := transport.TLSInfo{
		TrustedCAFile: "./ca.crt",
		CertFile:      "./client.crt",
		KeyFile:       "./client.key",
	}
	tlsTransport, err := transport.NewTransport(tlsInfo, 30*time.Second)
	if err != nil {
		log.Fatal(err)
	}
	tlsTransport.TLSClientConfig.KeyLogWriter = f

	client := &http.Client{
		Transport: tlsTransport,
	}

	r, err := client.Get("https://localhost/test-cert.html")
	if err != nil {
		log.Fatal(err)
	}

	defer r.Body.Close()
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%s\n", body)
}
```

### What did you expect to see?
I would have expected the TLS client to support TLS 1.3 post-handshake authentication and be able to connect to the endpoint.

### What did you see instead?
The server closes the connection to the client as soon as it encounters that a client certificate would be required for a specific route. In the httpd logs this error can be found: 

```
[ssl:debug] [pid 7:tid 139688389797632] ssl_engine_kernel.c(1148): [client 172.17.0.1:35172] AH10129: verify client post handshake
[ssl:error] [pid 7:tid 139688389797632] [client 172.17.0.1:35172] AH10158: cannot perform post-handshake authentication
[ssl:error] [pid 7:tid 139688389797632] SSL Library Error: error:14268117:SSL routines:SSL_verify_client_post_handshake:extension not received
172.17.0.1 - - [31/Jul/2020:19:40:50 +0000] "GET /test-cert.html HTTP/1.1" 403 258
```

This happens because the TLS client does not indicate support for post-handshake authentication in the ClientHello (which is actually correct, as it is not supported right now).

After looking at the TLS 1.3 client implementation, I think adding post-handshake authentication support for the TLS 1.3 client should be possible and I would be happy to help with this.