OpenSSL thread safe secure connections
Time ago I wrote some articles to explain, with simple examples, the use of OpenSSL API s for file encryption:
Now, in this article, I’ll show how to add secure thread safe connections to your software using OpenSSL .
As reported by official FAQs, Multi-threaded applications must provide two callback functions to OpenSSL by calling CRYPTO_set_locking_callback() and CRYPTO_set_id_callback() . The library below, sslc ( Secure Sockets Layer Connections ) , sets up this two callbacks and offers two functions to the application to handle secure connections : open_sslc and close_sslc .
Version: 0.1
Changelog: initial release
/*************************************************************************/
/* sslc.c */
/* v. 0.1 */
/* Copyright (C) 2008 Paolo Ardoino, */
/* by Paolo Ardoino < paolo.ardoino@gmail.com > */
/* */
/* This program is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU General Public License as */
/* published by the Free Software Foundation; either version 2 of the */
/* License, or (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will be useful, but */
/* WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
/* General Public License for more details. */
/* */
/* You should have received a copy of the GNU General Public License */
/* along with this program; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111- */
/* 1307, USA. */
/*************************************************************************/
#ifndef SSLC_H
#define SSLC_H
#include <netdb.h>
#define MAX_THREADS 100
#define BUFFER_SIZE 512
#define READ_BUFFER(ssl, buf) do { SSL_read((SSL *) ssl, (buf), BUFFER_SIZE); (buf)[strlen(buf) - 2] = ‘\0′; } while(0)
#define WRITE_BUFFER(ssl, buf) do { SSL_write((SSL *) ssl, (buf), strlen(buf)); } while(0)
static void ssl_thread_setup(void);
static void ssl_thread_cleanup(void);
static void locking_function(int mode, int type, const char *file, int line);
static unsigned long id_function(void);
static void *open_sslc(struct hostent *hent, int port, char *user, char *password);
static void close_sslc(void *ssl);
#endif /* SSLC_H */
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <openssl/crypto.h>
#include <errno.h>
#include <openssl/ssl.h>
static pthread_mutex_t *lock_cs;
static long *lock_count;
static pthread_mutex_t locker = PTHREAD_MUTEX_INITIALIZER;
static int mtctr;
static unsigned long id_function(void)
{
return ((unsigned long) pthread_self());
}
static void locking_function(int mode, int type, const char *file, int line)
{
if (mode & CRYPTO_LOCK) {
pthread_mutex_lock(&lock_cs[type]);
lock_count[type]++;
} else {
pthread_mutex_unlock(&lock_cs[type]);
}
}
static void ssl_thread_setup(void)
{
int num = CRYPTO_num_locks();
int ctr;
lock_cs = (pthread_mutex_t*) OPENSSL_malloc(num * sizeof(pthread_mutex_t));
lock_count = (long*) OPENSSL_malloc(num * sizeof(long));
for (ctr = 0; ctr < num; ctr++) {
lock_count[ctr] = 0;
pthread_mutex_init(&lock_cs[ctr], NULL);
}
CRYPTO_set_id_callback(id_function);
CRYPTO_set_locking_callback(locking_function);
}
static void ssl_thread_cleanup(void)
{
int ctr;
CRYPTO_set_locking_callback(NULL);
for (ctr = 0; ctr < CRYPTO_num_locks(); ctr++) {
pthread_mutex_destroy(&lock_cs[ctr]);
}
OPENSSL_free(lock_cs);
OPENSSL_free(lock_count);
}
static void *open_sslc(struct hostent *hent, int port, char *user, char *password)
{
struct sockaddr_in sa;
int sd;
char cmd[BUFFER_SIZE];
SSL *ssl;
SSL_CTX *ctx;
pthread_mutex_lock(&locker);
if (!mtctr++) {
ssl_thread_setup();
}
pthread_mutex_unlock(&locker);
sa.sin_family = hent->h_addrtype;
sa.sin_port = htons(port);
memcpy((char *) &sa.sin_addr.s_addr, hent->h_addr_list[0], hent->h_length);
if ((sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
printf("cannot open socket for ‘%s’\n", hent->h_name);
return NULL;
}
printf("connecting to ‘%s’\n", hent->h_name);
if (connect(sd, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)) == -1) {
printf("connection failed on ‘%s’\n", hent->h_name);
close(sd);
return NULL;
}
printf("’%s’ connected\n", hent->h_name);
SSLeay_add_ssl_algorithms();
ctx = SSL_CTX_new(SSLv23_client_method());
ssl = SSL_new(ctx);
SSL_CTX_free(ctx);
SSL_set_fd(ssl,sd);
if (SSL_connect(ssl) == 1) {
return ssl;
}
printf("cannot authenticate on ‘%s’\n", hent->h_name);
if (!SSL_shutdown(ssl)) {
SSL_shutdown(ssl);
}
close(sd);
SSL_free(ssl);
pthread_mutex_lock(&locker);
if (!–mtctr) {
ssl_thread_cleanup();
}
pthread_mutex_unlock(&locker);
return NULL;
}
static void close_sslc(void *ssl)
{
char cmd[BUFFER_SIZE];
sprintf(cmd, "QUIT\r\n");
WRITE_BUFFER(ssl,cmd);
READ_BUFFER(ssl,cmd);
if (ERR_BUFFER(cmd)) {
printf("sslc refuses to quit\n");
}
if (!SSL_shutdown(ssl)) {
SSL_shutdown(ssl);
}
close(SSL_get_fd(ssl));
SSL_free(ssl);
pthread_mutex_lock(&locker);
if (!–mtctr) {
ssl_thread_cleanup();
}
pthread_mutex_unlock(&locker);
}
Download this code: sslc.c
Here is an example of usage of the above library :
int main() { struct hostent *he; SSL *ssl; if(!(he = gethostbyname("mail.example.com"))) { fprintf(stderr, "Error: failed gethostbyname(localhost)\n"); exit(EXIT_FAILURE); } ssl = open_pop3s(he, 995, "username", "password"); close_pop3s(ssl); }
:-)
Simple enough?


Hi Paolo,
Thank you for the sample code. but It’s the first time dealing with cryptography.
I would appreciate if you can recommend me a book that explain from beginig , how to set up an SSL Server, what libraries are needed and sample codes that show how to deal with OpenSSL library.
BTW, I am doing programming under Linux Suse 10.2
Thanks again Paolo,
Amir