000026133 - How to enable thread safety in RSA BSAFE Crypto-C ME  SSL-C and MES

Document created by RSA Customer Support Employee on Jun 16, 2016Last modified by RSA Customer Support Employee on Apr 21, 2017
Version 2Show Document
  • View in full screen mode

Article Content

Article Number000026133
Applies ToRSA BSAFE Crypto-C ME 2.0
RSA BSAFE Crypto-C ME 2.1
RSA BSAFE SSL-C 2.7
RSA BSAFE MES 2.2
Operating in a multi-threaded environment
IssueHow to enable thread safety in RSA BSAFE Crypto-C ME, SSL-C and MES
Intermittant errors, possibly including SSL_ERROR_SYSCALL with SSL-C
Infinite loop when R_lock_num() is called within the locking callback function
CauseProper locking in a multi-threaded environment is not occurring.
Resolution

RSA BSAFE Crypto-C ME, SSL-C and MES are not multi-threaded, but they are thread safe as long as the proper locking callbacks are registered and cryptographic objects are not shared between threads.  These callbacks provide a method for application programmers to set platform specific locking mechanisms into the BSAFE libraries.  When these callbacks are set the libraries will use them to synchronize access to global data structures.

The associated library requires that two callback functions be registered.  The first is a function that returns the current thread ID.  The second is a function that will obtain or release a lock on a particular object.  If these two functions are registered, the library will lock necessary sections of code when appropriate.  All locking after this point is transparent to the application and application programmer. 

There is a default implementation for the thread ID callback for all release level platforms, so it is unnecessary to implement a callback on these platforms.  See the Release Notes for a list of release level platforms.  The ability to implement a custom thread ID callback enables developers to use our libraries on non-standard environments and OS's.

Note:  The following examples demonstrate how to implement the callbacks for a Win32 based system.  The sample code provides sample implementations for Solaris, Win32, VxWorks, and pthreads based applications.  The sample code can be found in the samples\source\cb directory in your installation.

The following function demonstrates how one might implement the thread ID callback.  This function simply calls the appropriate Win32 function to obtain the current thread ID and returns that value.

unsigned long APPCB_thread_id(void) {
  unsigned long ret;

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


This callback function is then registered by a call to R_thread_id_set_cb:

R_thread_id_set_cb((unsigned long (*)(void))APPCB_thread_id);

The other callback function that needs to be registered is the function that will actually obtain or release a lock.  Because the library performs many different operations it uses multiple locks to efficient control access to the different internal structures.  

In the case of Win32, we'll demonstrate Mutex objects.

The R_lock_num() function returns an integer value that is equal to the number of Mutexes (locks) required.  To satisfy the library's needs, we'll declare a series of Mutexes:

int numLocks = R_lock_num();
HANDLE *locks =
malloc (sizeof(HANDLE*) * numLocks);
int i = 0;
for ( i = 0 ; i <
numLocks ; i++) {
  locks[i] =
CreateMutex (NULL, FALSE, NULL);
}


Once the series of locks has been created, a function that will obtain or release the lock is required:
int APPCB_locking_cb(int mode,int lockid,char *file,int line) {
  if (mode & R_LOCK_LOCK) {
    
WaitForSingleObject(locks[lockid],INFINITE);
  }
  else {
    
ReleaseMutex(locks[lockid]);
  }

  return (1);
}

This function is then registered by calling R_lock_set_cb:

R_lock_set_cb((int (*)(int,int,char *,int))APPCB_locking_cb);

In addition to setting up the locking callbacks, the application needs to be written correctly.  The external objects are not thread safe ? multiple threads cannot concurrently read and write to a BSAFE object.  Normally each thread maintains and accesses its own objects.  If multiple threads will be accessing the same object, the application must guarantee they will not access it concurrently.

In order to see exactly where the locking occurs, use the sample callback implementations in your application and define APP_LOCK_TRACE when compiling.

Generally the following operations will perform locking.  The most important is the random number generator. Operations are locked for reasons of sharing global entropy.  It is possible to use the random number generators without locking but continuous random number generator checks may fail. 

  1. Creating an R_CR_CTX in FIPS mode.
  2. Using a random number generator. (all operations are mutually exclusive).
  3. Creating a copy of a R_PKEY object will lock the reference count - all reference counting uses the same lock.
  4. Getting a module cached in the library context - R_LIB_CTX_get_module().
  5. Performing an SSL handshake

R_lock_num() generates a call to the locking callback function, so calling R_lock_num() within a custom locking callback will result in an infinite loop.  Generally, you'll want to call R_lock_num() once to determine how many locks to create, before registering the locking callback with R_lock_set_cb().  This is how the default implementations work.
Legacy Article IDa33302

Attachments

    Outcomes