Search code examples
c++boostboost-asio

Handshake is not working Http GET request with Boost.Asio


I'm trying to Boost.Asio to make a GET request to https://api.binance.com/api/v3/time, which it will show a result like this one:

{"serverTime":1679236121308}

To do this, I'm using Boost.Asio and I'm following this example from the official Boost library.

It seems that my problem is with the handshake. Mi code looks like this:

#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/error.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <cstdlib>
#include <iostream>
#include <string>


namespace http = boost::beast::http;
using namespace std;
using tcp = boost::asio::ip::tcp;
namespace ssl = boost::asio::ssl;

void load_root_certificate(ssl::context& ctx)
{
    string cert;
    cert += "-----BEGIN CERTIFICATE-----\n"
        "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\n"
        "Y26WPws6rA==\n"
        "-----END CERTIFICATE-----";

    boost::system::error_code ec;
    ctx.add_certificate_authority(boost::asio::buffer(cert.data(), cert.size()), ec);
    cout << ec.what() << endl;
}

int main()
{
    try {
        auto const host = "api.binance.com";
        auto port = "80";
        auto target = "/api/v3/time";

        boost::asio::io_context ioc;
        ssl::context ctx{ssl::context::sslv23_client};
        ctx.set_default_verify_paths();
        load_root_certificate(ctx);

        tcp::resolver resolver{ioc};
        ssl::stream<tcp::socket> stream{ioc, ctx};

        auto const result = resolver.resolve(host, port);


        boost::asio::connect(stream.next_layer(), result.begin(), result.end());
        stream.handshake(ssl::stream_base::client);

        http::request<http::string_body> req{http::verb::get, target, 10};
        req.set(http::field::host, host);
        req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);

        http::write(stream, req);

        boost::beast::flat_buffer buffer;
        http::response<http::dynamic_body> res;

        http::read(stream, buffer, res);
        cout << res << endl;

        boost::system::error_code ec;
        stream.shutdown(ec);

        if (ec && ec != boost::system::errc::not_connected)
            throw boost::system::system_error{ec};
    } catch(const exception& e) {
        std::cout << "Error: " << e.what() << endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

I took the certificate added in load_toor_certificate function using Chrome, but this is the part I have doubts about, because if I run my code I get the error:

Error: handshake: packet length too long (SSL routines) [asio.ssl:167772358]

Is there any way to use the boost example to make a GET or POST request over HTTPS without downloading the certificate or something like that like CURL does?

PD: Running the same query using curl:

freddy@Freddys-Mac-Studio ~ %
curl https://api.binance.com/api/v3/time
{"serverTime":1679237703479}%    

Solution

  • You are using port 80 (HTTP) but you need to use port 443 (HTTPS). This is likely why you get a weird-looking error from OpenSSL--because you aren't connecting to an SSL/TLS-enabled endpoint.