Converting a tcp client program to SSL

Recently I updated a usenet client program I’d written to use SSL. The usenet NNTP protocol has been around for a very long time, and is a very simple text based protocol. The program I had is written in C and simply opens a tcp client socket to an NNTP server, promotes the socked to a file descriptor then uses fgets and fputs to send lines back and forth. Its pretty elementary stuff.

Now, in recent years usenet server have started handling requests via NNTPS, or NNTP over SSL. I hadn’t considered updating my program to use SSL, but my brother wanted to use it in this way, so I started to investigate how to update it.

OpenSSL is the usual library to use, so I started searching for examples of how to use it. Initially I thought I could just replace the connect with an SSL equivalent and also somehow promote my ssl socket so I could use fgets/fputs on it. Not so. It was a little more complicated than that

First there is a lot more initialisation code: (apologies for the indentation. I hate wordpress)

SSL_library_init(); 
SSL_load_error_strings(); 
OpenSSL_add_all_algorithms(); 
CRYPTO_set_id_callback(thread_id_myprog); 
CRYPTO_set_locking_callback(thread_lock_myprog); 
num_locks = CRYPTO_num_locks(); 
locks = malloc (num_locks * sizeof *locks); 
for (n=0;n < num_locks;n++) { 
   if (pthread_mutex_init(&locks[n], NULL)) { 
      printf("cannot init mutexes for openssl\n"); 
      return -1; 
   } 
}

All the locks stuff is supposedly to do with my program being multi-threaded. I don’t really understand it that well.

Then you need to make your tcp client socket connection as you normally do (in the ‘sock’ var below)

int sock; 

SSL_CTX *context; 
SSL_METHOD *method; 
SSL *connection; 
BIO *io; 
BIO *sbio; 
BIO *ssl_bio; 

context= NULL; 
method= NULL; 
connection=NULL; 
method=SSLv23_client_method(); 
context = SSL_CTX_new(connection.method); 
... 
sbio= BIO_new_socket(sock,BIO_NOCLOSE); 
if (sbio==NULL) {printf("bad sbion"); exit(1); } 
connection = SSL_new(context); 
if (connection==NULL) {printf("bad connectionn"); exit(1); } 
SSL_set_bio(connection,sbio,sbio); 
... 
io = BIO_new(BIO_f_buffer()); 
ssl_bio = BIO_new(BIO_f_ssl()); 
BIO_set_ssl(ssl_bio,connection,BIO_CLOSE); 
BIO_push(io,ssl_bio); 
... 
SSL_connect(connection);

Thats enought to get the SSL connection going. You’ll find examples similar to the above all over the place (i find Google codesearch invaluable). I think you’re meant to verify the SSL cert somewhere in there as well.

And now for the bit that tripped me up. Initially I made attempts to use SSL_read to read lines from the remote NNTPS server. SSL_read works much the same as read so its not line buffered. I really needed a line buffered function, otherwise I’d have to do a lot of rewriting. Fortunately there are some line buffered functions; the BIO functions. So my fgets was basically replaced with:

result = BIO_gets(io,linebuf,sizeof(linebuf));

My fputs was replaced with:

BIO_puts(io,cmdbuf); 
BIO_flush(io);

And finally when you’re closing your connection you need to do this:

SSL_set_shutdown(connection, 
   SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); 
BIO_free_all(io);