跳到主要内容
ecdsa.com
OpenSSLOpenSSL CLI

错误信息

SSL routines:ssl3_read_bytes:ssl/tls alert bad certificate

也可能输出为

  • SSL routines:ssl3_read_bytes:sslv3 alert bad certificate
  • error:0A000412:SSL routines::ssl/tls alert bad certificate

OpenSSL 3.3 及以上版本输出“ssl/tls alert bad certificate”,更早的版本输出“sslv3 alert bad certificate”(代码 0A000412;1.1.1 使用的是 14094412),后面跟着“SSL alert number 42”。OpenSSL 客户端自己在同样的拒绝情况下发送的是 unknown_ca(48)或 certificate_expired(45)。

OpenSSL — TLS alert 42 (bad_certificate) received from the peer

含义

对端发送了 TLS 告警 42(bad_certificate):它拒绝了本端出示的证书。Go 的 crypto/tls 对任何验证不通过的服务器证书(CA 未知、已过期、名称错误)都会发送这个告警,因此每当 Go 客户端拒绝基于 OpenSSL 的服务器(nginx、HAProxy、Postfix、s_server)的证书时,这些服务器都会记录它。在双向 TLS 中,服务器拒绝客户端的证书时会发送它。

原因

修复方法

  1. 1.

    找出拒绝证书的客户端及原因

    日志行中写有客户端地址;在那个客户端上,错误信息会给出真正的原因。从外部验证证书链,往往也能直接看出原因。

    bash
    # Server log: which client rejected the certificate, and does the chain verify from outside?
    openssl s_client -connect api.example.com:443 -servername api.example.com </dev/null 2>/dev/null \
      | grep -E 'Verify return code'
  2. 2.

    Go 客户端:信任该 CA 或修复证书链

    提供由受信任 CA 签发的完整证书链,或者把私有 CA 添加到 Go 客户端的 RootCAs 中;切勿用 InsecureSkipVerify 作为修复手段。

    go
    // Go clients: trust the server's CA explicitly (keeps verification on)
    pool, _ := x509.SystemCertPool()
    caPEM, _ := os.ReadFile("internal-ca.pem")
    pool.AppendCertsFromPEM(caPEM)
    client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{RootCAs: pool}}}
  3. 3.

    双向 TLS:检查客户端证书

    客户端证书的有效期、颁发者和密钥用法必须符合服务器的要求。

    bash
    # Mutual TLS: check the client certificate the server rejected
    openssl x509 -in client.pem -noout -issuer -dates -ext extendedKeyUsage,keyUsage

相关错误

浏览完整的签名错误库