16

OpenSSL documents state that it can safely be used in multi-threaded applications provided that at least two callback functions are set, locking_function and threadid_func....

I've written programs which use OpenSSL API. Moreover, I know how to use pthreads. However, the OpenSSL documents are written in the form of a manual, and I can't see a step-by-step guide on what I have to do when using OpenSSL in a multi-threaded app.

Is there a tutorial on using OpenSSL with pthreads? (I searched the web, but no satisfactory result appeared.)

PS: I'm working in Debian Lenny & Ubuntu Lucid/Maverick.

PS2: OpenSSL includes a sample, but it's far too complicated to start with.

Sadeq Dousti
  • 3,346
  • 6
  • 35
  • 53
  • I did a search on the web and found this code below - unfortunately I do not know openSSL enough to tell you it will help, but it seems related to what you asking :)

    http://www.cs.odu.edu/~cs772/sourcecode/NSwO/compiled/common.c

    good luck

    – lemic Nov 09 '10 at 14:43

4 Answers4

13

Chapter 10 of the book The Definitive Guide to Linux Network Programming includes a section Thread-safe Programming with OpenSSL (on pages 255-259). This section details how OpenSSL and the pthreads library work. Specially, it tells how to setup the callback functions both in static allocation (where the number of threads are known a priori) and dynamic allocation (where threads are created and destroyed on the fly).

Another good source is Section 4.1 of the book Network Security with OpenSSL, titled Multithread Support. It provides static/dynamic allocation mechanisms in subsections 4.1.1 and 4.1.2, respectively.

Finally, there's the book Unix-Netzwerkprogrammierung mit Threads, Sockets und SSL, which is by far the most comprehensive one on the subject. Unfortunately, the English translation of this German book is not available.

Edit: The above references are now considered obsolete, as OpenSSL 1.1.0 changelog explains:

OpenSSL now uses a new threading API. It is no longer necessary to set locking callbacks to use OpenSSL in a multi-threaded environment. There are two supported threading models: pthreads and windows threads. It is also possible to configure OpenSSL at compile time for "no-threads". The old threading API should no longer be used. The functions have been replaced with "no-op" compatibility macros.

[Alessandro Ghedini, Matt Caswell]

This is further elaborated in OpenSSL blog post OpenSSL and Threads.

See also this issue on OpenSSL GitHub repository, which is open since 2017.

Community
  • 1
  • 1
Sadeq Dousti
  • 3,346
  • 6
  • 35
  • 53
11

Don't know about a tutorial, but here are two libcurl-based examples that might help:

http://curl.haxx.se/libcurl/c/opensslthreadlock.html
http://curl.haxx.se/libcurl/c/threaded-ssl.html

Wodin
  • 3,243
  • 1
  • 26
  • 55
9
  • openssl must be configured with threads option ./config thread -D_REENTRANT

  • It's a matter of copy & paste; the openssl tar ball includes a sample in file crypto/threads/mttest.c

copy relevant platform specific implementation & call thread_setup for initialization and thread_cleanup for wrap up;

MichaelMoser
  • 3,172
  • 1
  • 26
  • 26
  • 1
    Thank you very much. This is the best answer, IMHO. All other answers reference dated methods. For me, I checked with OpenSSL version I was running with `openssl version -a`. Then, I referenced the exact version with the git tag, which in my case, was `https://github.com/openssl/openssl/blob/OpenSSL_1_0_1/crypto/threads/mttest.c`. When checking the OpenSSL version with this method, you can see if its compiled with `-D_REENTRANT` as well. Hope this helps. – Homer6 Jan 22 '14 at 20:31
5

Based on Wodin's answer using cURL references, all I did was copy these 4 functions

#include <openssl/crypto.h> //In addition to other ssl headers

...

/* we have this global to let the callback get easy access to it */ 
static pthread_mutex_t *lockarray;

static void lock_callback(int mode, int type, char *file, int line)
{
  (void)file;
  (void)line;
  if (mode & CRYPTO_LOCK) {
    pthread_mutex_lock(&(lockarray[type]));
  }
  else {
    pthread_mutex_unlock(&(lockarray[type]));
  }
}

static unsigned long thread_id(void)
{
  unsigned long ret;

  ret=(unsigned long)pthread_self();
  return(ret);
}

static void init_locks(void)
{
  int i;

  lockarray=(pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() *
                                        sizeof(pthread_mutex_t));
  for (i=0; i<CRYPTO_num_locks(); i++) {
    pthread_mutex_init(&(lockarray[i]),NULL);
  }

  CRYPTO_set_id_callback((unsigned long (*)())thread_id);
  CRYPTO_set_locking_callback((void (*)(int, int, const char*, int))lock_callback);
}

static void kill_locks(void)
{
  int i;

  CRYPTO_set_locking_callback(NULL);
  for (i=0; i<CRYPTO_num_locks(); i++)
    pthread_mutex_destroy(&(lockarray[i]));

  OPENSSL_free(lockarray);
}

Then call these two functions as follows

int main(int argc, char **argv)
{
   //pthread initialization goes here

  init_locks();

  //pthread stuff here (create, join, etc)


  kill_locks();
  return 0;
}

That got rid of all weird errors with SSL_load_error_strings(); segfaults and double free condition from glibc.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
enthusiasticgeek
  • 2,640
  • 46
  • 53
  • Great example! Can we use reader-writer locks instead of mutex in "lock_callback"? Does OpenSSL support that? – manpatha Sep 19 '17 at 05:56
  • 1
    @manpatha - Yes, the call backs send a CRYPTO_WRITE or CRYPTO_READ to the lock function, so in theory, you can use that to determine what kind of lock you need. – Rahly Dec 28 '17 at 20:53