本文へスキップ
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 は、検証に失敗したサーバー証明書に対して、理由(不明な認証局、期限切れ、名前の不一致)を問わずこのアラートを送信します。そのため、OpenSSL ベースのサーバー(nginx、HAProxy、Postfix、s_server)は、Go のクライアントが自身の証明書を拒否するたびにこのアラートをログに記録します。相互 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

関連するエラー

署名エラーデータベースをすべて見る