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();

        ...
}

Reply via email to