Reputation: 145
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
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