使用OpenSSL建立SSL连接报错:SSL_connect()返回0、SSL_ERROR_SSL
先给你拆解下这个报错的几个核心可能原因,结合你贴的代码来看:
未抓取详细错误栈:
SSL_ERROR_SSL只是一个笼统的协议层错误标识,没法直接定位问题。你需要在报错后打印OpenSSL的详细错误栈,这才能拿到具体的失败原因(比如证书验证失败、加密套件不兼容、协议版本不匹配等)。可以在SSL_get_error之后添加这段代码:ERR_print_errors_fp(stderr); // 或者用编程方式逐个获取错误码 unsigned long err; while ((err = ERR_get_error()) != 0) { fprintf(stderr, "OpenSSL error: %s\n", ERR_error_string(err, NULL)); }证书验证未配置:默认情况下,OpenSSL的客户端上下文会强制验证服务器证书的合法性。如果服务器用的是自签名证书,或者你没有加载对应的根CA证书,握手就会失败。你可以先做个测试:临时关闭证书验证(仅用于排查,生产环境绝对不能这么做),看看是否能成功连接:
// 在创建m_ctx之后添加 SSL_CTX_set_verify(m_ctx, SSL_VERIFY_NONE, NULL);如果这样能成功,那就是证书验证的问题,生产环境需要加载正确的CA证书文件:
if (!SSL_CTX_load_verify_locations(m_ctx, "/path/to/ca-cert.pem", NULL)) { // 处理CA证书加载失败的逻辑 }TCP连接未完成:
SSL_connect的前提是底层的TCP连接已经成功建立(也就是你已经调用了connect函数并且返回成功)。如果你的hSocket还没完成TCP连接就直接调用SSL握手,肯定会触发协议错误。先确认TCP连接是否正常建立。协议版本兼容性问题:你代码里用的是
TLSv1_2_client_method(),如果服务器不支持TLS 1.2(比如只支持TLS 1.3或者更旧的版本),就会导致握手协商失败。建议换成更通用的协议方法,让客户端自动协商支持的最高版本:m_ctx = SSL_CTX_new(SSLv23_client_method()); // 如果需要限制最高版本,可以添加 SSL_CTX_set_options(m_ctx, SSL_OP_NO_TLSv1_3); // 示例:禁用TLS1.3初始化和资源问题:虽然不是直接导致当前报错的原因,但你的代码有几个可以优化的点:新版本OpenSSL(1.1.0+)已经废弃了
SSL_library_init()和SSL_load_error_strings(),建议改用OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);另外,代码里没有释放SSL和SSL_CTX资源,长期运行会内存泄漏,记得在函数末尾添加:SSL_free(m_ssl); SSL_CTX_free(m_ctx);
内容的提问来源于stack exchange,提问作者Trânf Hà




