0

I am writing a client server application using the standalone version of asio.

I would like to use the same tcp socket for ssl and non ssl traffic.

Say I have a variable m_socket of type asio::ssl::stream<tcp::socket>, where I have already successfully completed the handshake. I want to use it to send/receive messages in clear, e.g.

// send in clear
asio::async_write(m_socket.next_layer(), buffer, handler);

or encrypted, e.g.

// send encrypted
asio::async_write(m_socket, buffer, handler);

To test if it is even possible to use the raw socket embedded in an ssl stream to send and receive traffic in clear, I wrote the following mini client-server programs. It works correctly when I use the ssl stream in read/write operations. If instead I replace socket with socket.next_layer() (i.e. if I change the #if 1 to #if 0 in both programs) then the text received by the client is garbled.

//////////////////
// CLIENT
//

#include <cstdlib>
#include <iostream>
#include <asio.hpp>
#include <asio/ssl.hpp>

#if 1 // change this to zero to send/recv in clear
#define SOCKET socket
#else
#define SOCKET socket.next_layer()
#endif

using asio::ip::tcp;

int main(int argc, char* argv[])
{
    char message[4] = {};

    try
    {
        asio::io_context io_context;
        asio::ssl::context sslctx(asio::ssl::context::sslv23);
        sslctx.use_certificate_chain_file("certificate.pem");
        sslctx.use_private_key_file("key.pem", asio::ssl::context::pem);
        sslctx.use_tmp_dh_file("dh2048.pem");
        sslctx.set_options(
            asio::ssl::context::default_workarounds
            | asio::ssl::context::no_sslv2
            | asio::ssl::context::single_dh_use);
        asio::ssl::stream<tcp::socket> socket(io_context, sslctx);
        tcp::acceptor(io_context, tcp::endpoint(tcp::v4(), 15000)).accept(socket.next_layer());
        socket.handshake(asio::ssl::stream_base::server);

        for (int i = 0; i < 10; ++i) {
            asio::read(SOCKET, asio::buffer(message, 3));
            std::cout << "read: " << message << "\n";
            snprintf(message, sizeof(message), "%03d", 1 + atoi(message));
            asio::write(SOCKET, asio::buffer(message, 3));
            std::cout << "sent: " << message << "\n";
        }
    }
    catch (std::exception& e)  {
        std::cerr << "Exception: " << e.what() << "\n";
    }

    return 0;
}

and

//////////////////
// SERVER
//

#include <cstdlib>
#include <cstring>
#include <iostream>
#include <asio.hpp>
#include <asio/ssl.hpp>

#if 1 // change this to 0 to send/receive in clear
#define SOCKET socket
#else
#define SOCKET socket.next_layer()
#endif

using asio::ip::tcp;

int main(int argc, char* argv[])
{
    char message[4] = {};

    try
    {
        asio::io_context io_context;
        asio::ssl::context sslctx(asio::ssl::context::sslv23);
        sslctx.load_verify_file("certificate.pem");
        asio::ssl::stream<tcp::socket> socket(io_context, sslctx);
        socket.set_verify_mode(asio::ssl::verify_peer);
        
        auto endpoints = tcp::resolver(io_context).resolve(tcp::v4(), "localhost", "15000");
        asio::connect(socket.lowest_layer(), endpoints);
        socket.handshake(asio::ssl::stream_base::client);
    
        for (int i = 0; i < 10; ++i) {
            snprintf(message, sizeof(message), "%03d", 2*i);
            asio::write(SOCKET, asio::buffer(message, 3));
            std::cout << "sent: " << message << "\n";
            asio::read(SOCKET, asio::buffer(message, 3));
            std::cout << "read: " << message << "\n";
        }

    }
    catch (std::exception& e) {
        std::cerr << "Exception: " << e.what() << "\n";
    }

    return 0;
}

Does somebody know if what I am trying to do is even possible using an asio ssl stream?

Fabio
  • 2,105
  • 16
  • 26
  • How do you send the "single character"? Have you remembered to modify the client to handle this extra protocol layer (you only explicitly say that you have modified the server)? – Some programmer dude Jan 17 '22 at 14:24
  • Yes I do. However in the simple example I posted, there is no additional character. I just try to transmit/receive everything in clear using the ssl stream. – Fabio Jan 17 '22 at 14:28
  • Please try to create an [mre] of the relevant parts of both the client and the server to show us,. Hos is the client sending the "single character"? How is the server receiving it? How is the server sending the "single character"? How is the client receiving it? And how do the client and server both receive the "in the clear" data? – Some programmer dude Jan 17 '22 at 14:33
  • I'm not familiar with the library, but most TLS/SSL libraries support running TLS over an already connected socket. The are various protocols that start out in the clear and then "upgrade" the connection using STARTTLS or something similar, so this is not uncommon. – President James K. Polk Jan 17 '22 at 15:11
  • Edited the question and added a minimal reproducible example – Fabio Jan 17 '22 at 15:41

0 Answers0