使用自签名证书进行TLS连接失败

时间:2016-05-06 10:44:21

标签: ssl curl go tls1.2

以下简化的测试用例代码在我的笔记本电脑上本地运行时使用我自己的“开发人员”证书来访问内部服务

如果我在具有动态生成的证书的远程计算机上运行(所有这些证书都由我的组织中的一个单独的团队处理),则会失败并显示400并且“未发送所需的SSL证书”错误

但是,如果我在远程计算机上使用curl,并指定与我的Go代码中引用的相同的证书,它将起作用

所以看来证书不是问题,而是Go代码,但这本身似乎不是问题,因为它与我自己的本地证书一起工作

package main

import (
  "crypto/tls"
  "crypto/x509"
  "fmt"
  "io/ioutil"
  "net/http"
  "os"
  "time"
)

func main() {
  transport, transErr := configureTLS()
  if transErr != nil {
    fmt.Printf("trans error: %s", transErr.Error())
    return
  }

  timeout := time.Duration(1 * time.Second)
  client := http.Client{
    Transport: transport,
    Timeout:   timeout,
  }
  resp, clientErr := client.Get("https://my-service-with-nginx/")

  if clientErr != nil {
    fmt.Printf("client error: %s", clientErr.Error())
  } else {
    defer resp.Body.Close()

    contents, contErr := ioutil.ReadAll(resp.Body)
    if contErr != nil {
      fmt.Printf("contents error: %s", contErr.Error())
    }

    fmt.Printf("\n\ncontents:\n\n%+v", string(contents))
  }
}

func configureTLS() (*http.Transport, error) {
  certPath := "/path/to/client.crt"
  keyPath := "/path/to/client.key"
  caPath := "/path/to/ca.crt"

  // Load client cert
  cert, err := tls.LoadX509KeyPair(certPath, keyPath)
  if err != nil {
    return nil, err
  }

  // Load CA cert
  caCert, err := ioutil.ReadFile(caPath)
  if err != nil {
    return nil, err
  }
  caCertPool := x509.NewCertPool()
  caCertPool.AppendCertsFromPEM(caCert)

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

  return &http.Transport{TLSClientConfig: tlsConfig}, nil
}

有谁知道为什么会发生这种情况?

我认为这可能是Go的重新协商错误(截至1.6),但我不认为这是在这种情况,否则当我在本地运行应用程序时它会失败(但它没有,使用我的自己的开发证书和本地运行工作正常 - 问题只发生在具有不同证书的远程实例上;并且这些证书不是问题,因为它们在curl使用时工作正常

1 个答案:

答案 0 :(得分:0)

所以这里的实际问题是与我的组织基础架构相关的部分,以及与nginx如何使用ssl_client_certificate相关的部分。

我们有int,测试和实时环境

我被引导相信环境可以相互通信。

所以我在int上进行了服务设置,然后我就可以使用curl与实时环境中的其他服务设置进行通信。

使用Go跨环境进行通信时出现问题。

对我来说,快速解决方案是确保我对其他服务进行GET时,而不是使用:

https://service.live.me.com

我会用:

https://service.int.me.com

或者:

https://service.test.me.com

取决于我的代码在其中运行的环境。

显然,对于遇到类似问题但没有相同设置的其他人来说,这不是一个解决方案。

那么对于那些仍然需要解决方案的人来说......

我还要尝试(并且显然适用于this guy)是为了获取我尝试与之通信的服务来修改他们的nginx conf,以便他们将ssl_client_certificate设置为不指向仅限客户端证书,但组合证书(包含整个CA链的证书)。

这是因为显然Go并没有发回任何带有响应的证书,除非服务器已通过CA及其响应。

我原本怀疑这是Go 1.6及以下版本中经典的重新协商错误,但在这种情况下情况并非如此。

希望这可以帮助其他人在同一条船上。