跳到主要内容
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;

相关错误

浏览完整的签名错误库