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: client certificate not sent #23924

mihazoubek opened this issue Feb 19, 2018 · 3 comments

crypto/tls: client certificate not sent #23924

mihazoubek opened this issue Feb 19, 2018 · 3 comments


Copy link

mihazoubek commented Feb 19, 2018

Version: go version go1.9.2 windows/amd64
I also tested this in linux and it is the same
Windows or Linux
set GOARCH=amd64
set GOBIN=
set GOEXE=.exe
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=windows
set GOPATH=D:\Temp\goLang
set GOROOT=C:\Go
set GOTOOLDIR=C:\Go\pkg\tool\windows_amd64
set GCCGO=gccgo
set CC=gcc
set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0
set CXX=g++
set CGO_CFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config

func main() {

	xml := `

	// Load client cert
	cert, err := tls.LoadX509KeyPair("../cert/certNEW.pem", "../cert/serverNEW.key")
	if err != nil {

	// Load CA cert
	caCert, err := ioutil.ReadFile("../cert/telekomsi.crt")
	if err != nil {
	caCertPool := x509.NewCertPool()

	// Setup HTTPS client
	tlsConfig := &tls.Config{
		Certificates:       []tls.Certificate{cert},
		RootCAs:            caCertPool,
		InsecureSkipVerify: false,

	transport := &http.Transport{TLSClientConfig: tlsConfig}
	client := &http.Client{Transport: transport}

	resp, err := client.Post("", "text/xml", bytes.NewBuffer([]byte(xml)))

	if err != nil {
	contents, err := ioutil.ReadAll(resp.Body)
	fmt.Printf("%s\n", string(contents))

The issue is that I send request to server, servers sends back request to present client certificate for auth, but certificate is not send it client respons.


I also attached wireshark trace.

Copy link

mvdan commented Feb 19, 2018

This seems like a question more than a bug report. Have you posted this on one of the forums or mailing lists?

Copy link

@mvdan agree, but noboday really knows how to solve this as everyone are saying that i am doing it in the right way. That is why i opened ticket here :(

Copy link

Hi @miha-, what I think is happening here is that the Certificate Request applies constraints (RSA vs ECDSA, or a specific issuer) which are not satisfied by your certificate.

The full logic is here:

func (hs *clientHandshakeState) getCertificate(certReq *certificateRequestMsg) (*Certificate, error) {
c := hs.c
var rsaAvail, ecdsaAvail bool
for _, certType := range certReq.certificateTypes {
switch certType {
case certTypeRSASign:
rsaAvail = true
case certTypeECDSASign:
ecdsaAvail = true
if c.config.GetClientCertificate != nil {
var signatureSchemes []SignatureScheme
if !certReq.hasSignatureAndHash {
// Prior to TLS 1.2, the signature schemes were not
// included in the certificate request message. In this
// case we use a plausible list based on the acceptable
// certificate types.
signatureSchemes = tls11SignatureSchemes
if !ecdsaAvail {
signatureSchemes = signatureSchemes[tls11SignatureSchemesNumECDSA:]
if !rsaAvail {
signatureSchemes = signatureSchemes[:len(signatureSchemes)-tls11SignatureSchemesNumRSA]
} else {
signatureSchemes = certReq.supportedSignatureAlgorithms
return c.config.GetClientCertificate(&CertificateRequestInfo{
AcceptableCAs: certReq.certificateAuthorities,
SignatureSchemes: signatureSchemes,
// RFC 4346 on the certificateAuthorities field: A list of the
// distinguished names of acceptable certificate authorities.
// These distinguished names may specify a desired
// distinguished name for a root CA or for a subordinate CA;
// thus, this message can be used to describe both known roots
// and a desired authorization space. If the
// certificate_authorities list is empty then the client MAY
// send any certificate of the appropriate
// ClientCertificateType, unless there is some external
// arrangement to the contrary.
// 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
for i, chain := range c.config.Certificates {
if !rsaAvail && !ecdsaAvail {
for j, cert := range chain.Certificate {
x509Cert := chain.Leaf
// parse the certificate if this isn't the leaf
// node, or if chain.Leaf was nil
if j != 0 || x509Cert == nil {
var err error
if x509Cert, err = x509.ParseCertificate(cert); err != nil {
return nil, errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error())
switch {
case rsaAvail && x509Cert.PublicKeyAlgorithm == x509.RSA:
case ecdsaAvail && x509Cert.PublicKeyAlgorithm == x509.ECDSA:
continue findCert
if len(certReq.certificateAuthorities) == 0 {
// they gave us an empty list, so just take the
// first cert from c.config.Certificates
return &chain, nil
for _, ca := range certReq.certificateAuthorities {
if bytes.Equal(x509Cert.RawIssuer, ca) {
return &chain, nil
// No acceptable certificate found. Don't send a certificate.
return new(Certificate), nil

You can bypass the default logic by using tls.Config.GetClientCertificate.

Feel free to reopen this if you think this is a bug.

FYI, you leaked the server IP in the details part of the screenshot.

@FiloSottile FiloSottile changed the title Issue with sending certificate in client response crypto/tls: client certificate not sent Feb 21, 2018
@golang golang locked and limited conversation to collaborators Mar 3, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
None yet

No branches or pull requests

4 participants