Please note, I don't know the insides of OpenSSL, but I do a lot of multithreaded programming on Unix, so the following are not authorative answers, just my own opinions:
> 1) According to the FAQ, "an SSL connection may not concurrently be > used by multiple threads". Does this mean that an SSL connection can > be used by different threads provided access is limited to one at a > time? > I assume that having a mutex for each SSL object would prevent it from being concurrently used by multiple threads. So this should be OK. However do you really need to use multiple concurrent threads with the same SSL object? Think of it as a TCP socket, each thread has a list of open sockets, or SSL objects, there is no need to share it with other threads. > 2) We've implemented the required locking and thread_id callbacks and > we're getting into a deadlock. OpenSSL is aquiring a lock and not > releasing it. Have there been any bug fixes to the static locking > since 0.9.7d? We've looked at the change log and nothing is jumping > out at us. > You don't say which platform this is, or which threading library is being used. My guess is, this is more likely to be a problem with your implementation, rather than OpenSSL bug. > 3) Our application opens multiple SSL connections. We call > SSL_library_init() only once. However, we're calling > CRYPTO_set_locking_callback and CRYPTO_set_id_callback for each > connection, but always with the same function pointers. Is this > correct? > I don't think this is correct. The whole point of locking callbacks is to provide mutual exclusion for critical sections. You need to initialise static/dynamic threading callbacks before you call SSL_library_init(). If you're in the middle of using the library and locking callbacks are not set, this can result in race conditions. I've attached a fragment from some of my code. It shows how to initialise static and dynamic locking callbacks on Unix, using Pthreads API. You can probably adapt it to your platform/programming language.
/* Static locks */ static pthread_mutex_t *stlocks; int stlocks_len; /* Dynamic locks */ struct CRYPTO_dynlock_value { pthread_mutex_t mutex; }; /* Static locking functions ------------------------------------------------------------------------------*/ static unsigned long id_callback(void) { return (unsigned long)&errno; } static void locking_callback(int mode, int n, const char *file, int line) { if(mode & CRYPTO_LOCK) pthread_mutex_lock(&stlocks[n]); else pthread_mutex_unlock(&stlocks[n]); } static void init_openssl_stlocks(void) { int i; stlocks_len = CRYPTO_num_locks(); if((stlocks = malloc(sizeof(pthread_mutex_t) * stlocks_len)) == NULL) { printf("malloc() error\n"); exit(1); } for(i = 0; i < stlocks_len; i++) { pthread_mutex_init(&stlocks[i], NULL); } CRYPTO_set_id_callback(id_callback); CRYPTO_set_locking_callback(locking_callback); } /*----------------------------------------------------------------------------*/ /* Dynamic locking functions ------------------------------------------------------------------------------*/ static struct CRYPTO_dynlock_value *dynlock_create_callback( const char *file, int line) { struct CRYPTO_dynlock_value *lock; if((lock = malloc(sizeof(struct CRYPTO_dynlock_value))) == NULL) { printf("malloc() error\n"); exit(1); } pthread_mutex_init(&lock->mutex, NULL); return lock; } static void dynlock_destroy_callback( struct CRYPTO_dynlock_value *lock, const char *file, int line) { pthread_mutex_destroy(&lock->mutex); free(lock); } static void dynlock_lock_callback( int mode, struct CRYPTO_dynlock_value *lock, const char *file, int line) { if(mode & CRYPTO_LOCK) pthread_mutex_lock(&lock->mutex); else pthread_mutex_unlock(&lock->mutex); } static void init_openssl_dynlocks(void) { CRYPTO_set_dynlock_create_callback(dynlock_create_callback); CRYPTO_set_dynlock_destroy_callback(dynlock_destroy_callback); CRYPTO_set_dynlock_lock_callback(dynlock_lock_callback); } /*----------------------------------------------------------------------------*/ int main(void) { init_openssl_stlocks(); init_openssl_dynlocks(); SSL_library_init(); SSL_load_error_strings(); ... }