Mensagem de erro
SSL routines:ssl3_read_bytes:ssl/tls alert bad certificate
Também aparece como
- SSL routines:ssl3_read_bytes:sslv3 alert bad certificate
- error:0A000412:SSL routines::ssl/tls alert bad certificate
O OpenSSL 3.3 e posteriores imprimem “ssl/tls alert bad certificate”; as versões anteriores, “sslv3 alert bad certificate” (código 0A000412; o 1.1.1 usava 14094412), seguido de “SSL alert number 42”. Os próprios clientes OpenSSL enviam unknown_ca (48) ou certificate_expired (45) nas mesmas rejeições.
OpenSSL — TLS alert 42 (bad_certificate) received from the peer
O que significa
O peer enviou o alerta TLS 42 (bad_certificate): ele rejeitou o certificado que este lado apresentou. O crypto/tls do Go envia esse alerta para qualquer certificado de servidor que não consegue verificar (autoridade desconhecida, expirado, nome errado), por isso servidores baseados em OpenSSL (nginx, HAProxy, Postfix, s_server) o registram sempre que um cliente Go rejeita o certificado deles. No TLS mútuo, um servidor o envia quando rejeita o certificado do cliente.
Por que acontece
Um cliente Go rejeitou o certificado do servidor
comumProgramas em Go (componentes do Kubernetes, Terraform, Prometheus, Docker, muitas CLIs) enviam bad_certificate quando a verificação falha. O lado Go mostra o motivo real, por exemplo, “x509: certificate signed by unknown authority”.
TLS mútuo: o servidor rejeitou o certificado de cliente
comumO certificado de cliente expirou, não foi emitido por uma CA aceita ou é inaceitável para o servidor por outro motivo.
O uso da chave do certificado não permite a função que ele exerce
ocasionalVerificadores rigorosos, como o do Go, rejeitam um certificado cujo extendedKeyUsage não inclui serverAuth (ou clientAuth, no caso de certificados de cliente).
Como corrigir
- 1.
Descobrir qual cliente rejeitou o certificado e por quê
A linha do log traz o endereço do cliente; nesse cliente, a mensagem de erro informa a causa real. Verificar a cadeia de fora muitas vezes já mostra a causa diretamente.
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.
Clientes Go: confiar na CA ou corrigir a cadeia
Sirva uma cadeia completa de uma CA confiável ou adicione a CA privada ao RootCAs do cliente Go; nunca use InsecureSkipVerify como solução.
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.
TLS mútuo: verificar o certificado de cliente
As datas de validade, o emissor e o uso da chave do certificado de cliente precisam corresponder ao que o servidor espera.
bash # Mutual TLS: check the client certificate the server rejected openssl x509 -in client.pem -noout -issuer -dates -ext extendedKeyUsage,keyUsage