连接到 Golang 服务器失败,原因是 x509 证书依赖于传统的 Common Name 字段。

huangapple go评论116阅读模式
英文:

Failed to connect to a server with Golang due x509 certificate relies on legacy Common Name field

问题

我正在尝试连接到一个MongoDB服务器,为了连接,我必须提供一个CA证书文件和一个TLS证书文件。

当我使用以下命令时,没有问题:

  1. $ mongo --host customhost:port DB --authenticationDatabase=DB -u ACCOUNT -p PWD --tls --tlsCAFile /etc/ca-files/new-mongo.ca.crt --tlsCertificateKeyFile /etc/ca-files/new-mongo-client.pem

但是当我尝试使用mongo连接(也测试了只使用TLS客户端)时,出现以下错误:

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

如果我使用环境变量,一切正常,但我想知道如何在不使用环境变量的情况下修复它。

以下是我的代码配置和加载证书的方式,我不确定问题是我的代码配置有误还是SSL证书配置有误,但从证书的外观来看,它们似乎是正确的。我感觉加载的证书由于某种原因被忽略了。

证书信息如下:

CA证书:

  1. $ openssl x509 -in /etc/ca-files/new-mongo.ca.crt -text -noout
  2. Certificate:
  3. Data:
  4. Version: 3 (0x2)
  5. Serial Number:
  6. ....
  7. Signature Algorithm: sha256WithRSAEncryption
  8. Issuer: C = FR, ST = IDF, L = Paris, O = COMP, OU = IT, CN = newmongo
  9. Validity
  10. Not Before: Jun 30 13:02:12 2021 GMT
  11. Not After : Jun 30 13:02:12 2023 GMT
  12. Subject: C = FR, ST = IDF, L = Paris, O = COMP, OU = IT, CN = newmongo
  13. ...
  14. X509v3 extensions:
  15. X509v3 Subject Key Identifier:
  16. ...
  17. X509v3 Authority Key Identifier:
  18. ....
  19. X509v3 Basic Constraints: critical
  20. CA:TRUE

客户端证书:

  1. $ openssl x509 -in /etc/ca-files/newmongo-client.pem -text -noout
  2. Certificate:
  3. Data:
  4. Version: 3 (0x2)
  5. Serial Number:
  6. ...
  7. Signature Algorithm: sha256WithRSAEncryption
  8. Issuer: C = FR, ST = IDF, L = Paris, O = COMP, OU = IT, CN = newmongo
  9. Validity
  10. Not Before: Jun 30 13:17:25 2021 GMT
  11. Not After : Jun 30 13:17:25 2023 GMT
  12. Subject: C = FR, ST = IDF, L = Paris, O = COMP, OU = IT, CN = newmongo-client
  13. ...
  14. X509v3 extensions:
  15. X509v3 Subject Alternative Name:
  16. DNS:customhost:port, DNS:customhost, DNS:newmongo-client

我有点困惑,不知道问题是我的代码配置TLS和加载证书的方式有问题,还是SSL证书配置有问题,但从证书的外观来看,它们似乎是正确的。我感觉加载的证书由于某种原因被忽略了。

英文:

I'm trying to connect on a mongodb server, to connect I have to provide a CA cert file and also tls cert file.

When I use the following command I don't have issue

  1. $ mongo --host customhost:port DB --authenticationDatabase=DB -u ACCOUNT -p PWD --tls --tlsCAFile /etc/ca-files/new-mongo.ca.crt --tlsCertificateKeyFile /etc/ca-files/new-mongo-client.pem

But when I try to connect with mongo (and also tested with just a tls client) I have the following error:

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

