本文へスキップ
ecdsa.com
OpenSSL (client side)OpenSSL CLI

エラーメッセージ

SSL routines:ssl3_read_bytes:ssl/tls alert handshake failure

別の表記

  • SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
  • SSL alert number 40

OpenSSL 3.3 以降は「ssl/tls alert handshake failure」、それより前のバージョンは「sslv3 alert handshake failure」と出力します(コードはどちらも 0A000410。1.1.1 では 14094410)。行の末尾には、出力元のソースコードの位置と「SSL alert number 40」が付きます。

OpenSSL (client side) — TLS alert 40 (handshake_failure) received from the server

このエラーの意味

サーバーが TLS アラート 40(handshake_failure)を送信して接続を閉じました。これは汎用的な拒否で、ClientHello に受け入れ可能な暗号スイート、鍵交換グループ、署名アルゴリズムのいずれかが含まれていなかった場合、サーバーがクライアント証明書を要求した場合、要求されたサーバー名をサーバーが拒否した場合に送られます。クライアントはアラートから理由を知ることができません。理由はサーバーのログに記録されています。

発生する理由

修正方法

  1. 1.

    サーバーのログを確認する

    サーバーは実際の理由(たとえば「no shared cipher」や「peer did not return a certificate」)を記録しています。

    bash
    # The server knows why; with openssl s_server or nginx the log says e.g.
    #   ...:tls_post_process_client_hello:no shared cipher
    #   ...:tls_process_client_certificate:peer did not return a certificate
    sudo tail -n 50 /var/log/nginx/error.log | grep -i ssl
  2. 2.

    クライアント側から原因を絞り込む

    SNI、プロトコルバージョン、暗号リスト、クライアント証明書の有無を変えて試してください。成功した組み合わせから、何が欠けているかがわかります。

    bash
    h=api.example.com
    echo | openssl s_client -connect $h:443 -servername $h -brief                       # with SNI
    echo | openssl s_client -connect $h:443 -servername $h -tls1_2 -cipher 'ALL:@SECLEVEL=0' -brief
    echo | openssl s_client -connect $h:443 -servername $h -cert client.pem -key client.key -brief   # mTLS
  3. 3.

    サーバー管理者:現行の暗号スイートを提供する

    TLS 1.3 に加えて、ECDHE と AEAD の暗号スイートを使う TLS 1.2 を提供すれば、保守されているすべてのクライアントで動作します。

    text
    # nginx: modern suites for TLS 1.2 plus 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;

関連するエラー

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