You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SSL_connect报错SSL_ERROR_SSL,如何排查问题根源?

问题描述

我编写了一个简单的套接字程序,尝试连接一个可通过FireFox/Chrome正常访问的HTTPS服务器,代码如下:

// Register the error strings for libcrypto & libssl
SSL_load_error_strings();
// Register the available ciphers and digests
SSL_library_init();
// load all algos
OpenSSL_add_all_algorithms();
// create context (new context for each connection)
ssl_ctx_ = SSL_CTX_new(SSLv23_client_method());
if(!ssl_ctx_) {
    throw std::runtime_error("Can't initialize ssl context");
}
// create handle
ssl_h_ = SSL_new(ssl_ctx_);
if(!ssl_h_) {
    SSL_CTX_free(ssl_ctx_);
    throw std::runtime_error("Can't initialize new ssl handle");
}
// sd_ is a valid socket connected to a host on port 443,
// i.e. www.repubblica.it:443
// bind socket
if (!SSL_set_fd(ssl_h_, sd_)) {
    SSL_free(ssl_h_);
    SSL_CTX_free(ssl_ctx_);
    throw std::runtime_error("Can't set sd to ssl handle");
}
// set blocking
// this api makes the socket blocking
fd_block(sd_);
// perform handshake
const int r = SSL_connect(ssl_h_);
// r is now -1
if(1 != r) {
    // find out the error
    const int   err = SSL_get_error(ssl_h_, r);
    SSL_free(ssl_h_);
    SSL_CTX_free(ssl_ctx_);
    throw std::runtime_error(std::string("Can't perform ssl handshake, err code: ") + ssl_err_human(err));
}

调用SSL_connect后返回值为-1,抛出错误:Exception: Can't perform ssl handshake, err code: SSL_ERROR_SSL,该错误信息不够直观。运行环境为Ubuntu 22.04及默认libssl-dev包,请问后续该如何排查问题并修复?

排查与修复步骤

1. 获取详细的OpenSSL错误栈

SSL_ERROR_SSL是通用错误码,无法定位具体问题。在错误处理逻辑中添加代码打印OpenSSL内部错误信息:

// 在获取err变量后添加
char err_buf[256];
ERR_error_string_n(ERR_get_error(), err_buf, sizeof(err_buf));
// 将详细错误信息加入抛出的异常
throw std::runtime_error(std::string("Can't perform ssl handshake, err code: ") + ssl_err_human(err) + ", detail: " + err_buf);

执行后会得到类似error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure的具体错误,直接指向问题核心。

2. 更新SSL上下文创建方法

Ubuntu 22.04默认libssl为3.0版本,SSLv23_client_method()已过时,且部分现代服务器禁用了旧版SSL/TLS协议。替换为兼容更高版本的方法:

// 替换原SSL_CTX_new调用
ssl_ctx_ = SSL_CTX_new(TLS_client_method());

TLS_client_method()会自动协商服务器支持的最高TLS版本(从TLS 1.0到TLS 1.3),适配绝大多数现代HTTPS服务器。

3. 添加服务器名称指示(SNI)配置

多数现代HTTPS服务器托管多个域名,需客户端发送SNI信息才能返回对应证书,这是握手失败的常见原因。在SSL_set_fd之后、SSL_connect之前添加:

const char* target_host = "www.repubblica.it"; // 替换为实际连接的域名
if (!SSL_set_tlsext_host_name(ssl_h_, target_host)) {
    SSL_free(ssl_h_);
    SSL_CTX_free(ssl_ctx_);
    throw std::runtime_error("Failed to set SNI host name");
}

4. 确认套接字连接有效性

即使标注sd_为有效套接字,仍需验证:

  • connect调用返回值为0,确认已成功建立TCP连接
  • 无本地防火墙或代理拦截443端口流量
  • 用telnet www.repubblica.it 443测试基础网络连通性,能建立连接则说明网络层面无问题

5. 排查证书信任问题

若服务器证书不在系统信任库中,也会导致握手失败。可临时关闭证书验证(仅用于测试,生产环境绝对禁止):

// 在SSL_CTX_new之后添加
SSL_CTX_set_verify(ssl_ctx_, SSL_VERIFY_NONE, NULL);

若测试通过,说明是证书信任问题,需将服务器根证书添加到系统信任库,或在代码中指定自定义信任证书文件。


内容的提问来源于stack exchange,提问作者Emanuele

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 05:36:00