Saleem gagguturu
Saleem gagguturu

Reputation: 145

Boost Beast handshake: sslv3 alert handshake failure error

I'm using Boost Beast to connect to a Web Socket server, but I keep getting an error

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;
}

Example taken from https://www.boost.org/doc/libs/1_70_0/libs/beast/example/websocket/client/sync-ssl/websocket_client_sync_ssl.cpp

I looked on other threads similar to Boost asio GET with client certificate sslv3 hand shake failed which suggested adding the ctx.set_options, which I've also tried, but I'm getting the same error.

Compilation options:

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

gcc version 9.1.0 (Ubuntu 9.1.0-2ubuntu2~19.04)

Any suggestions would only be appreciated.

Upvotes: 3

Views: 3975

Answers (1)

Alan Birtles
Alan Birtles

Reputation: 36379

The server requires the SSL SNI extension otherwise it doesn't know which host you are trying to connect to and therefore which certificate to send back to you so it aborts the handshake. You can see the same issue if you go to https://99.86.115.35/ in your browser, it will show some SSL error.

The solution is to tell OpenSSL the hostname you are trying to connect to:

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};
}

See the beast http_client_sync_ssl.cpp for a full example

Upvotes: 7

Related Questions