Fehlermeldung
SSL routines:ssl3_read_bytes:ssl/tls alert bad certificate
Auch ausgegeben als
- SSL routines:ssl3_read_bytes:sslv3 alert bad certificate
- error:0A000412:SSL routines::ssl/tls alert bad certificate
Ab OpenSSL 3.3 lautet die Ausgabe „ssl/tls alert bad certificate“, in früheren Versionen „sslv3 alert bad certificate“ (Code 0A000412; 1.1.1 verwendete 14094412), gefolgt von „SSL alert number 42“. OpenSSL-Clients selbst senden bei denselben Ablehnungen unknown_ca (48) oder certificate_expired (45).
OpenSSL — TLS alert 42 (bad_certificate) received from the peer
Was der Fehler bedeutet
Die Gegenstelle hat den TLS-Alert 42 (bad_certificate) gesendet und damit das Zertifikat abgelehnt, das diese Seite präsentiert hat. crypto/tls von Go sendet diesen Alert für jedes Serverzertifikat, dessen Prüfung fehlschlägt (unbekannte Zertifizierungsstelle, abgelaufen, falscher Name); deshalb steht er in den Logs von Servern auf OpenSSL-Basis (nginx, HAProxy, Postfix, s_server), sobald ein Go-Client ihr Zertifikat ablehnt. Bei Mutual TLS sendet ein Server ihn, wenn er das Zertifikat des Clients ablehnt.
Warum der Fehler auftritt
Ein Go-Client hat das Zertifikat des Servers abgelehnt
häufigGo-Programme (Kubernetes-Komponenten, Terraform, Prometheus, Docker, viele CLIs) senden bad_certificate, wenn die Prüfung fehlschlägt. Die Go-Seite zeigt den tatsächlichen Grund, zum Beispiel „x509: certificate signed by unknown authority“.
Mutual TLS: Der Server hat das Client-Zertifikat abgelehnt
häufigDas Client-Zertifikat ist abgelaufen, nicht von einer akzeptierten CA ausgestellt oder aus anderen Gründen für den Server nicht akzeptabel.
Die Key Usage des Zertifikats erlaubt seine Rolle nicht
gelegentlichEin Zertifikat, in dessen extendedKeyUsage serverAuth fehlt (oder clientAuth bei Client-Zertifikaten), wird von strengen Prüfern wie Go abgelehnt.
So behebst du den Fehler
- 1.
Ablehnenden Client und den Grund finden
Die Log-Zeile nennt die Adresse des Clients; auf diesem Client nennt die Fehlermeldung die tatsächliche Ursache. Prüfst du die Kette von außen, siehst du sie oft direkt.
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.
Go-Clients: CA vertrauen oder Kette korrigieren
Liefere eine vollständige Kette von einer vertrauenswürdigen CA aus oder füge die private CA zu den RootCAs des Go-Clients hinzu; verwende nie InsecureSkipVerify als Lösung.
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.
Mutual TLS: Client-Zertifikat prüfen
Gültigkeitszeitraum, Aussteller und Key Usage des Client-Zertifikats müssen dem entsprechen, was der Server erwartet.
bash # Mutual TLS: check the client certificate the server rejected openssl x509 -in client.pem -noout -issuer -dates -ext extendedKeyUsage,keyUsage