If I use the env variable everything works well but I would like to know how to fix it without having to use it.

  1. const CONFIG_DB_CA = "/etc/ca-files/new-mongo.ca.crt"
  2. func main() {
  3. cer, err := tls.LoadX509KeyPair("mongo-server.crt", "mongo-server.key")
  4. if err != nil {
  5. log.Println(err)
  6. return
  7. }
  8. roots := x509.NewCertPool()
  9. ca, err := ioutil.ReadFile(CONFIG_DB_CA)
  10. if err != nil {
  11. fmt.Printf("Failed to read or open CA File: %s.\n", CONFIG_DB_CA)
  12. return
  13. }
  14. roots.AppendCertsFromPEM(ca)
  15. tlsConfig := &tls.Config{
  16. Certificates: []tls.Certificate{cer},
  17. RootCAs: roots,
  18. }
  19. conn, err := tls.Dial("tcp", "customhost:port", tlsConfig)
  20. if err != nil {
  21. fmt.Printf("failed to connect: %v.\n", err)
  22. return
  23. }
  24. err = conn.VerifyHostname("customhost")
  25. if err != nil {
  26. panic("Hostname doesn't match with certificate: " + err.Error())
  27. }
  28. for i, cert := range conn.ConnectionState().PeerCertificates {
  29. prefix := fmt.Sprintf("CERT%d::", i+1)
  30. fmt.Printf("%sIssuer: %s\n", prefix, cert.Issuer)
  31. fmt.Printf("%sExpiry: %v\n", prefix, cert.NotAfter.Format(time.RFC850))
  32. fmt.Printf("%sDNSNames: %v\n\n", prefix, cert.DNSNames)
  33. }
  34. fmt.Printf("Success!")
  35. }

Certificates:

  1. $ openssl x509 -in /etc/ca-files/new-mongo.ca.crt -text -noout
  2. Certificate:
  3. Data:
  4. Version: 3 (0x2)
  5. Serial Number:
  6. ....
  7. Signature Algorithm: sha256WithRSAEncryption
  8. Issuer: C = FR, ST = IDF, L = Paris, O = COMP, OU = IT, CN = newmongo
  9. Validity
  10. Not Before: Jun 30 13:02:12 2021 GMT
  11. Not After : Jun 30 13:02:12 2023 GMT
  12. Subject: C = FR, ST = IDF, L = Paris, O = COMP, OU = IT, CN = newmongo
  13. ...
  14. X509v3 extensions:
  15. X509v3 Subject Key Identifier:
  16. ...
  17. X509v3 Authority Key Identifier:
  18. ....
  19. X509v3 Basic Constraints: critical
  20. CA:TRUE
  1. $ openssl x509 -in /etc/ca-files/newmongo-client.pem -text -noout
  2. Certificate:
  3. Data:
  4. Version: 3 (0x2)
  5. Serial Number:
  6. ...
  7. Signature Algorithm: sha256WithRSAEncryption
  8. Issuer: C = FR, ST = IDF, L = Paris, O = COMP, OU = IT, CN = newmongo
  9. Validity
  10. Not Before: Jun 30 13:17:25 2021 GMT
  11. Not After : Jun 30 13:17:25 2023 GMT
  12. Subject: C = FR, ST = IDF, L = Paris, O = COMP, OU = IT, CN = newmongo-client
  13. ...
  14. X509v3 extensions:
  15. X509v3 Subject Alternative Name:
  16. DNS:customhost:port, DNS:customhost, DNS:newmongo-client

I'm a bit stuck and don't know if the problem is my code configuration of tls and the way I loaded certificates or if it comes from the SSL certificate misconfiguration but from what certificates look fine.
I feel like loaded certificate are ignored for any reason.

答案1

得分: 9

你需要修复问题的源头,并生成一个带有DNS SAN字段的证书-然后Go运行时检查就会消失。

这可以通过使用openssl实现,但是需要一个配置文件,因为SAN字段的选项太广泛,无法适应简单的命令行选项。

总体思路是,创建一个CSR

  1. openssl req -new \
  2. -subj "${SUBJ_PREFIX}/CN=${DNS}/emailAddress=${EMAIL}" \
  3. -key "${KEY}" \
  4. -addext "subjectAltName = DNS:${DNS}" \
  5. -out "${CSR}";

