Andrew,

  1.  I'm using 0.9.6 so I don't know if what I write here applies to your
OpenSSL version.  Initializing SSL_CTX once before spawning threads should
work. I have SSL_CTX be initialized in a static class so I'm sure SSL_CTX is
ready first and goes away when the process is shutdown (any lingering
threads will fail of course in this case). (I'm passing
SSLv23_client_method() to SSL_CTX_new call).

  2. Also, if you are running on Solaris you will see that the default hash
id created for thread slots is not a very good one: it uses the pid which
will probably be the same for all threads :)
In your version of OpenSSl check if in cryptlib.c the CRYPTO_thread_id
function  returns getpid() when in SOLARIS.  You will notice that
id_callback will be NULL if you don't set an id_callback via
CRYPTO_set_id_callback.
If this is the case, then this is probably your problem.

Make sure that you provide a "sane" implementation to generate IDs by
calling CRYPT_set_id_callback function when you are initializing the SSL
context (you need to this only once per process obviously).

You can use pthreads_thread_id(void ); or solaris_thread_id(void ); (in
crypto/threads/th-locks.c ) functions as the callback functions to generate
the hash for thread slot ids.

For example:

  // Set function to create hash for slot ID
  CRYPTO_set_id_callback(solaris_thread_id);


I hope this helps

Emilio

-----Original Message-----
From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED] Behalf Of Andrew Mann
Sent: Monday, September 08, 2003 9:35 AM
To: [EMAIL PROTECTED]; [EMAIL PROTECTED]
Subject: SSL_CTX_new race condition


        I appologize if this comes through twice.  I haven't seen the first
come through the list yet and it was sent Friday, so I presume it's been
gobbled up somewhere :)


        I'm working on an application that needs to work with a lot of
simultaneous SSL connections to the same remote host.  It spawns a
thread for each connection and handles each connection entirely in that
thread.  These connections each last anywhere from half a second to a
minute, and as soon as the connection is finished, it's closed and the
thread is terminated (and often another thread started to process
another request).
        The OpenSSL library is initialized prior to any connection handling
thread starting.  Apparently thread safety is a FAQ, but the answer on
the www.openssl.org FAQ and related links falls far short of helpful and
borders on just plain inaccurate.
        Initially I tried using a single SSL_CTX for all connections, so that
while no SSL objects were being shared across threads, one SSL_CTX
object was being used to all calls to SSL_new().  This failed miserably.
  SSL connections failed randomly and frequently during the negotation
phase.  The SSL_CTX ended up getting freed on some test runs during the
middle of the run.  Although there are suggestions that a single SSL_CTX
is meant to be shared between multiple connections, there isn't any
specific mention of wether that is supposed to work with connections
handled by different threads, so I suppose it's not (well it appears not
to at least).
        I moved to making a new SSL_CTX for each thread as well.  This had
somewhat better luck, but randomly during startup one of the calls to
SSL_CTX_new() would fail with "error:140A90A1:SSL
routines:SSL_CTX_new:library has no ciphers".  After a bit of digging it
appears that SSL_CTX_new() is not really threadsafe either.  It calls
ssl_create_cipher_list() which checks the status of an unmutexed global
variable init_ciphers (ssl/ssl_ciph.c).  If the value is its
initialization value of 1, then load_ciphers() is called.
load_ciphers() sets init_ciphers to 0 and then procedes to load various
ciphers for the library to use.
        Unfortunately, since this value isn't protected by a mutex it's not
unlikely that in the event of two threads "racing" through SSL_CTX_new()
that the lead thread will clear init_ciphers and then be interrupted
before it can actually perform any loading.
        For the time being I've worked around this by creating a SSL_CTX prior
to starting any threads that has no point other than to prompt cipher
loading before any potential race conditions.

Fixes:
        I'm not sure about the SSL_CTX shared between threads, but it would be
nice if the settings (CA files particularly) didn't have to be loaded
from disk for each thread spawned in this scenario.
        Protect init_ciphers with a mutex. Or at least move init_ciphers=0 to
the end of the load_ciphers() function so that the worst case condition
becomes multiple calls to load_ciphers() instead of a tiny chance of
multiple calls and a larger chance of a"library has no ciphers" error.

Andrew




______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    [EMAIL PROTECTED]
Automated List Manager                           [EMAIL PROTECTED]

______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
User Support Mailing List                    [EMAIL PROTECTED]
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to