错误信息
SSL Handshake failed with OpenSSL error - SSL_ERROR_SSL.
也可能输出为
- Interop+OpenSsl+SslException: SSL Handshake failed with OpenSSL error - SSL_ERROR_SSL.
外围的异常链依次为“The SSL connection could not be established”→“Authentication failed, see inner exception.”→本消息→OpenSSL 原因(例如 OpenSSL 3.0 中为“error:0A000410:SSL routines::sslv3 alert handshake failure”,3.3 及以上版本中为“ssl/tls alert handshake failure”)。在 Windows(Schannel)和 macOS(Apple 的 TLS 协议栈)上,.NET 会改用各平台特有的消息报告此类失败。
.NET on Linux (SslStream over OpenSSL) — inner exception carrying the OpenSSL reason
含义
在 Linux 上,.NET 的 SslStream 基于系统的 OpenSSL 运行,而握手在 OpenSSL 内部失败,错误为 SSL_ERROR_SSL。这一行只是个外壳;下一层内部异常(Interop+Crypto+OpenSslCryptographicException)才包含真正的 OpenSSL 原因,例如服务器发来的告警或被拒绝的协议版本。
原因
没有共同的密码套件或协议版本
常见只支持 RSA 密钥交换、3DES 或 TLS 1.0/1.1 的老旧服务器;OpenSSL 原因会显示服务器发送的告警。
服务器要求客户端证书
偶见使用 TLS 1.2 的双向 TLS 服务器在客户端没有提供证书时,会以 handshake_failure 告警作为回应。
系统 OpenSSL 策略禁止了服务器所需的配置
偶见发行版的默认设置(安全级别 2、最低 TLS 1.2)同样适用于 Linux 上的 .NET;同一个应用可能在 Windows 上正常运行,在 Linux 容器中却失败。
修复方法
- 1.
读取最内层异常中的 OpenSSL 原因
error:0A… 错误码及其文本指明了问题所在;按示例将其对应到具体问题。
text Interop+Crypto+OpenSslCryptographicException: error:0A000410:SSL routines::sslv3 alert handshake failure -> the server rejected the offered suites/versions (or wants a client certificate) error:0A00042E:SSL routines::tlsv1 alert protocol version -> the server only speaks TLS 1.0/1.1 error:0A00018A:SSL routines::dh key too small -> the server uses 1024-bit DH - 2.
比较服务器与客户端的能力
列出服务器支持的密码套件以及本地 OpenSSL 的默认设置。
bash nmap --script ssl-enum-ciphers -p 443 legacy.example.com # what the server offers openssl ciphers -v 'DEFAULT' | head # what this system's OpenSSL offers - 3.
修复服务器,而不是修改客户端策略
让服务器的 TLS 配置跟上现代标准;只有作为范围很小的临时例外,才放宽客户端的 OpenSSL 策略。
text Server side: enable TLS 1.2/1.3 with ECDHE + AES-GCM (or ChaCha20) suites. Lowering the system-wide OpenSSL policy (CipherString=DEFAULT@SECLEVEL=1 in openssl.cnf) affects every application on the host and should only be a short-lived exception for an isolated legacy peer.