Сообщение об ошибке
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. Причину оповещение не сообщает, поэтому настоящая причина видна только в журналах сервера; на стороне клиента можно лишь сравнить, что поддерживает каждая сторона. Сертификат к этому моменту ещё не проверялся.
Почему это происходит
Нет общего набора шифров
частоУстаревшие серверы, ограниченные обменом ключами RSA и наборами шифров CBC-SHA1, 3DES или RC4, сталкиваются с клиентами, которые эти наборы уже удалили; серверы с усиленной защитой, разрешающие лишь несколько наборов, сталкиваются со старыми клиентами, у которых этих наборов нет. В обоих случаях сервер не находит в ClientHello ничего приемлемого.
Клиент не отправил имя сервера (SNI)
частоCDN и мультитенантные прокси (Cloudflare, AWS CloudFront, многие ingress-контроллеры Kubernetes) отклоняют рукопожатия без SNI или для имён, которые они не обслуживают. Подключение по IP-адресу или инструментами, которые не отправляют SNI, вызывает именно это оповещение.
Сервер требует клиентский сертификат
иногдаНекоторые серверы TLS 1.2, настроенные на взаимную TLS-аутентификацию, отвечают на отсутствующий или неприемлемый клиентский сертификат оповещением handshake_failure, а не более конкретными оповещениями о проблемах с сертификатом.
Нет общей группы обмена ключами или общего алгоритма подписи
иногдаСервер, который разрешает только постквантовую гибридную группу, кривую brainpool или подписи RSA-PSS, может не договориться с клиентами, которые их не предлагают; с очень старыми клиентами бывает и наоборот.
Как исправить
- 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.
Владельцам серверов: используйте современную конфигурацию шифров
Предлагайте 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.
Отправляйте правильное имя сервера
Указывайте в 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.
Предъявите клиентский сертификат для взаимной 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/
Связанные ошибки
SSL routines:ssl3_read_bytes:ssl/tls alert handshake failureOpenSSL (client side)SSL routines:tls_post_process_client_hello:no shared cipherOpenSSL (server side: nginx, Apache, Postfix, openssl s_server)curl: (35) TLS connect error: error:0A00042E:SSL routines::tlsv1 alert protocol…curl (OpenSSL backend)[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] ssl/tls alert handshake failurePython ssl module (OpenSSL)javax.net.ssl.SSLHandshakeException: (handshake_failure) Received fatal alert:…Java (JSSE)