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

Linux下cpprestsdk双向TLS配置遇SSL握手错误求助

双向TLS(Mutual-TLS)握手错误排查(cpprestsdk + Linux)

我在Linux环境下使用cpprestsdk实现双向TLS,服务器部署在localhost。已生成自签名证书,通过以下OpenSSL命令测试正常:

openssl s_server -accept 4433 -cert server.crt -key server.key -CAfile ca.crt -Verify 1
openssl s_client -connect localhost:4433 -cert client1.crt -key client1.key -CAfile ca.crt -debug

但使用cpprestsdk发起请求时出现Error in SSL handshake错误,以下是相关配置,请求排查问题:

证书生成命令

# CA证书
openssl ecparam -name prime256v1 -genkey -noout -out ca.key
openssl req -new -x509 -sha256 -key ca.key -out ca.crt 

# 服务器私钥
openssl ecparam -name prime256v1 -genkey -noout -out server.key

# 服务器签名请求
openssl req -new -sha256 -key server.key -out server.csr -addext "subjectAltName=DNS:localhost,IP:0.0.0.0,IP:127.0.0.0"

# 服务器证书
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 1000 -sha256 -extfile server-extensions.txt

# 客户端私钥
openssl ecparam -name prime256v1 -genkey -noout -out client1.key
    
# 客户端签名请求
openssl req -new -sha256 -key client1.key -out client1.csr 

# 客户端证书
openssl x509 -req -in client1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client1.crt -days 1000 -sha256 -extfile client-extensions.txt

cpprest客户端配置

web::http::client::http_client_config config;
config.set_validate_certificates(true);
config.set_ssl_context_callback([path = settings.certificate_directory.value()](boost::asio::ssl::context& ctx)
{
    ctx.set_password_callback([](std::size_t max_length, boost::asio::ssl::context::password_purpose purpose) {
        return "0000";
    });

    ctx.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::tlsv13);

    ctx.use_certificate_file(path / "client1.crt", boost::asio::ssl::context::pem);
    ctx.use_private_key_file(path / "client1.key", boost::asio::ssl::context::pem);
    ctx.load_verify_file(path / "ca.crt");

    ctx.set_verify_mode(boost::asio::ssl::verify_peer);
});

cpprest服务器配置

web::http::experimental::listener::http_listener_config config;
config.set_ssl_context_callback([path = m_settings.certificates_path.value()](boost::asio::ssl::context& ctx)
{
    ctx.set_password_callback([](std::size_t max_length, boost::asio::ssl::context::password_purpose purpose) {
        return "0000";
    });

    ctx.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::tlsv13);

    ctx.use_certificate_file(path / "server.crt", boost::asio::ssl::context::pem);
    ctx.use_private_key_file(path / "server.key", boost::asio::ssl::context::pem);
    ctx.load_verify_file(path / "ca.crt");

    ctx.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert
});

客户端请求代码

// 类成员:
std::unique_ptr<web::http::client::http_client> m_client

// 简化后的请求代码
void synchronous_request(const std::string& uri, web::http::method method, std::string body) 
{
    auto msg = web::http::http_request(method);
    msg.set_request_uri(uri);
    msg.set_body(std::move(body));
    return m_client->request(std::move(msg), pplx::cancellation_token::none()).get();
}

证书扩展文件

server-extensions.txt

extendedKeyUsage=serverAuth

client-extensions.txt

extendedKeyUsage=clientAuth

排查要点

  1. 服务器配置语法错误
    服务器SSL上下文配置的最后一行ctx.set_verify_mode缺少闭合括号和分号,正确写法应为:

    ctx.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert);
    

    语法错误会导致SSL上下文初始化失败,直接引发握手错误。

  2. 服务器证书SubjectAltName错误
    生成服务器CSR时指定的IP:127.0.0.0是网段地址,而非客户端实际连接的127.0.0.1。客户端验证服务器证书时,会检查SAN是否包含实际连接的IP/域名,不匹配会触发握手失败。重新生成服务器CSR,将SAN改为:

    -addext "subjectAltName=DNS:localhost,IP:0.0.0.0,IP:127.0.0.1"
    
  3. TLS版本兼容性问题
    当前配置仅启用了TLS 1.3,若cpprestsdk依赖的Boost.Asio或OpenSSL版本对TLS 1.3支持不完善,可能导致握手协商失败。建议添加兼容版本,修改为:

    ctx.set_options(boost::asio::ssl::context::default_workarounds | 
                    boost::asio::ssl::context::tlsv12 | 
                    boost::asio::ssl::context::tlsv13);
    
  4. 证书路径与权限问题
    Linux环境下需确保程序能读取证书文件,检查证书路径是否正确(避免Windows风格的C:\路径),同时确保文件权限为可读(如chmod 644 *.crt *.key)。

  5. 密钥密码回调冗余
    若生成密钥时未设置密码,密码回调函数无需添加,多余的回调可能干扰SSL上下文初始化。可移除ctx.set_password_callback相关代码,或确认密钥确实设置了密码"0000"。

  6. 客户端验证模式补充
    客户端可显式设置验证深度,确保能正确验证服务器证书链:

    ctx.set_verify_depth(1);
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 04:41:03