Перейти к содержимому
ecdsa.com
curl (OpenSSL backend)curl

Сообщение об ошибке

curl: (35) TLS connect error: error:0A000410:SSL routines::ssl/tls alert handshake failure

Также выводится как

  • curl: (35) error:0A000410:SSL routines::sslv3 alert handshake failure
  • curl: (35) error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure

В OpenSSL 3.3 и новее причина звучит как «ssl/tls alert handshake failure»; OpenSSL 3.1 и более ранние версии выводят «sslv3 alert handshake failure» (1.1.1 — с кодом 14094410 и именем функции ssl3_read_bytes). Последние версии curl добавляют в начало «TLS connect error: ».

curl (OpenSSL backend) — CURLE_SSL_CONNECT_ERROR, TLS alert 40 (handshake_failure) received from the server

Что это означает

Сервер прервал рукопожатие, отправив оповещение TLS 40 (handshake_failure): он не смог согласовать параметры с тем, что предложил curl. Причину оповещение не сообщает, поэтому настоящая причина видна только в журналах сервера; на стороне клиента можно лишь сравнить, что поддерживает каждая сторона. Сертификат к этому моменту ещё не проверялся.

Почему это происходит

Как исправить

  1. 1.

    Сравните, что предлагают обе стороны

    Перечислите наборы шифров и версии протокола, которые поддерживает сервер, и сравните их со списком шифров клиента. Подробный вывод curl показывает, до какого этапа дошло рукопожатие и какую версию пытались согласовать.

    bash
    # What the server accepts (needs nmap) and what this client offers
    nmap --script ssl-enum-ciphers -p 443 api.example.com
    openssl ciphers -v 'DEFAULT' | head -20
    # Full handshake trace from curl's side
    curl -sv https://api.example.com/ -o /dev/null 2>&1 | grep -E '^\* (TLS|SSL)'
  2. 2.

    Владельцам серверов: используйте современную конфигурацию шифров

    Предлагайте TLS 1.3 и TLS 1.2 с ECDHE и наборами шифров AEAD (AES-GCM, ChaCha20-Poly1305). Их поддерживает любой клиент, выпущенный за последнее десятилетие, и ничему современному не нужны обмен ключами RSA или CBC.

    text
    # nginx: TLS 1.2 with forward-secret AEAD suites + TLS 1.3
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
    ssl_prefer_server_ciphers off;
  3. 3.

    Отправляйте правильное имя сервера

    Указывайте в URL имя хоста или задавайте адрес принудительно через --resolve, сохраняя имя. В openssl s_client при подключении по IP передавайте -servername.

    bash
    # Use the host name in the URL (SNI is sent automatically); for IP targets keep the name:
    curl --resolve api.example.com:443:203.0.113.10 https://api.example.com/
    # openssl s_client sends SNI only with -servername (or a host name in -connect)
    openssl s_client -connect 203.0.113.10:443 -servername api.example.com </dev/null
  4. 4.

    Предъявите клиентский сертификат для взаимной TLS-аутентификации

    Если эндпоинт — API с mTLS, настройте клиентский сертификат и ключ; в журналах сервера проблема будет описана как отсутствующий или непроверяемый сертификат другой стороны (peer certificate).

    bash
    # Mutual TLS: present the client certificate and key the server expects
    curl --cert client.pem --key client.key https://mtls.example.com/

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

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