Golang中TLS连接的问题

jon*_*zza 8 ssl https certificate ssl-certificate go

我有以下证书层次结构:

根 - > 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
}
Run Code Online (Sandbox Code Playgroud)

certFile是证书链文件,keyFile是私钥文件.caCertFile是信任库,只包含根证书

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

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

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

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

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

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

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

更新:

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

在客户端:远程错误:错误的证书

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

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

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

小智 4

当你说

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

我使用了 openssl 生成的证书,并且使用以下命令打开它们没有问题:

tls.LoadX509KeyPair(cert, key)
Run Code Online (Sandbox Code Playgroud)

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