Originally published by Robert Beisert at fortcollinsprogram.robert-beisert.com

GNUTLS: Basic Connection with OpenSSL

It’s an interesting problem: how to make it LOOK like we’re using one library, when we’re actually using a completely different one?

GNUTLS comes packaged with an openssl library (-l gnutls-openssl) and associated headers (gnutls/openssl.h). They do a fairly admirable job of allowing us to keep our OpenSSL code.

I’ve noticed a couple of problems, though:

  • BIO_set_conn_hostname() does not exist. We have to open a tcp connection ourselves and pass it into a BIO
  • At present, there is NO MECHANISM for verification callbacks. There’s no reason to call the set_verify() functions

But, hey! Even if you don’t have time to learn the library, you can still open a basic connection. That counts as a win.

/**
  @brief Open a basic TCP socket
**/
int tcp_connect_ct(void)
{
  int err, sd;
  struct sockaddr_in sa;

  sd = socket(AF_INET, SOCK_STREAM, 0);

  memset(&sa, '\0', sizeof(sa));

  sa.sin_family = AF_INET;
  sa.sin_port = htons(atoi("1138"));
  inet_pton(AF_INET, "127.0.0.1", &sa.sin_addr);

  err = connect(sd, (struct sockaddr *) &sa, sizeof(sa));
  if(err < 0)
  {
    printf("Connection error");
    return err;
  }

  return sd;
}


/**
  @brief Certify the input key (1) and obtain the key and certificate from the requested component(2)
  @detail WILL NOT BUILD!!! Sample of functions required to open connection ONLY
  @return	0 on success, non-zero on error
**/
int Create_Client_Connection	(

              )
{
  SSL_library_init();
  OpenSSL_add_all_algorithms();

  SSL_CTX *ctx;
  BIO *bio;
  SSL *ssl;

  ctx = SSL_CTX_new(SSLv23_client_method());
  printf("Setting SSL params\n");
  //This is our certificate file
  SSL_CTX_use_certificate_file(ctx, "cert.pem", SSL_FILETYPE_PEM);
  //This is our own private key
  SSL_CTX_use_PrivateKey_file(ctx, "key.pem", SSL_FILETYPE_PEM);

  //Can set callback where NULL currently is
  //Fun fact: NO IMPLEMENTATION for handling response of callback or second argument (!!)
  //Basically, the OpenSSL compatability library doesn't yet do verification
  SSL_CTX_set_verify(ctx, 1, NULL);

  ssl = SSL_new(ctx);

  //Generate BIO connection (tcp socket)

  //	Connect tcp socket (BIO)

  //We have to open sockets ourselves - hence tcp_connect_ct()
  //No BIO_set_conn_hostname() in the compatabilty library yet
  printf("Connecting with tcp\n");
  int sock = tcp_connect_ct();

  bio = BIO_new_socket(sock, 0);

  SSL_set_bio(ssl, bio, bio);

  //Connect TLS

  if(SSL_connect(ssl) != 1)
  {
    printf("Bad connection\n");
    return -2;
  }
  //For Server variant only - listen for client to connect
  //SSL_accept(ssl);
  printf("SSL connected\n");
  //Hand-verify connection (because the other way is irritating)
  X509 * remote = SSL_get_peer_certificate(ssl);
  if(remote == NULL)
  {
    printf("Error: no certificate retrieved\n");
    return -3;
  }
  else
  {
    printf("Successfully retrieved certificate\n");
  }

  //Imaginary "Read and Write" loop - there are better ways to actually implement this
  while(1)
  {
    SSL_write(ssl, void * buffer, int len);
    SSL_read(ssl, void * buffer, int len);
  }

  free(expected);
  free(key_buffer);
  SSL_shutdown(ssl);
  SSL_free(ssl);
  SSL_CTX_free(ctx);
}

When you have time, check into the source. It’s a free example of how to match someone else’s interfaces with your code.

photo by: