0

I am trying to send a BIGNUM (from openssl/bn.h) over socket, but its behaviour is strange.

I use BN_bn2bin() to convert BIGNUM to array of unsigned char and send it over socket using send(). But what the client receives is corrupted. Why?

Here's a minimal working sample:

server.cpp

#include <iostream>
#include <netinet/in.h>
#include <cstring>
#include <cstdlib>
#include <openssl/bn.h>
using namespace std;
int main() {
    // Set up
    int result;
    int opt_val = 1;
    int port = 12345;

    int listen_sock;
    int peer_sock;

    struct sockaddr_in address;

    listen_sock = socket(AF_INET, SOCK_STREAM, 0);

    memset(&address, 0, sizeof(address));

    address.sin_family = AF_INET;
    address.sin_port = htons(port);
    address.sin_addr.s_addr = INADDR_ANY;

    setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof(opt_val));

    result = bind(listen_sock, (struct sockaddr*)&address, sizeof(address));
    if (result != 0) {
        cerr << "bind() failed." << endl;
        exit(result);
    }

    result = listen(listen_sock, 5);
    if (result !=  0) {
        cerr << "listen() failed." << endl;
        exit(result);
    }

    size_t size = sizeof(address);
    peer_sock = accept(listen_sock, (struct sockaddr*)&address, (socklen_t *)&size);
    if (peer_sock < 0) {
        cerr << "accept() failed." << endl;
        exit(result);
    }

    ////////////////////////////////
    // Prepare BIGNUM
    BIGNUM* bn = BN_new();
    BN_rand(bn, 1024, 0, 0);
    size = BN_num_bytes((const BIGNUM*)bn);

    // Send using fixed array
    unsigned char fixed[size];
    BN_bn2bin((const BIGNUM*)bn, fixed);

    // Send using dynamic array
    unsigned char *dynamic;
    dynamic = new unsigned char[size];
    BN_bn2bin((const BIGNUM*)bn, dynamic);

    // First let's compare
    if ( memcmp(fixed, dynamic, size) != 0) {
        cout << "Fixed and dynamic do not equal" << endl;
        exit(-1);
    }

    // Then let's send two arrays
    send(peer_sock, &size, sizeof(size), MSG_MORE);
    send(peer_sock, fixed, size, MSG_MORE);
    send(peer_sock, dynamic, size, MSG_MORE);

}

client.cpp

#include <netinet/in.h>
#include <iostream>
#include <netdb.h>
#include <cstdlib>
#include <arpa/inet.h>
#include <openssl/bn.h>
#include <cstring>

using namespace std;

int main() {

    struct addrinfo* res;
    struct sockaddr_in address;
    int peer_port = 12345;
    int self_sock;
    string peer_ip = "127.0.0.1";
    address.sin_family = AF_INET;
    address.sin_port = htons(peer_port);

    int result = getaddrinfo((const char*)peer_ip.c_str(), NULL, NULL, &res);
    if (result != 0) {
        std::cerr << "Peer hostname invalid." << std::endl;
        exit(-1);
    }
    freeaddrinfo(res);
    inet_pton(AF_INET, (const char*)peer_ip.c_str(), &(address.sin_addr));
    self_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (::connect(self_sock, (struct sockaddr*)&address, sizeof(address)) != 0) {
        std::cerr << "connect() failed." << std::endl;
        exit(-1);
    }


    int size;
    recv(self_sock, &size, sizeof(size), 0);
    // Receive fixed array
    unsigned char fixed[size];
    unsigned char* dynamic = new unsigned char[size];
    recv(self_sock, fixed, size, 0);
    recv(self_sock, dynamic, size, 0);

    if (memcmp(fixed, dynamic, size) != 0) {
        cerr << "client: fixed and dynamic are different!" << endl;
        exit(-1);
    }

    BIGNUM* bn_fixed = BN_new();
    BIGNUM* bn_dynamic = BN_new();
    BN_bin2bn((const unsigned char*)fixed, size, bn_fixed);
    BN_bin2bn((const unsigned char*)dynamic, size, bn_dynamic);
    if (BN_cmp((const BIGNUM*)bn_fixed, (const BIGNUM*)bn_dynamic) != 0) {
        cerr << "bn_fixed and bn_dynamic are different!" << endl;
        exit(-1);
    }

    return 0;
}

Build both with g++ -o <server/client> <server.cpp/client.cpp> -lssl -lcrypto


I used memcmp and verified that the memeory fixed and dynamic points to are equal to one another, but the fixed and dynamic client receives are totally different from each other and the original message. I doubt that it could be because I am using localhost, but when I tried using two independent machines it still happens.

xtt
  • 857
  • 1
  • 8
  • 24
  • 2
    In the server side you are using `size_t` for size, but in the client side you are using just `int`. Although their size can be different. – Konstantin T. Oct 13 '17 at 05:57
  • Why do you cast to `const BIGNUM*` for every function call? This could hide errors where the argument isn't actually of type `BIGNUM*`. – Karsten Koop Oct 13 '17 at 06:39

0 Answers0