0

I am writing a client to send data to remote server. I am 3 different messages (hello, hello1, hello2) using SSL_WRITE, but in server I can see only single message is sent like this: hellohello1hello2. Can someone please help what am I missing here, why separate hello, hello1 and hello2 messages are not sent but a string hellohello1hello2 is sent. I am new to openSSL, could you please suggest any tutorial to learn openSSL for TLS over TCP. I need to send logs from my client machine to remote syslog server using TLS over TCP.

#include <winsock2.h>
#include <ws2tcpip.h>
#include <Wspiapi.h>  // This is for pre XP machines to work with new APIs. See MSDN

#include "openssl/sha.h"
#include "openssl/rsa.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
#include "openssl/x509v3.h"
#include "openssl/rand.h"
#include "openssl/crypto.h"
#include <errno.h>
#include <iostream>

#include <thread>
using namespace std;
#include <string>

SSL_CTX *InitSSL_CTX(void)
{
    
    const SSL_METHOD *method = TLSv1_2_method(); // Create new client-method instance 
    SSL_CTX *ctx = SSL_CTX_new(method);


    // Trusted root CA certificate bundle
    int iRetVal = SSL_CTX_load_verify_locations(ctx, "ca.pem", NULL);
    if (iRetVal != ERR_LIB_NONE)
    {
        cout<<"Failed to load trusted CA certificates bundle";
        exit(EXIT_FAILURE);
    }

// Callback gets invoked for each certificate in the certificate chain; we just log certificate information in there

    if (ctx == nullptr)
    {
        ERR_print_errors_fp(stderr);
        exit(EXIT_FAILURE);
    }
    return ctx;
}


int OpenConnection(const char *hostname, const char *port)
{
    SOCKET ConnectSocket;
    struct addrinfo *result, *ptr, hints;
    int iResult;
    char portStr[1024];


/*
Initialize Winsock.
WSAStartup allows to specify what version of WinSock you want to use.
It sets up all the "behind the scenes stuff" that any process needs to use sockets.
winSockDLL is loaded into the process and it sets up many internal structures.
Each process must call WSAStartup to initialize the structures within its own memory space and WSACleanup to tear them down again when it is finished using sockets.
*/
    WSADATA wsaData;
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        cout << "WSAStartup failed with error: " << iResult << endl;
        return 1;
    }


    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    // Resolve the server address and port
    iResult = getaddrinfo(hostname, port, &hints, &result);
    if (iResult != 0)
    {
        cout << "getaddrinfo failed with error: " << iResult;
        WSACleanup();
        return 1;
    }

    // Attempt to connect to an address
    for (ptr = result; ptr != NULL; ptr = ptr->ai_next)
    {
        // Create a SOCKET for connecting to server
        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
        ptr->ai_protocol);
        if (ConnectSocket == INVALID_SOCKET)
        {
            cout << "socket failed with error: " << WSAGetLastError();
            break;
        }

        // Connect to server.
        iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
        if (iResult == SOCKET_ERROR) {
            closesocket(ConnectSocket);
            ConnectSocket = INVALID_SOCKET;
            cout << "connect failed" << endl;
            continue;
        }
        break;
    }

    freeaddrinfo(result);
    if (ConnectSocket == INVALID_SOCKET) {
        cout << "Unable to connect to server!" << endl;
        WSACleanup();
        return 1;
    }
    return ConnectSocket;
}

int main()
{
     SSL_CTX *ctx = InitSSL_CTX();
     SSL *ssl = SSL_new(ctx);
     if (ssl == nullptr)
     {
       cout << "SSL_new() failed\n";
       exit(EXIT_FAILURE);
     }

     //Host is hardcoded to localhost for testing purposes
     const int sfd = OpenConnection("172.16.74.4", "6514");
     SSL_set_fd(ssl, sfd);
 
     const int status = SSL_connect(ssl);
     if (status != 1)
     {
         SSL_get_error(ssl, status);
         ERR_print_errors_fp(stderr); //High probability this doesn't do anything
         cout << "SSL_connect failed with SSL_get_error code :" << status << endl;
         exit(EXIT_FAILURE);
     }

     cout << "Connected with %s encryption\n" << SSL_get_cipher(ssl) << endl;
     DisplayCerts(ssl);

      SSL_write(ssl, "hello", strlen("hello"));
      SSL_write(ssl, "hello1", strlen("hello1"));
      SSL_write(ssl, "hello2", strlen("hello2"));

      SSL_free(ssl);

      SSL_CTX_free(ctx);

      return 0;

}

aromahola
  • 170
  • 1
  • 9
  • That just isn't how tcp works, there are no separate messages it's just a continuous stream of bytes, you need to add your own message delimiters – Alan Birtles Nov 16 '20 at 07:13
  • how should I add my own message delimiters here @AlanBirtles could you please help? – aromahola Nov 16 '20 at 07:16
  • Add a comma between messages? – Alan Birtles Nov 16 '20 at 07:17
  • @aromahola: There are many similar questions on this site. Typical approaches are either to prefix the message with fixed-size length parameter or to have a clear separator between messages. The first approach is usually the easier one to implement since it is up-front clear how many bytes are needed to get the length and from the length how many bytes are needed for the following message. A separator needs you to continuously analyze the read data and also maybe escape the separator in the normal data. – Steffen Ullrich Nov 16 '20 at 07:21
  • @aromahola: Apart from that: SSL_write usually writes different SSL records and these should be separable at the server. If it does not then the problem is likely how your server side code (which is not shown) is reading the data. Still, you better don't rely on message boundaries set by SSL records since the maximum size of a SSL record might be smaller than the maximum size of your message - in which case it will be split over multiple records and you again face the problem that it is not clear where the message ends. – Steffen Ullrich Nov 16 '20 at 07:26
  • When you want to send and receive messages, you must define precisely what you mean by a "message" and write code that sends and receives messages according to that definition. If you don't do that, your code has no idea where one message ends and another begins. – David Schwartz Nov 16 '20 at 07:48
  • @SteffenUllrich the code above is my client and the server here is syslog server (rsyslog from centOS). I do not see any message limit in rsyslog.conf file in server side. I saw in wireshark on client, that 3 different requests(application data) are sent to syslog server, It means that syslog server is merging them somehow. Let me check how can I avoid merging of content in syslog server. – aromahola Nov 16 '20 at 08:01
  • @DavidSchwartz Could you please suggest any video/course/doc to implement TLS over TCP from my windows program to remote syslog server. I am not able to get a proper documentation with all the detailed concepts of openSSL. Even if I don't load ca.pem in client messages were being sent to syslog server and I could see TLSv1.2 in the wireshark – aromahola Nov 16 '20 at 08:03
  • @SteffenUllrich Could you please suggest any video/course/doc to implement TLS over TCP from my windows program to remote syslog server. I am not able to get a proper documentation with all the detailed concepts of openSSL. Even if I don't load ca.pem in client messages were being sent to syslog server and I could see TLSv1.2 in the wireshark – aromahola Nov 16 '20 at 08:03
  • @aromahola: Suggestions about external video/course etc are off-topic here but you of course might ask more specific questions here as a new question. As for sending messages to a syslog server - please study the standards in this area on how the messages need to look like, for example [this section in RFC 6587](https://tools.ietf.org/html/rfc6587#section-3.4.1). – Steffen Ullrich Nov 16 '20 at 08:07
  • Note that [syslog over TCP already suggests such a framing method](https://tools.ietf.org/html/rfc6587#section-3.4) – Botje Nov 16 '20 at 12:01

0 Answers0