LibCurl code:35排查:curl -k生效但C++代码SSL连接失败
执行C++脚本时遇到错误:LibCurl code:35 - Message: schannel: failed to receive handshake, SSL/TLS connection failed。已在代码中设置curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L)和curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L)以模拟curl命令的-k选项,但直接在命令行使用curl -k却能正常运行。
添加curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L)后的输出如下:
Trying x.x.x.x:443... Connected to x.x.x.x (x.x.x.x) port 443 (#0) schannel: disabled automatic use of client certificate schannel: using IP address, SNI is not supported by OS. schannel: failed to receive handshake, SSL/TLS connection failed Closing connection 0
补充说明:报错的服务器无需认证,以下示例代码(与项目中使用的CURL选项一致,以www.example.com为例)也会返回相同错误:
#include <curl/curl.h> #include <iostream> int main() { CURL *curl; CURLcode res; char errbuf[CURL_ERROR_SIZE]; curl = curl_easy_init(); if (curl) { curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 5000); res = curl_easy_perform(curl); if (res != CURLE_OK) { std::cerr << "curl_easy_perform() failed: " << errbuf << std::endl; } curl_easy_cleanup(curl); } return 0; }
请问还需添加哪些CURL选项以完全模拟curl -k的行为?
从verbose输出的schannel: using IP address, SNI is not supported by OS可以看出,问题出在Windows schannel SSL库的配置细节上——命令行curl默认处理了这些逻辑,而代码中缺少对应的选项。可以尝试添加以下选项来匹配curl -k的完整行为:
指定TLS版本范围:部分服务器仅支持特定版本的TLS,代码默认的版本协商可能失效。添加以下选项让curl自动协商最高可用的TLS版本:
curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_MAX_ALLOWED);若仍失败,可尝试强制指定TLS 1.2或1.3:
// 强制使用TLS 1.2 curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);禁用证书吊销检查:Windows下schannel默认会执行证书吊销状态检查,即使关闭了证书验证,该检查也可能导致握手失败。添加选项禁用该检查:
curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);强制启用SNI:虽然输出提示OS不支持SNI,但编译的libcurl版本可能支持强制开启该功能,尝试添加:
curl_easy_setopt(curl, CURLOPT_SSL_ENABLE_SNI, 1L);检查libcurl版本一致性:确保代码链接的libcurl版本与命令行使用的curl版本一致,旧版本libcurl对schannel的支持可能存在缺陷,升级到最新版本可解决部分兼容性问题。
修改后的示例代码:
#include <curl/curl.h> #include <iostream> int main() { CURL *curl; CURLcode res; char errbuf[CURL_ERROR_SIZE]; curl = curl_easy_init(); if (curl) { curl_easy_setopt(curl, CURLOPT_URL, "https://example.com"); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 5000); // 添加选项匹配curl -k行为 curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_MAX_ALLOWED); curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE); curl_easy_setopt(curl, CURLOPT_SSL_ENABLE_SNI, 1L); res = curl_easy_perform(curl); if (res != CURLE_OK) { std::cerr << "curl_easy_perform() failed: " << errbuf << std::endl; } curl_easy_cleanup(curl); } return 0; }
内容的提问来源于stack exchange,提问作者Anees

