首页 >后端开发 >Golang >为什么我会遇到'连接失败:x509:证书依赖于旧版公用名字段,使用 SAN 或暂时启用与 GODEBUG=x509ignoreCN=0 匹配的公用名”错误

为什么我会遇到'连接失败:x509:证书依赖于旧版公用名字段,使用 SAN 或暂时启用与 GODEBUG=x509ignoreCN=0 匹配的公用名”错误

Barbara Streisand
Barbara Streisand原创
2024-10-28 12:10:30718浏览

Why am I encountering the

错误:Go TLS 连接中的证书字段差异

尝试使用 Go 与 MongoDB 服务器建立 TLS 连接时,您可能会遇到以下错误:

failed to connect: x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0

原因:

当服务器的 TLS 证书依赖旧版通用名称 (CN) 字段进行识别时,会发生此错误,但 Go 的运行时默认使用主题备用名称 (SAN) 进行 TLS 连接。

解决方案:

解决此问题的主要方法有两种:

1.利用服务器证书中的 SAN:

  • 使用与用于连接到服务器的主机名或 IP 地址相匹配的 SAN 重新生成服务器证书。
  • 这可以通过使用来实现OpenSSL 或第三方证书颁发机构等工具。

2.暂时禁用 CN 匹配:

如果无法立即重新生成服务器证书,可以通过设置环境变量来暂时禁用 CN 匹配:

GODEBUG=x509ignoreCN=0

但这不是一个长期解决方案,只能用于临时建立连接。

代码实现:

如果您选择在 Go 代码中修复问题,请确保您加载的证书包含与连接期间使用的主机名匹配的 SAN。以下是您提供的代码片段的更新版本:

<code class="go">const CONFIG_DB_CA = "/etc/ca-files/new-mongo.ca.crt"

func main() {
    cer, err := tls.LoadX509KeyPair("/mongo-server.crt", "/mongo-server.key")
    if err != nil {
        log.Println(err)
        return
    }

    roots := x509.NewCertPool()
    ca, err := ioutil.ReadFile(CONFIG_DB_CA)
    if err != nil {
        fmt.Printf("Failed to read or open CA File: %s.\n", CONFIG_DB_CA)
        return
    }
    roots.AppendCertsFromPEM(ca)

    tlsConfig := &tls.Config{
        Certificates: []tls.Certificate{cer},
        RootCAs:      roots,
        VerifyPeerCertificate: func(rawCerts [][]*x509.Certificate) error {
            for _, certs := range rawCerts {
                for _, cert := range certs {
                    if len(cert.Subject.CommonName) > 0 {
                        continue
                    }
                    for _, dns := range cert.DNSNames {
                        if dns == "customhost" || dns == "customhost:port" {
                            return nil
                        }
                    }
                    return errors.New("certificate does not contain a SAN for the host")
                }
            }
            return errors.New("no valid certificate found")
        },
    }

    conn, err := tls.Dial("tcp", "customhost:port", tlsConfig)
    if err != nil {
        fmt.Printf("failed to connect: %v.\n", err)
        return
    }

    err = conn.VerifyHostname("customhost")
    if err != nil {
        panic("Hostname doesn't match with certificate: " + err.Error())
    }
    for i, cert := range conn.ConnectionState().PeerCertificates {
        prefix := fmt.Sprintf("CERT%d::", i+1)
        fmt.Printf("%sIssuer: %s\n", prefix, cert.Issuer)
        fmt.Printf("%sExpiry: %v\n", prefix, cert.NotAfter.Format(time.RFC850))
        fmt.Printf("%sDNSNames: %v\n\n", prefix, cert.DNSNames)
    }

    fmt.Printf("Success!")
}</code>

此更新的代码使用自定义的VerifyPeerCertificate函数来验证证书是否包含与主机名匹配的CN或与主机名匹配的SAN。如果找到合适的证书,连接就会成功。

以上是为什么我会遇到'连接失败:x509:证书依赖于旧版公用名字段,使用 SAN 或暂时启用与 GODEBUG=x509ignoreCN=0 匹配的公用名”错误的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn