title: Issues with TLS connection in Golang
body: <p>I have the following certificate hierarchy:</p>
  
  <p>Root-->CA-->3 leaf certificates</p>
  
  <p>The entire chain has both serverAuth and clientAuth as extended key usages explicitly defined.</p>
  
  <p>In my go code, I create a tls.Config object like so:</p>
  
  <pre><code>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 &gt;=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 = &amp;tls.Config {
          CipherSuites: ciphers,
          ClientAuth: tls.RequireAndVerifyClientCert,
          PreferServerCipherSuites: true,
          RootCAs: certPool,
          ClientCAs: certPool,
          Certificates: []tls.Certificate{c},
      }
  
      return
  }
  </code></pre>
  
  <p>certFile is the certificate chain file and keyFile is the private key file. caCertFile is the truststore and consists of just the root certificate</p>
  
  <p>So basically, here is what I expect to have inside of my tls.Config object that comes out of this function:</p>
  
  <p>RootCAs: Just the root certificate from caCertFile
  ClientCAs: Again, just the root certificate from caCertFile, same as RootCAs
  Certificates: A single certificate chain, containing all of the certificates in certFile, ordered to be leaf first.</p>
  
  <p>Now, I have 3 pieces here. A server, a relay, and a client. The client connects directly to the relay, which in turn forwards the request to the server. All three pieces use the same configuration code, of course using different certs/keys. The caCertFile is the same between all 3 pieces.</p>
  
  <p>Now, if I stand up the server and the relay and connect to the relay from my browser, all goes well, so I can assume that the connection between relay and server is fine. The issue comes about when I try to connect my client to the relay. When I do so, the TLS handshake fails and the following error is returned:</p>
  
  <p><strong>x509: certificate signed by unknown authority</strong></p>
  
  <p>On the relay side of things, I get the following error:
  <strong>http: TLS handshake error from : remote error: bad certificate</strong></p>
  
  <p>I am really at a loss here. I obviously have something setup incorrectly, but I am not sure what. It's really weird that it works from the browser (meaning that the config is correct from relay to server), but it doesn't work with the same config from my client. </p>
  
  <h2>Update:</h2>
  
  <p>So if I add <code>InsecureSkipVerify: true</code> to my tls.Config object on both the relay and the client, the errors change to:</p>
  
  <p>on the client: <strong>remote error: bad certificate</strong></p>
  
  <p>and on the relay: <strong>http: TLS handshake error from : tls: client didn't provide a certificate</strong></p>
  
  <p>So it looks like the client is rejecting the certificate on from the server (the relay) due to it being invalid for some reason and thus never sending its certificate to the server (the relay).</p>
  
  <p>I really wish go had better logging. I can't even hook into this process to see what, exactly, is going on.</p>