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

Closed
miha- opened this issue Feb 19, 2018 · 3 comments
Closed

crypto/tls: client certificate not sent #23924

miha- opened this issue Feb 19, 2018 · 3 comments

Comments

@miha-
Copy link

@miha- miha- 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 GORACE=
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_ENABLED=1
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config

func main() {

	xml := `
	<Packet>
<Header>
 <ID>1231232132132354234</ID>
 </Header>
 <Body>
 <Item>
 <Content>SMS</Content>
 <Phone_no>+123213</Phone_no>
 <Content>test</Content>
 <OriginAddress>Posiljatelj</OriginAddress>
 </Item>
 </Body>
</Packet>
	`

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

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

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

	//tlsConfig.BuildNameToCertificate()
	transport := &http.Transport{TLSClientConfig: tlsConfig}
	client := &http.Client{Transport: transport}

	resp, err := client.Post("https://api.test.si/test/PdPush", "text/xml", bytes.NewBuffer([]byte(xml)))

	if err != nil {
		fmt.Println(err)
	}
	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.

slika_jpg

I also attached wireshark trace.

@mvdan

This comment has been minimized.

Copy link
Member

@mvdan 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? https://golang.org/wiki/Questions

@miha-

This comment has been minimized.

Copy link
Author

@miha- miha- commented Feb 20, 2018

@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 :(

@FiloSottile

This comment has been minimized.

Copy link
Member

@FiloSottile FiloSottile commented Feb 21, 2018

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
findCert:
for i, chain := range c.config.Certificates {
if !rsaAvail && !ecdsaAvail {
continue
}
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 {
c.sendAlert(alertInternalError)
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:
default:
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.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.