错误信息
SSL routines:tls_post_process_client_hello:no shared cipher
也可能输出为
- SSL_do_handshake() failed (SSL: error:0A0000C1:SSL routines::no shared cipher)
- error:0A0000C1:SSL routines::no shared cipher
openssl s_server(OpenSSL 3.x)记录的是“error:0A0000C1:SSL routines:tls_post_process_client_hello:no shared cipher:<source>”;nginx 以 info 级别记录“SSL_do_handshake() failed (SSL: error:0A0000C1:SSL routines::no shared cipher) while SSL handshaking”,因此在默认的 error_log 级别下看不到。OpenSSL 1.1.1 使用的代码是 1417A0C1。
OpenSSL (server side: nginx, Apache, Postfix, openssl s_server) — SSL_R_NO_SHARED_CIPHER
含义
这是服务器视角下的握手失败:客户端 ClientHello 中的密码套件,没有一个既在服务器上启用、又能与服务器证书的密钥配合使用。随后服务器向客户端发送 handshake_failure(告警 40)。这条错误出现在服务器日志中,而不是客户端输出中。
原因
密码套件列表与证书的密钥类型不匹配
常见使用 ECDSA 证书却只启用了 ECDHE-RSA-* 套件(或使用 RSA 证书却只启用了 ECDHE-ECDSA-*),就没有可用的 TLS 1.2 套件,所有 TLS 1.2 客户端都会连接失败。
手动精简的密码套件列表排除了实际存在的客户端
常见精简到只剩一两个套件,或者只剩 CHACHA20 的列表,会把偏好其他现代套件的客户端(以及监控工具)拒之门外。
非常老旧的客户端
偶见只支持 RSA 密钥交换套件、CBC 套件或 3DES 套件的客户端(旧版 Java、嵌入式设备)无法连接采用现代配置的服务器;是否支持它们,需要慎重决定。
修复方法
- 1.
对照套件检查证书密钥
ECDHE-ECDSA-* 套件需要 ECDSA 证书,ECDHE-RSA-* 套件需要 RSA 证书;同时拥有两种证书的服务器可以列出两类套件。
bash # ECDSA key + only ECDHE-RSA suites (or the reverse) leaves nothing usable openssl x509 -in server.pem -noout -text | grep 'Public Key Algorithm' openssl ciphers -v 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256' - 2.
列出服务器实际接受的套件
从外部逐一枚举,再与需要支持的客户端对照。
bash # Which TLS 1.2 suites does the server accept? (nmap needed) nmap --script ssl-enum-ciphers -p 443 api.example.com - 3.
使用经过充分测试的套件列表
从生成的现代配置或中间配置出发,而不要手动精简列表。
text # nginx: suites for both RSA and ECDSA certificates, TLS 1.3 enabled 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;