首页 > 解决方案 > Boost Beast 握手:sslv3 alert 握手失败错误

问题描述

我正在使用 Boost Beast 连接到 Web Socket 服务器,但我不断收到错误消息

Resolving push-private.kucoin.com:443...
Performing SSL handshake...
terminate called after throwing an instance of 'boost::wrapexcept<boost::system::system_error>'
  what():  handshake: sslv3 alert handshake failure
Aborted (core dumped)
#include <iostream>
#include <boost/beast/core.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/beast/websocket/ssl.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <cstdlib>
#include <string>
#include "root_certificates.hpp"

using namespace std;

namespace beast = boost::beast;         // from <boost/beast.hpp>
namespace http = beast::http;           // from <boost/beast/http.hpp>
namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
namespace net = boost::asio;            // from <boost/asio.hpp>
namespace ssl = boost::asio::ssl;       // from <boost/asio/ssl.hpp>
using tcp = boost::asio::ip::tcp;       // from <boost/asio/ip/tcp.hpp>

int main() {
    // for a new token, make a POST request to https://api.kucoin.com/api/v1/bullet-public
    const auto token = "2neAiuYvAU61ZDXANAGAsiL4-iAExhsBXZxftpOeh_55i3Ysy2q2LEsEWU64mdzUOPusi34M_wGoSf7iNyEWJ3XLno4x6QqZaEm7Ya4KUfToabAuI1Do9tiYB9J6i9GjsxUuhPw3BlrzazF6ghq4L2ls_Ixv_6qQ8ZRhwt_6WmM=.ianWlE3VQZogjKRmJ-tpyg==";

    auto const host = "push-private.kucoin.com";
    auto const port = "443";
    auto const text = "hello world";

    // The io_context is required for all I/O
    net::io_context ioc;

    // The SSL context is required, and holds certificates
    boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);

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

    ctx.set_default_verify_paths();

    // This holds the root certificate used for verification
    load_root_certificates(ctx);

    // These objects perform our I/O
    tcp::resolver resolver{ioc};
    websocket::stream<beast::ssl_stream<tcp::socket>> ws{ioc, ctx};

    // Look up the domain name
    cout << "Resolving " << host << ":" << port << "..." << endl;
    auto const results = resolver.resolve(host, port);

    // Make the connection on the IP address we get from a lookup
    net::connect(ws.next_layer().next_layer(), results.begin(), results.end());

    // Perform the SSL handshake
    cout << "Performing SSL handshake..." << endl;
    ws.next_layer().handshake(ssl::stream_base::client);

    // Set a decorator to change the User-Agent of the handshake
    ws.set_option(websocket::stream_base::decorator([](websocket::request_type& req){
        req.set(http::field::user_agent,
            std::string(BOOST_BEAST_VERSION_STRING) +
                " websocket-client-coro");
    }));

    // Perform the websocket handshake
    cout << "Performing the websocket handshake..." << endl;
    ws.handshake(host, "/endpoint");

    // Send the message
    cout << "Sending '" << text << "'..." << endl;
    ws.write(net::buffer(std::string(text)));

    // This buffer will hold the incoming message
    beast::flat_buffer buffer;

    // Read a message into our buffer
    cout << "Waiting for web socket server to respond..." << endl;
    ws.read(buffer);

    // Close the WebSocket connection
    ws.close(websocket::close_code::normal);

    // The make_printable() function helps print a ConstBufferSequence
    cout << "This is the data received from the server:" << endl;
    std::cout << beast::make_printable(buffer.data()) << std::endl;

    return 0;
}

示例取自https://www.boost.org/doc/libs/1_70_0/libs/beast/example/websocket/client/sync-ssl/websocket_client_sync_ssl.cpp

我查看了类似于Boost asio GET with client certificate sslv3 hand shake failed的其他线程,这建议添加我也尝试过的 ctx.set_options,但我遇到了同样的错误。

编译选项:

g++ -std=c++17 test.cpp -l boost_system -l crypto -l ssl -pthread  && ./a.out

gcc 版本 9.1.0 (Ubuntu 9.1.0-2ubuntu2~19.04)

任何建议将不胜感激。

标签: c++boost

解决方案


服务器需要 SSL SNI 扩展,否则它不知道您尝试连接到哪个主机,因此不知道将哪个证书发回给您,因此它会中止握手。如果您在浏览器中访问https://99.86.115.35/ ,您会看到同样的问题,它会显示一些 SSL 错误。

解决方案是告诉 OpenSSL 您尝试连接的主机名:

if(! SSL_set_tlsext_host_name(stream.native_handle(), host))
{
   boost::system::error_code ec{static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()};
   throw boost::system::system_error{ec};
}

有关完整示例,请参见野兽 http_client_sync_ssl.cpp


推荐阅读