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

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


如果我在具有动态生成的证书(所有这些都由我组织中的一个单独的团队处理)的远程计算机上运行,它会失败并显示 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)


三国纷争
浏览 296回答 1
1回答

偶然的你

所以这里的实际问题部分与我的组织基础设施有关,部分与 nginx 的使用方式有关ssl_client_certificate。我们有 int、test 和 live 环境我被引导相信环境可以相互交流。所以我在 int 上设置了我的服务,并且我能够从那里使用 curl 与实时环境中的另一个服务设置进行通信。使用 Go 跨环境通信时出现问题。对我来说,快速的解决方案是确保当我对其他服务进行 GET 时,而不是使用:https://service.live.me.com我会使用:https://service.int.me.com或者:https://service.test.me.com根据我的代码运行的环境。显然,对于有类似问题但没有相同设置的其他人来说,这不是解决方案。所以对于那些仍然需要解决方案的人......我还将尝试(并且显然为这个人工作)是让我试图与之通信的服务来修改他们的 nginx conf,以便他们设置ssl_client_certificate不只是指向客户端证书,而是指向组合证书(包括整个 CA 链)。这是因为显然 Go 不会在其响应中发回任何证书,除非服务器已通过 CA 及其响应。我最初怀疑这是 Go 1.6 及更低版本中的经典重新协商错误,但在这种情况下并非如此。希望这可以帮助同一条船上的其他人。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go