Please answer these questions before submitting your issue. Thanks!
- What version of Go are you using (
go version)?
go version go1.6.3 linux/amd64
- What operating system and processor architecture are you using (
go env)?
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/opt/go/ext"
GORACE=""
GOROOT="/opt/go/golang"
GOTOOLDIR="/opt/go/golang/pkg/tool/linux_amd64"
GO15VENDOREXPERIMENT="1"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0"
CXX="g++"
CGO_ENABLED="1"
- Feature request:
Requirement for a customized selection of a client certificate during TLS handshake with a server. The current implementation in crypto/tls/handshake_client.go uses the first certificate that is signed by an acceptable CA. The application cannot set the client cert in tls.Config.Certificates based on user selection before calling conn.Handshake(), because it has no way to tell which CAs will be accepted by a server in a handshake.
The problem was locally fixed by cloning crypto/tls and applying the following changes. If the requirement is considered legit and usually useful, feel free to use and modify it as you see fit:
crypto/tls/common.go:
// ServerHelloInfo contains information from a ServerHello message in order to
// guide certificate selection in the GetClientCertificate callback.
type ServerHelloInfo struct {
// CertCAs lists the CA root certificates accepted for successful
// client authentication.
CertCAs [][]byte
// CertTypes lists the supported certificate types for each CA cert.
CertTypes []byte
}
:
type Config struct {
:
// GetClientCertificate returns a Certificate based on the given
// ServerHelloInfo. It will only be called if the server requests
// client authentication and if Certificates is empty.
//
// If GetClientCertificate is nil or returns nil, no client certificate
// is send to the server as a response.
GetClientCertificate func(serverHello *ServerHelloInfo) (*Certificate, error)
:
}
crypto/tls/handshake_client.go(doFullHandshake):
:
// If no client certs are available in Config and the
// GetClientCertificate callback is defined, get a
// certificate from the callback function.
//
// It is the responsibility of the callback to return
// an appropriate certificate.
if c.config.Certificates == nil && c.config.GetClientCertificate != nil {
hello := &ServerHelloInfo{
CertCAs: certReq.certificateAuthorities,
CertTypes: certReq.certificateTypes,
}
if chainToSend, err = c.config.GetClientCertificate(hello); err != nil {
return err
}
} else {
// We need to search our list of client certs for one
// where SignatureAlgorithm is acceptable to the server and the
// Issuer is in certReq.certificateAuthorities
findCert:
for i, chain := range c.config.Certificates {
:
}
}
crypto/tls/tls_test.go(TestClone):
:
case "Time", "GetCertificate", "GetClientCertificate":
:
Please answer these questions before submitting your issue. Thanks!
go version)?go version go1.6.3 linux/amd64
go env)?GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/opt/go/ext"
GORACE=""
GOROOT="/opt/go/golang"
GOTOOLDIR="/opt/go/golang/pkg/tool/linux_amd64"
GO15VENDOREXPERIMENT="1"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0"
CXX="g++"
CGO_ENABLED="1"
Requirement for a customized selection of a client certificate during TLS handshake with a server. The current implementation in crypto/tls/handshake_client.go uses the first certificate that is signed by an acceptable CA. The application cannot set the client cert in tls.Config.Certificates based on user selection before calling conn.Handshake(), because it has no way to tell which CAs will be accepted by a server in a handshake.
The problem was locally fixed by cloning crypto/tls and applying the following changes. If the requirement is considered legit and usually useful, feel free to use and modify it as you see fit:
crypto/tls/common.go:
crypto/tls/handshake_client.go(doFullHandshake):
crypto/tls/tls_test.go(TestClone):