エラーメッセージ
[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] ssl/tls alert handshake failure
別の表記
- [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure
理由コードは SSLV3_ALERT_HANDSHAKE_FAILURE のままですが、テキストは OpenSSL によって異なり、OpenSSL 3.3 以降では「ssl/tls alert handshake failure」、それより古いバージョンでは「sslv3 alert handshake failure」です。その後に「(_ssl.c:1082)」のようなソースの位置が続きます。
Python ssl module (OpenSSL) — ssl.SSLError, TLS alert 40 (handshake_failure) from the server
このエラーの意味
サーバーが TLS アラート 40(handshake_failure)でハンドシェイクを中止しました。Python の ClientHello の中に受け入れ可能なパラメーターを見つけられなかったか、クライアント証明書を要求したのにそれが提示されなかったかのどちらかです。アラート自体には詳細が含まれていないため、双方が何をサポートしているかを比較するか、サーバーのログを読んで原因を突き止める必要があります。
発生する理由
共通の暗号スイートがない
よくあるPython 3.10 以降、デフォルトのコンテキストは OpenSSL のセキュリティレベル 2 で動作し、前方秘匿性のない暗号スイートも SHA-1 の MAC を使う暗号スイートも提示しません。RSA 鍵交換、CBC-SHA、3DES のいずれかを使う暗号スイートしか使えない古いサーバーとは、共通するものがありません。
サーバーがクライアント証明書を要求している
よくある相互 TLS のエンドポイント(銀行や B2B の API、社内サービス)は、TLS 1.2 では、クライアント証明書のないハンドシェイクに対してこのアラートで応答します。
SNI がない、またはサーバーで設定されていない
ときどきserver_hostname を指定せずに IP で接続した場合や、CDN やプロキシが提供していない名前に接続した場合、一部のサーバーは handshake_failure で中止します。
修正方法
- 1.
暗号リストを比較する
この Python が提示するものを出力し、サーバーの一覧(たとえば nmap --script ssl-enum-ciphers で取得したもの)と比較してください。重なりがなければ、サーバーの更新が必要です。
python import ssl ctx = ssl.create_default_context() print(sorted(c["name"] for c in ctx.get_ciphers())) # what this Python offers (TLS 1.2 names) - 2.
クライアント証明書を提示する
mTLS の API では、load_cert_chain() でクライアント証明書と鍵をコンテキストに読み込んでください。requests では cert=("client.pem", "client.key") を渡します。
python import ssl, urllib.request ctx = ssl.create_default_context() ctx.load_cert_chain(certfile="client.pem", keyfile="client.key") # mutual TLS urllib.request.urlopen("https://mtls.example.com/", context=ctx) - 3.
サーバー管理者:現行の暗号スイートを提供する
TLS 1.3 に加えて、AES-GCM または ChaCha20-Poly1305 と ECDHE を組み合わせた TLS 1.2 を提供すれば、保守されているすべてのクライアントに受け入れられます。
text # Server side: offer TLS 1.3 and TLS 1.2 ECDHE + AEAD suites 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;