RequireAndVerifyClientCert

1,304 views
Skip to first unread message

jean.andr...@gmail.com

unread,
Nov 30, 2013, 11:44:51 AM11/30/13
to golan...@googlegroups.com
Hey all,

I'm trying to authenticate clients with TLS in go, using self signed certificates. I have few questions.

I joined the keys and certs I use for my tests. They have been generated with extendedKeyUsage = serverAuth,clientAuth as needed by the golang implementation.

I succeded to establish a connection using
$ openssl s_server -accept 5640 -cert server.cert -key server.privkey -CAfile client.cert -tls1
$ openssl s_client -connect localhost:5640 -cert client.cert -key client.privkey -CAfile server.cert -tls1

and got a Verify return code: 0 (ok)

So I think my test keys and certificates are ok...

My go code looks like this on the server side:

certpool := x509.NewCertPool()
pem, err := ioutil.ReadFile("client.cert")
success := certpool.AppendCertsFromPEM(pem)

if ! success {
log.Println("can't parse cert pool")
return
}

cert, err := tls.LoadX509KeyPair("server.cert", "server.privkey")
if err != nil {
log.Println(fmt.Sprintf("Error: %s", err))
return
}

ls, oerr := tls.Listen("tcp", *addr, &tls.Config{
Rand:               rand.Reader,
Certificates:       []tls.Certificate{cert},
CipherSuites:       []uint16{tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA},
ClientAuth:         tls.RequireAndVerifyClientCert,
ClientCAs:          certpool,
InsecureSkipVerify: true,
})
if oerr != nil {
log.Println("can't listen:", oerr)
return
}

err = rsrv.srv.StartListener(ls)
if err != nil {
log.Println(fmt.Sprintf("Error: %s", err))
return
}

And on the client side:

certpool := x509.NewCertPool()
pem, err := ioutil.ReadFile("server.cert")
success := certpool.AppendCertsFromPEM(pem)
if ! success {
log.Println("can't parse cert pool")
return
}

cert, err := tls.LoadX509KeyPair("client.cert", "client.privkey")
if err != nil {
log.Println(fmt.Sprintf("Error: %s", err))
return
}

c, oerr := tls.Dial("tcp", *addr, &tls.Config{
ServerName:         "localhost",
Rand:               rand.Reader,
Certificates:       []tls.Certificate{cert},
CipherSuites:       []uint16{tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA},
RootCAs:            certpool,
InsecureSkipVerify: true,
})
if oerr != nil {
log.Println("can't dial", oerr)
return
}

Now here are my questions.

1) My client cannot connect my server if I dont set the client RequireAndVerifyClientCert to true, otherwise I get a "x509: certificate signed by unknown authority". However, I provided my own ClientCAs, and I want the client certificate to be checked against these.
2) Why do I get a "remote error: bad certificate" when my client tries to connect the server? Is my certpool wrong?
3) What is the difference between RootCAs and ClientCAs? I use RootCAs on client side and ClientCAs on server side, but other implementations of tls does not differenciate these two.
4) If I realy want to authenticate my clients, is RequireAndVerifyClientCert the only option? How is it affected by InsecureSkipVerify exactly?

Thank you
client.cert
client.privkey
server.cert
server.privkey

Alex Zorin

unread,
Dec 1, 2013, 1:10:01 AM12/1/13
to golan...@googlegroups.com, jean.andr...@gmail.com
This is the error I get with your code and certificates:

> can't dial x509: certificate signed by unknown authority (possibly because of "x509: invalid signature: parent certificate cannot sign this kind of certificate" while trying to verify candidate authority certificate "localhost")
 
As I understand it, this setup isn't valid because the client certificate was not signed using a CA certificate. Have a look at http://golang.org/src/pkg/crypto/x509/x509.go, in particular 'CheckSignatureFrom'.

I believe you should be able to get this working correctly if you setup a private CA, such as in http://www.g-loaded.eu/2005/11/10/be-your-own-ca/ 

Alex
Reply all
Reply to author
Forward
0 new messages