Перейти к содержимому
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): она отвергла сертификат, который предъявила эта сторона. Пакет crypto/tls в Go отправляет это оповещение для любого сертификата сервера, который не прошёл проверку (неизвестный центр сертификации, истёкший срок действия, неверное имя), поэтому серверы на базе 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 в RootCAs клиента на Go; никогда не используйте 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

Связанные ошибки

Открыть всю базу ошибок подписей