I have the following certificate hierarchy:
Root β CA β 3 sheet certificates
The entire chain has both serverAuth and clientAuth, as explicitly defined usage restrictions.
In my go code, I create a tls.Config object as follows:
func parseCert(certFile, keyFile string) (cert tls.Certificate, err error) { certPEMBlock , err := ioutil.ReadFile(certFile) if err != nil { return } var certDERBlock *pem.Block for { certDERBlock, certPEMBlock = pem.Decode(certPEMBlock) if certDERBlock == nil { break } if certDERBlock.Type == "CERTIFICATE" { cert.Certificate = append(cert.Certificate, certDERBlock.Bytes) } } // Need to flip the array because openssl gives it to us in the opposite format than golang tls expects. cpy := make([][]byte, len(cert.Certificate)) copy(cpy, cert.Certificate) var j = 0 for i := len(cpy)-1; i >=0; i-- { cert.Certificate[j] = cert.Certificate[i] j++ } keyData, err := ioutil.ReadFile(keyFile) if err != nil { return } block, _ := pem.Decode(keyData) if err != nil { return } ecdsaKey, err := x509.ParseECPrivateKey(block.Bytes) if err != nil { return } cert.PrivateKey = ecdsaKey return } // configure and create a tls.Config instance using the provided cert, key, and ca cert files. func configureTLS(certFile, keyFile, caCertFile string) (tlsConfig *tls.Config, err error) { c, err := parseCert(certFile, keyFile) if err != nil { return } ciphers := []uint16 { tls.TLS_RSA_WITH_AES_256_CBC_SHA, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, } certPool := x509.NewCertPool() buf, err := ioutil.ReadFile(caCertFile) if nil != err { log.Println("failed to load ca cert") log.Fatal(seelog.Errorf("failed to load ca cert.\n%s", err)) } if !certPool.AppendCertsFromPEM(buf) { log.Fatalln("Failed to parse truststore") } tlsConfig = &tls.Config { CipherSuites: ciphers, ClientAuth: tls.RequireAndVerifyClientCert, PreferServerCipherSuites: true, RootCAs: certPool, ClientCAs: certPool, Certificates: []tls.Certificate{c}, } return }
certFile is a certificate chain file, and keyFile is a private key file. caCertFile is a trusted store and consists only of a root certificate
So basically, this is what I expect to have inside my tls.Config object, which exits this function:
RootCAs: only the root certificate from caCertFile ClientCAs: again, only the root certificate from caCertFile, the same as RootCAs Certificates: the only certificate chain containing all the certificates in certFile, which must first be a leaf.
Now I have 3 parts. Server, relay, and client. The client connects directly to the relay, which, in turn, redirects the request to the server. All three parts use the same configuration code, of course, using different certificates / keys. CaCertFile is the same between all three parts.
Now, if I get up on the server and relay and connect to the relay from my browser, everything is going well, so I can assume that the connection between the relay and the server is fine. The problem occurs when I try to connect my client to a relay. When I do this, the TLS confirmation message fails and the following error is returned:
x509: certificate signed by an unknown authority
On the relay side, I get the following error: http: TLS handshake error: remote error: bad certificate
I am really at a loss. I obviously have something wrong configured, but I'm not sure what. It is strange that it works in the browser (this means that the configuration is correct from the relay to the server), but it does not work with the same configuration of my client.
Update:
So, if I add InsecureSkipVerify: true to my tls.Config object for both the relay and the client, the errors change to:
on the client: remote error: bad certificate
and on the relay: HTTP connection establishment error: TLS: tls: client did not provide a certificate
Thus, it seems that the client rejects the certificate from the server (relaying) due to the fact that for some reason it is not valid and, therefore, never sends its certificate to the server (relay).
I really want to have a better registration. I canβt even connect to this process to find out what exactly is happening.