然后使用你的根CA签署CSR

  1. openssl ca \
  2. -create_serial \
  3. -cert "${ROOT_CRT}" \
  4. -keyfile "${ROOT_KEY}" \
  5. -days "${CERT_LIFETIME}" \
  6. -in "${CSR}" \
  7. -batch \
  8. -config "${CA_CONF}" \
  9. -out "${CRT}";

上面引用的CA_CONF类似于以下内容:

  1. [ ca ]
  2. default_ca = my_ca
  3. [ my_ca ]
  4. dir = ./db
  5. database = $dir/index.txt
  6. serial = $dir/serial
  7. new_certs_dir = $dir/tmp
  8. x509_extensions = my_cert
  9. name_opt = ca_default
  10. cert_opt = ca_default
  11. default_md = default
  12. policy = policy_match
  13. # 'copy_extensions' will copy over SAN ("X509v3 Subject Alternative Name") from CSR
  14. copy_extensions = copy
  15. [ my_cert ]
  16. basicConstraints = CA:FALSE
  17. nsComment = "generated by https://github.com/me/my-pki"
  18. subjectKeyIdentifier = hash
  19. authorityKeyIdentifier = keyid,issuer
  20. [ policy_match ]
  21. # ensure CSR fields match that of delivered Cert
  22. countryName = match
  23. stateOrProvinceName = match
  24. organizationName = match
  25. organizationalUnitName = optional
  26. commonName = supplied
  27. emailAddress = optional

检查生成的服务器证书:

  1. openssl x509 -in server.crt -noout -text

应该有一个类似于以下的SAN部分:

  1. X509v3 Subject Alternative Name:
  2. DNS:myserver.com
英文:

You need to fix the problem at the source and generate a certificate with a DNS SAN field - then the Go runtime check will disappear.

This is achievable with openssl but is tricky as it requires a config file - as SAN field options are too broad to fit into simple command-line options.

The general gist is, create a CSR:

  1. openssl req -new \
  2. -subj "${SUBJ_PREFIX}/CN=${DNS}/emailAddress=${EMAIL}" \
  3. -key "${KEY}" \
  4. -addext "subjectAltName = DNS:${DNS}" \
  5. -out "${CSR}"

and then sign the CSR with your root CA:

  1. openssl ca \
  2. -create_serial \
  3. -cert "${ROOT_CRT}" \
  4. -keyfile "${ROOT_KEY}" \
  5. -days "${CERT_LIFETIME}" \
  6. -in "${CSR}" \
  7. -batch \
  8. -config "${CA_CONF}" \
  9. -out "${CRT}"

CA_CONF referenced above looks something like this:

  1. [ ca ]
  2. default_ca = my_ca
  3. [ my_ca ]
  4. dir = ./db
  5. database = $dir/index.txt
  6. serial = $dir/serial
  7. new_certs_dir = $dir/tmp
  8. x509_extensions = my_cert
  9. name_opt = ca_default
  10. cert_opt = ca_default
  11. default_md = default
  12. policy = policy_match
  13. # 'copy_extensions' will copy over SAN ("X509v3 Subject Alternative Name") from CSR
  14. copy_extensions = copy
  15. [ my_cert ]
  16. basicConstraints = CA:FALSE
  17. nsComment = "generated by https://github.com/me/my-pki"
  18. subjectKeyIdentifier = hash
  19. authorityKeyIdentifier = keyid,issuer
  20. [ policy_match ]
  21. # ensure CSR fields match that of delivered Cert
  22. countryName = match
  23. stateOrProvinceName = match
  24. organizationName = match
  25. organizationalUnitName = optional
  26. commonName = supplied
  27. emailAddress = optional

Inspecting the resulting server cert:

  1. openssl x509 -in server.crt -noout -text

should then have a SAN section like:

  1. X509v3 Subject Alternative Name:
  2. DNS:myserver.com

huangapple
  • 本文由 发表于 2021年6月30日 22:15:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/68196502.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定