Golang中TLS连接的问题

时间:2014-11-03 17:51:01

标签: ssl https go certificate ssl-certificate

我有以下证书层次结构:

Root - > CA - > 3个叶子证书

整个链都有serverAuth和clientAuth作为显式定义的扩展密钥用法。

在我的go代码中,我创建了一个tls.Config对象,如下所示:

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是证书链文件,keyFile是私钥文件。 caCertFile是信任库,只包含根证书

所以基本上,这是我希望在我的tls.Config对象中出现的函数:

RootCAs:来自caCertFile的根证书 ClientCAs:同样,只是来自caCertFile的根证书,与RootCAs相同 证书:单个证书链,包含certFile中的所有证书,被命令为叶子。

现在,我在这里有3件。服务器,中继和客户端。客户端直接连接到中继,中继又将请求转发给服务器。这三个部分使用相同的配置代码,当然使用不同的证书/密钥。 caCertFile在所有3件之间是相同的。

现在,如果我站起来服务器和继电器并从我的浏览器连接到继电器,一切顺利,所以我可以假设继电器和服务器之间的连接很好。当我尝试将我的客户端连接到中继时出现问题。当我这样做时,TLS握手失败并返回以下错误:

x509:由未知权限签署的证书

在继电器方面,我收到以下错误: http:TLS握手错误来自:远程错误:错误证书

我真的很茫然。我显然有不正确的设置,但我不知道是什么。从浏览器开始工作(意味着从中继到服务器的配置是正确的)真的很奇怪,但它不能与我的客户端使用相同的配置。

更新

因此,如果我将InsecureSkipVerify: true添加到中继和客户端上的tls.Config对象,则错误将更改为:

客户端上的

远程错误:错误证书

并在继电器上: http:TLS握手错误来自:tls:客户端没有提供证书

所以看起来客户端拒绝来自服务器(中继)的证书,因为它由于某种原因无效,因此从不将其证书发送到服务器(中继)。

我真的希望有更好的伐木。我甚至无法进入这个过程,看看到底发生了什么。

2 个答案:

答案 0 :(得分:0)

当你说

  

需要翻转数组,因为openssl以与golang tls预期相反的格式将其提供给我们。

我已经使用过openssl生成的证书,并且可以通过以下方式打开它们:

tls.LoadX509KeyPair(cert, key)

无论如何,错误消息错误的证书是由于服务器未设法将客户端提供的证书与其RootCA相匹配。我在Go中使用自签名证书也遇到了这个问题,我发现的唯一解决方法是将 caCertFile 安装到计算机系统证书中,并使用x509.SystemCertPool()代替x509.NewCertPool()。 也许其他人会有其他解决方案?

答案 1 :(得分:0)

在beldin0建议的内容旁边。 我尝试了另一种方法。

caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(crt)

client := &http.Client{
  //some config
  Transport: &http.Transport{
    TLSClientConfig: &tls.Config{
      RootCAs: caCertPool,
    },
  },
}

此处,变量“ crt”是证书中的内容。
基本上,您只需将其添加到代码中(或作为配置文件读取)。
那一切都会好起来的。