[Cryptech-Commits] [user/sra/pkcs11] 01/01: Add basic mutex support, including default ("OS") implementation using POSIX threads. Compiles, but no runtime testing done yet.

git at cryptech.is git at cryptech.is
Wed Jun 3 00:51:06 UTC 2015


This is an automated email from the git hooks/post-receive script.

sra at hactrn.net pushed a commit to branch master
in repository user/sra/pkcs11.

commit d5e614627886d09a19f39ffca51226a3f0760f6a
Author: Rob Austein <sra at hactrn.net>
Date:   Tue Jun 2 19:02:47 2015 -0400

    Add basic mutex support, including default ("OS") implementation using
    POSIX threads.  Compiles, but no runtime testing done yet.
---
 pkcs11.c | 588 +++++++++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 482 insertions(+), 106 deletions(-)

diff --git a/pkcs11.c b/pkcs11.c
index 5b7576f..fef9e0b 100644
--- a/pkcs11.c
+++ b/pkcs11.c
@@ -162,6 +162,20 @@
 #define PKCS15_KEYRING ".cryptech-pkcs11.p15"
 #endif
 
+/*
+ * Whether to include POSIX-specific features.
+ */
+
+#ifndef USE_POSIX
+#define USE_POSIX 1
+#endif
+
+#if USE_POSIX
+#include <unistd.h>
+#include <pthread.h>
+#include <errno.h>
+#endif
+
 

 
 /*
@@ -299,12 +313,41 @@ static CRYPT_DEVICE cryptlib_device = CRYPT_HANDLE_NONE;
 static char *database_filename = NULL;
 static char *keyring_filename = NULL;
 
+/*
+ * Mutex callbacks.
+ */
+
+static CK_CREATEMUTEX  mutex_cb_create;
+static CK_DESTROYMUTEX mutex_cb_destroy;
+static CK_LOCKMUTEX    mutex_cb_lock;
+static CK_UNLOCKMUTEX  mutex_cb_unlock;
+
+/*
+ * Global mutex.  We may want something finer grained later, but this
+ * will suffice to comply with the API requirements.
+ */
+
+static CK_VOID_PTR p11_global_mutex;
+
+/*
+ * (POSIX-specific) process which last called C_Initialize().
+ */
+
+#if USE_POSIX
+static pid_t initialized_pid;
+#endif
+
 

 
 /*
  * Syntactic sugar for functions returning CK_RV complex enough to
- * need cleanup actions on failure.  Also does very basic logging
- * for debug-by-printf().
+ * need cleanup actions on failure.  Also does very basic logging for
+ * debug-by-printf().
+ *
+ * NB: This uses a variable ("rv") and a goto target ("fail") which
+ * must be defined in the calling environment.  We could make these
+ * arguments to the macro, but doing so would make the code less
+ * readable without significantly reducing the voodoo factor.
  */
 
 #define lose(_ck_rv_code_)                                              \
@@ -386,6 +429,168 @@ static char *cf_pkcs15_keyring(void)
 

 
 /*
+ * Thread mutex utilities.  We need to handle three separate cases:
+ *
+ * 1) User doesn't care about mutexes;
+ * 2) User wants us to use "OS" mutexes;
+ * 3) User wants us to use user-specified mutexs.
+ *
+ * For "OS" mutexes, read POSIX Threads mutexes, at least for now.
+ *
+ * PKCS #11 sort of has a fourth case, but it's really just license
+ * for us to pick either the second or third case at whim.
+ *
+ * To simplify the rest of the API, we provide a POSIX-based
+ * implementation which uses the same API an user-provided mutex
+ * implementation would be required to use, use null function pointers
+ * to represent the case where the user doesn't need mutexes at all,
+ * and wrap the whole thing in trivial macros to insulate the rest of
+ * the code from the grotty details.
+ */
+
+/*
+ * Basic macros.
+ */
+
+#define mutex_create(_m_)   (mutex_cb_create  == NULL ? CKR_OK : mutex_cb_create(_m_))
+#define mutex_destroy(_m_)  (mutex_cb_destroy == NULL ? CKR_OK : mutex_cb_destroy(_m_))
+#define mutex_lock(_m_)     (mutex_cb_lock    == NULL ? CKR_OK : mutex_cb_lock(_m_))
+#define mutex_unlock(_m_)   (mutex_cb_unlock  == NULL ? CKR_OK : mutex_cb_unlock(_m_))
+
+/*
+ * Slightly higher-level macros for common operations.
+ */
+
+#define mutex_lock_or_fail(_m_)         \
+  do {                                  \
+    CK_RV _rv_ = mutex_lock(_m_);       \
+    if (_rv_ != CKR_OK)                 \
+      return _rv_;                      \
+  } while (0)
+
+#define mutex_unlock_with_rv(_rv_, _m_) \
+  ((_rv_) == CKR_OK ? mutex_unlock(_m_) : (mutex_unlock(_m_), (_rv_)))
+
+/*
+ * Mutex implementation using POSIX mutexes.
+ */
+
+#if USE_POSIX
+
+static CK_RV posix_mutex_create(CK_VOID_PTR_PTR ppMutex)
+{
+  pthread_mutex_t *m = NULL;
+  CK_RV rv;
+
+  if (ppMutex == NULL)
+    lose(CKR_GENERAL_ERROR);
+
+  if ((m = malloc(sizeof(*m))) == NULL)
+    lose(CKR_HOST_MEMORY);
+
+  switch (pthread_mutex_init(m, NULL)) {
+
+  case 0:
+    *ppMutex = m;
+    return CKR_OK;
+
+  case ENOMEM:
+    lose(CKR_HOST_MEMORY);
+
+  default:
+    lose(CKR_GENERAL_ERROR);
+  }  
+
+ fail:
+  if (m != NULL)
+    free(m);
+  return rv;
+}
+
+static CK_RV posix_mutex_destroy(CK_VOID_PTR pMutex)
+{
+  CK_RV rv;
+
+  if (pMutex == NULL)
+    lose(CKR_MUTEX_BAD);
+
+  switch (pthread_mutex_destroy(pMutex)) {
+
+  case 0:
+    free(pMutex);
+    return CKR_OK;
+
+  case EINVAL:
+    lose(CKR_MUTEX_BAD);
+
+  case EBUSY:
+    /*
+     * PKCS #11 mutex semantics are a bad match for POSIX here,
+     * leaving us only the nuclear option.  Feh.  Fall through.
+     */
+
+  default:
+    lose(CKR_GENERAL_ERROR);
+  }
+
+ fail:
+  return rv;
+}
+
+static CK_RV posix_mutex_lock(CK_VOID_PTR pMutex)
+{
+  CK_RV rv;
+
+  if (pMutex == NULL)
+    lose(CKR_MUTEX_BAD);
+
+  switch (pthread_mutex_lock(pMutex)) {
+
+  case 0:
+    return CKR_OK;
+
+  case EINVAL:
+    lose(CKR_MUTEX_BAD);
+
+  default:
+    lose(CKR_GENERAL_ERROR);
+  }
+
+ fail:
+  return rv;
+}
+
+static CK_RV posix_mutex_unlock(CK_VOID_PTR pMutex)
+{
+  CK_RV rv;
+
+  if (pMutex == NULL)
+    lose(CKR_MUTEX_BAD);
+
+  switch (pthread_mutex_unlock(pMutex)) {
+
+  case 0:
+    return CKR_OK;
+
+  case EINVAL:
+    lose(CKR_MUTEX_BAD);
+
+  case EPERM:
+    lose(CKR_MUTEX_NOT_LOCKED);
+
+  default:
+    lose(CKR_GENERAL_ERROR);
+  }
+
+ fail:
+  return rv;
+}
+
+#endif /* USE_POSIX */
+
+

+
+/*
  * Wrappers around some of Cryptlib's context functions, so that the
  * rest of the code can mostly ignore whether a particular algorithm
  * is implemented in hardware or not.  In theory, we could achieve
@@ -2240,36 +2445,97 @@ CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
   CK_C_INITIALIZE_ARGS_PTR a = pInitArgs;
   CK_RV rv;
 
+  /*
+   * We'd like to detect the error of calling this method more than
+   * once in a single process without an intervening call to
+   * C_Finalize(), but there's no completely portable way to do that
+   * when faced with things like the POSIX fork() system call.  For
+   * the moment, we use a POSIX-specific check, but may need to
+   * generalize this for other platforms.
+   */
+
+#if USE_POSIX
+  if (initialized_pid == getpid())
+    lose(CKR_CRYPTOKI_ALREADY_INITIALIZED);
+#endif
+
+  /*
+   * Sort out what the user wants to do about mutexes.  Default is not
+   * to use mutexes at all.
+   *
+   * There's a chicken and egg problem here: setting up the global
+   * mutex and mutex function pointers creates a race condition, and
+   * there's no obvious action we can take which is robust in the face
+   * of pathological behavior by the caller such as simultaneous calls
+   * to this method with incompatible mutex primitives.
+   *
+   * Given that (a) it's an error to call this method more than once
+   * in the same process without an intervening F_Finalize() call, and
+   * given that (b) we haven't actually promised to do any kind of
+   * locking at all until this method returns CKR_OK, we punt
+   * responsibility for this pathological case back to the caller.
+   */
+
+  mutex_cb_create  = NULL;
+  mutex_cb_destroy = NULL;
+  mutex_cb_lock    = NULL;
+  mutex_cb_unlock  = NULL;
+
   if (a != NULL) {
-    int functions_provided = ((a->CreateMutex  != NULL) +
-                              (a->DestroyMutex != NULL) +
-                              (a->LockMutex    != NULL) +
-                              (a->UnlockMutex  != NULL));
+
+    const int functions_provided = ((a->CreateMutex  != NULL) +
+                                    (a->DestroyMutex != NULL) +
+                                    (a->LockMutex    != NULL) +
+                                    (a->UnlockMutex  != NULL));
 
     /*
      * Reserved is, um, reserved.
-     * Threading parameters must either all be present or all be absent.
+     * Mutex parameters must either all be present or all be absent.
      */
 
     if (a->pReserved != NULL || (functions_provided & 3) != 0)
       lose(CKR_ARGUMENTS_BAD);
 
     /*
-     * At present we don't support threads or locking.  This may be a
-     * problem for OpenDNSSEC.  Need to figure out what the "obvious"
-     * system threading mechanism is supposed to be, or make it
-     * configurable, or something.  For the moment, just return the
-     * correct error code to report that we're lame.
+     * If the user provided mutex functions, use them.  Otherwise, if
+     * the user wants locking, use POSIX mutexes or return an error
+     * depending on whether we have POSIX mutexes available.
+     * Otherwise, we don't need to use mutexes.
      */
 
-#warning Thread support check disabled, this needs to be fixed
-#if 0
-    if (functions_provided || (a->flags & CKF_OS_LOCKING_OK) != 0)
+    if (functions_provided) {
+      mutex_cb_create  = a->CreateMutex;
+      mutex_cb_destroy = a->DestroyMutex;
+      mutex_cb_lock    = a->LockMutex;
+      mutex_cb_unlock  = a->UnlockMutex;
+    }
+
+    else if ((a->flags & CKF_OS_LOCKING_OK) != 0) {
+#if USE_POSIX
+      mutex_cb_create  = posix_mutex_create;
+      mutex_cb_destroy = posix_mutex_destroy;
+      mutex_cb_lock    = posix_mutex_lock;
+      mutex_cb_unlock  = posix_mutex_unlock;
+#else
       lose(CKR_CANT_LOCK);
 #endif
+    }
   }
 
   /*
+   * Now that we know which mutex implementation to use, set up a
+   * global mutex.  We may want something finer grained later, but
+   * this is enough to preserve the basic API semantics.
+   *
+   * Open question whether we should lock at this point, given that
+   * until we return we haven't promised to do locking.  Skip for now
+   * as it's simpler, fix later if it turns out to be a problem.
+   */
+
+  if ((rv = mutex_create(&p11_global_mutex)) != CKR_OK)
+    goto fail;
+
+  /*
    * Initialize SQLite3, opening the database(s) and loading the
    * schema and views.
    */
@@ -2300,6 +2566,10 @@ CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
     lose(CKR_GENERAL_ERROR);
 #endif
 
+#if USE_POSIX
+  initialized_pid = getpid();
+#endif
+
   return CKR_OK;
 
  fail:
@@ -2322,9 +2592,13 @@ CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
 
 CK_RV C_Finalize(CK_VOID_PTR pReserved)
 {
+  CK_RV rv = CKR_OK;
+
   if (pReserved != NULL)
     return CKR_ARGUMENTS_BAD;
 
+  mutex_lock_or_fail(p11_global_mutex);
+
   /*
    * Destroy all current sessions.
    */
@@ -2336,7 +2610,7 @@ CK_RV C_Finalize(CK_VOID_PTR pReserved)
    */
 
   if (!sql_fini())
-    return CKR_GENERAL_ERROR;
+    lose(CKR_GENERAL_ERROR);
 
   /*
    * Shut down hardware device and exit cryptlib.  Is there any point
@@ -2350,7 +2624,20 @@ CK_RV C_Finalize(CK_VOID_PTR pReserved)
 #endif
 
   cryptEnd();
-  return CKR_OK;
+
+  /*
+   * By this point we're pretty well committed to shutting down, so
+   * there's not much to be done if these mutex operations fail.
+   */
+
+  rv =  mutex_unlock(p11_global_mutex);
+  (void) mutex_destroy(p11_global_mutex);
+  p11_global_mutex = NULL;
+  return rv;
+
+ fail:
+  (void) mutex_unlock(p11_global_mutex);
+  return rv;
 }
 
 CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
@@ -2358,6 +2645,8 @@ CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
   /*
    * Use pkcs11f.h to build dispatch vector for C_GetFunctionList().
    * This should be const, but that's not what PKCS #11 says, oh well.
+   *
+   * This doesn't touch anything requiring locks, nor should it.
    */
 
   static CK_FUNCTION_LIST ck_function_list = {
@@ -2381,6 +2670,7 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent,
 {
   /*
    * We only have one slot, and it's hardwired.
+   * No locking required here as long as this holds.
    */
 
   if (pulCount == NULL)
@@ -2400,6 +2690,10 @@ CK_RV C_GetSlotList(CK_BBOOL tokenPresent,
 CK_RV C_GetTokenInfo(CK_SLOT_ID slotID,
                      CK_TOKEN_INFO_PTR pInfo)
 {
+  /*
+   * No locking required here as long as we're just returning constants.
+   */
+
   if (pInfo == NULL)
     return CKR_ARGUMENTS_BAD;
 
@@ -2496,6 +2790,8 @@ CK_RV C_OpenSession(CK_SLOT_ID slotID,
   p11_session_t *session = NULL;
   CK_RV rv;
 
+  mutex_lock_or_fail(p11_global_mutex);
+
   if (slotID != P11_ONE_AND_ONLY_SLOT)
     lose(CKR_SLOT_ID_INVALID);
 
@@ -2533,17 +2829,29 @@ CK_RV C_OpenSession(CK_SLOT_ID slotID,
 
   assert(p11_session_consistent_login());
 
+  if ((rv = mutex_unlock(p11_global_mutex)) != CKR_OK)
+    goto fail;
+
   *phSession = session->handle;
   return CKR_OK;
 
  fail:
   p11_session_free(session);
+  (void) mutex_unlock(p11_global_mutex);
   return rv;
 }
 
 CK_RV C_CloseSession(CK_SESSION_HANDLE hSession)
 {
-  return p11_session_delete(hSession);
+  CK_RV rv;
+
+  mutex_lock_or_fail(p11_global_mutex);
+
+  if ((rv = p11_session_delete(hSession)) != CKR_OK)
+    goto fail;
+
+ fail:
+  return mutex_unlock_with_rv(rv, p11_global_mutex);
 }
 
 CK_RV C_CloseAllSessions(CK_SLOT_ID slotID)
@@ -2551,9 +2859,11 @@ CK_RV C_CloseAllSessions(CK_SLOT_ID slotID)
   if (slotID != P11_ONE_AND_ONLY_SLOT)
     return CKR_SLOT_ID_INVALID;
 
+  mutex_lock_or_fail(p11_global_mutex);
+
   p11_session_delete_all();
 
-  return CKR_OK;
+  return mutex_unlock(p11_global_mutex);
 }
 
 CK_RV C_Login(CK_SESSION_HANDLE hSession,
@@ -2562,10 +2872,13 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession,
               CK_ULONG ulPinLen)
 {
   p11_session_t *session;
+  CK_RV rv = CKR_OK;
   int crypt_cmd;
 
+  mutex_lock_or_fail(p11_global_mutex);
+
   if (pPin == NULL)
-    return CKR_ARGUMENTS_BAD;
+    lose(CKR_ARGUMENTS_BAD);
 
   /*
    * Mind, I don't really know why this function takes a session
@@ -2574,7 +2887,7 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession,
    */
 
   if (p11_session_find(hSession) == NULL)
-    return CKR_SESSION_HANDLE_INVALID;
+    lose(CKR_SESSION_HANDLE_INVALID);
 
   /*
    * This is where the combination of pure-software and hardware
@@ -2596,7 +2909,7 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession,
    */
 
   if (logged_in_as != not_logged_in)
-      return CKR_USER_ALREADY_LOGGED_IN;    
+    lose(CKR_USER_ALREADY_LOGGED_IN);    
 
   /*
    * We don't (yet?) support CKU_CONTEXT_SPECIFIC.
@@ -2605,8 +2918,8 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession,
   switch (userType) {
   case CKU_USER:                crypt_cmd = CRYPT_DEVINFO_AUTHENT_USER;         break;
   case CKU_SO:                  crypt_cmd = CRYPT_DEVINFO_AUTHENT_SUPERVISOR;   break;
-  case CKU_CONTEXT_SPECIFIC:    return CKR_OPERATION_NOT_INITIALIZED;
-  default:                      return CKR_USER_TYPE_INVALID;
+  case CKU_CONTEXT_SPECIFIC:    lose(CKR_OPERATION_NOT_INITIALIZED);
+  default:                      lose(CKR_USER_TYPE_INVALID);
   }
 
   /*
@@ -2617,7 +2930,7 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession,
   if (userType == CKU_SO)
     for (session = p11_sessions; session != NULL; session = session->link)
       if (session->state == CKS_RO_PUBLIC_SESSION)
-        return CKR_SESSION_READ_ONLY_EXISTS;
+        lose(CKR_SESSION_READ_ONLY_EXISTS);
 
   /*
    * Ask Cryptlib to log us in.  We may need to examine cryptlib error
@@ -2626,16 +2939,16 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession,
 
 #if ENABLE_CRYPTLIB_DEVICE
   if (cryptSetAttributeString(cryptlib_device, crypt_cmd, pPin, ulPinLen) != CRYPT_OK)
-    return CKR_PIN_INCORRECT;
+    lose(CKR_PIN_INCORRECT);
 #endif
 
 #if ENABLE_CRYPTLIB_SOFTWARE
   {
     char *newpin;
     if (memchr(pPin, '\0', ulPinLen) != NULL)
-      return CKR_PIN_INCORRECT;
+      lose(CKR_PIN_INCORRECT);
     if ((newpin = malloc(ulPinLen + 1)) == NULL)
-      return CKR_HOST_MEMORY;
+      lose(CKR_HOST_MEMORY);
     memcpy(newpin, pPin, ulPinLen);
     newpin[ulPinLen] = '\0';
     if (pin != NULL)
@@ -2669,14 +2982,18 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession,
 
   assert(p11_session_consistent_login());
 
-  return CKR_OK;
+ fail:
+  return mutex_unlock_with_rv(rv, p11_global_mutex);
 }
 
 CK_RV C_Logout(CK_SESSION_HANDLE hSession)
 {
   p11_session_t *session;
+  CK_RV rv = CKR_OK;
   int crypt_cmd;
 
+  mutex_lock_or_fail(p11_global_mutex);
+
   /*
    * Mind, I don't really know why this function takes a session
    * handle, given that the semantics don't seem to call upon us to do
@@ -2684,12 +3001,12 @@ CK_RV C_Logout(CK_SESSION_HANDLE hSession)
    */
 
   if (p11_session_find(hSession) == NULL)
-    return CKR_SESSION_HANDLE_INVALID;
+    lose(CKR_SESSION_HANDLE_INVALID);
 
   switch (logged_in_as) {
   case logged_in_as_user:       crypt_cmd = CRYPT_DEVINFO_AUTHENT_USER;         break;
   case logged_in_as_so:         crypt_cmd = CRYPT_DEVINFO_AUTHENT_SUPERVISOR;   break;
-  case not_logged_in:           return CKR_USER_NOT_LOGGED_IN;
+  case not_logged_in:           lose(CKR_USER_NOT_LOGGED_IN);
   }
 
   /*
@@ -2703,7 +3020,7 @@ CK_RV C_Logout(CK_SESSION_HANDLE hSession)
 
 #if ENABLE_CRYPTLIB_DEVICE
   if (cryptSetAttributeString(cryptlib_device, crypt_cmd, "", 0) != CRYPT_OK)
-    return CKR_FUNCTION_FAILED;
+    lose(CKR_FUNCTION_FAILED);
 #endif
 
 #if ENABLE_CRYPTLIB_SOFTWARE
@@ -2740,7 +3057,8 @@ CK_RV C_Logout(CK_SESSION_HANDLE hSession)
 
   assert(p11_session_consistent_login());
 
-  return CKR_OK;
+ fail:
+  return mutex_unlock_with_rv(rv, p11_global_mutex);
 }
 
 CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession,
@@ -2757,10 +3075,14 @@ CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession,
 
   const char *flavor = is_token_handle(hObject) ? "token" : "session";
 
-  p11_session_t *session = p11_session_find(hSession);
+  p11_session_t *session;
   sqlite3_stmt *q = NULL;
-  CK_RV rv = CKR_OK;
   sqlite3_int64 id;
+  CK_RV rv = CKR_OK;
+
+  mutex_lock_or_fail(p11_global_mutex);
+
+  session = p11_session_find(hSession);
 
   if ((rv = p11_object_check_rights(session, hObject, p11_object_access_write)) != CKR_OK)
     goto fail;
@@ -2804,7 +3126,7 @@ CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession,
 
  fail:
   sqlite3_finalize(q);
-  return rv;
+  return mutex_unlock_with_rv(rv, p11_global_mutex);
 }
 
 CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession,
@@ -2818,19 +3140,23 @@ CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession,
 
   const char *flavor = is_token_handle(hObject) ? "token" : "session";
 
-  p11_session_t *session = p11_session_find(hSession);
+  p11_session_t *session;
   const p11_descriptor_t *descriptor = NULL;
   CK_BBOOL cka_sensitive, cka_extractable;
   CK_OBJECT_CLASS cka_class;
   CK_KEY_TYPE cka_key_type;
   int sensitive_object = 0;
   sqlite3_stmt *q = NULL;
-  CK_RV rv = CKR_OK;
+  CK_RV rv;
   int ret, i;
 
+  mutex_lock_or_fail(p11_global_mutex);
+
   if (pTemplate == NULL)
     lose(CKR_ARGUMENTS_BAD);
 
+  session = p11_session_find(hSession);
+
   if ((rv = p11_object_check_rights(session, hObject, p11_object_access_read)) != CKR_OK)
     goto fail;
 
@@ -2859,6 +3185,8 @@ CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession,
       !sql_check_ok(sqlite3_bind_int64(q, 1, hObject)))
     lose(CKR_FUNCTION_FAILED);
 
+  rv = CKR_OK;
+
   for (i = 0; i < ulCount; i++) {
 
     if (sensitive_object && p11_attribute_is_sensitive(descriptor, pTemplate[i].type)) {
@@ -2893,7 +3221,7 @@ CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession,
 
  fail:
   sqlite3_finalize(q);
-  return rv;
+  return mutex_unlock_with_rv(rv, p11_global_mutex);
 }
 
 CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession,
@@ -2930,12 +3258,14 @@ CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession,
   static const char select_format[] =
     " SELECT object_handle FROM findobjects_%lu NATURAL JOIN object ORDER BY object_id";
 
-  p11_session_t *session = p11_session_find(hSession);
+  p11_session_t *session;
   sqlite3_stmt *q1 = NULL, *q2 = NULL;
   CK_RV rv = CKR_OK;
   int i, ret;
 
-  if (session == NULL)
+  mutex_lock_or_fail(p11_global_mutex);
+
+  if ((session = p11_session_find(hSession)) == NULL)
     lose(CKR_SESSION_HANDLE_INVALID);
 
   if (ulCount > 0  && pTemplate == NULL)
@@ -3032,7 +3362,7 @@ CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession,
  fail:
   sqlite3_finalize(q1);
   sqlite3_finalize(q2);
-  return rv;
+  return mutex_unlock_with_rv(rv, p11_global_mutex);
 }
 
 CK_RV C_FindObjects(CK_SESSION_HANDLE hSession,
@@ -3040,11 +3370,13 @@ CK_RV C_FindObjects(CK_SESSION_HANDLE hSession,
                     CK_ULONG ulMaxObjectCount,
                     CK_ULONG_PTR pulObjectCount)
 {
-  p11_session_t *session = p11_session_find(hSession);
+  p11_session_t *session;
   int i, ret = SQLITE_OK;
   CK_RV rv = CKR_OK;
 
-  if (session == NULL)
+  mutex_lock_or_fail(p11_global_mutex);
+
+  if ((session = p11_session_find(hSession)) == NULL)
     lose(CKR_SESSION_HANDLE_INVALID);
 
   if (session->find_query == NULL)
@@ -3083,7 +3415,7 @@ CK_RV C_FindObjects(CK_SESSION_HANDLE hSession,
   *pulObjectCount = i;
 
  fail:
-  return rv;
+  return mutex_unlock_with_rv(rv, p11_global_mutex);
 }
 
 CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
@@ -3091,11 +3423,13 @@ CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
   static const char drop_format[] =
     " DROP TABLE IF EXISTS findobjects_%lu";
 
-  p11_session_t *session = p11_session_find(hSession);
+  p11_session_t *session;
   sqlite3_stmt *q = NULL;
   CK_RV rv = CKR_OK;
   
-  if (session == NULL)
+  mutex_lock_or_fail(p11_global_mutex);
+
+  if ((session = p11_session_find(hSession)) == NULL)
     lose(CKR_SESSION_HANDLE_INVALID);
 
   if (session->find_query == NULL)
@@ -3114,32 +3448,34 @@ CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
 
  fail:
   sqlite3_finalize(q);
-  return rv;
+  return mutex_unlock_with_rv(rv, p11_global_mutex);
 }
 
 CK_RV C_DigestInit(CK_SESSION_HANDLE hSession,
                    CK_MECHANISM_PTR pMechanism)
 {
-  p11_session_t *session = p11_session_find(hSession);
+  p11_session_t *session;
   CRYPT_ALGO_TYPE algo;
-  unsigned hash_len;
-  CK_RV rv;
+  unsigned hash_len = 0;
+  CK_RV rv = CKR_OK;
 
-  if (session == NULL)
-    return CKR_SESSION_HANDLE_INVALID;
+  mutex_lock_or_fail(p11_global_mutex);
+
+  if ((session = p11_session_find(hSession)) == NULL)
+    lose(CKR_SESSION_HANDLE_INVALID);
 
   if (pMechanism == NULL)
-    return CKR_ARGUMENTS_BAD;
+    lose(CKR_ARGUMENTS_BAD);
 
   if (session->digest_context != CRYPT_HANDLE_NONE)
-    return CKR_OPERATION_ACTIVE;
+    lose(CKR_OPERATION_ACTIVE);
 
   switch (pMechanism->mechanism) {
   case CKM_SHA_1:       algo = CRYPT_ALGO_SHA1; break;
   case CKM_SHA256:      algo = CRYPT_ALGO_SHA2; hash_len = 256; break;
   case CKM_SHA384:      algo = CRYPT_ALGO_SHA2; hash_len = 384; break;
   case CKM_SHA512:      algo = CRYPT_ALGO_SHA2; hash_len = 512; break;
-  default:              return CKR_MECHANISM_INVALID;
+  default:              lose(CKR_MECHANISM_INVALID);
   }
 
   assert((hash_len & 7) == 0);
@@ -3151,13 +3487,14 @@ CK_RV C_DigestInit(CK_SESSION_HANDLE hSession,
       cryptSetAttribute(session->digest_context, CRYPT_CTXINFO_BLOCKSIZE, hash_len >> 3) != CRYPT_OK)
     lose(CKR_FUNCTION_FAILED);
 
-  return CKR_OK;
+  return mutex_unlock(p11_global_mutex);
 
  fail:
-  if (session->digest_context != CRYPT_HANDLE_NONE)
+  if (session != NULL && session->digest_context != CRYPT_HANDLE_NONE) {
     cryptDestroyContext(session->digest_context);
-  session->digest_context = CRYPT_HANDLE_NONE;
-  return rv;
+    session->digest_context = CRYPT_HANDLE_NONE;
+  }
+  return mutex_unlock_with_rv(rv, p11_global_mutex);
 }
 
 CK_RV C_Digest(CK_SESSION_HANDLE hSession,
@@ -3166,24 +3503,26 @@ CK_RV C_Digest(CK_SESSION_HANDLE hSession,
                CK_BYTE_PTR pDigest,
                CK_ULONG_PTR pulDigestLen)
 {
-  p11_session_t *session = p11_session_find(hSession);
-  CK_RV rv;
+  p11_session_t *session;
+  CK_RV rv = CKR_OK;
   int len;
 
-  if (session == NULL)
-    return CKR_SESSION_HANDLE_INVALID;
+  mutex_lock_or_fail(p11_global_mutex);
+
+  if ((session = p11_session_find(hSession)) == NULL)
+    lose(CKR_SESSION_HANDLE_INVALID);
 
   if (pData == NULL || pulDigestLen == NULL)
-    return CKR_ARGUMENTS_BAD;
+    lose(CKR_ARGUMENTS_BAD);
 
   if (session->digest_context == CRYPT_HANDLE_NONE)
-    return CKR_OPERATION_NOT_INITIALIZED;
+    lose(CKR_OPERATION_NOT_INITIALIZED);
 
   if (pDigest == NULL) {
     if (cryptGetAttribute(session->digest_context, CRYPT_CTXINFO_BLOCKSIZE, &len) != CRYPT_OK)
       lose(CKR_FUNCTION_FAILED);
     *pulDigestLen = len;
-    return CKR_OK;
+    return mutex_unlock(p11_global_mutex);
   }
 
   if (cryptEncrypt(session->digest_context, pData, ulDataLen) != CRYPT_OK)
@@ -3209,31 +3548,36 @@ CK_RV C_Digest(CK_SESSION_HANDLE hSession,
   rv = CKR_OK;                  /* Fall through */
 
  fail:
-  cryptDestroyContext(session->digest_context);
-  session->digest_context = CRYPT_HANDLE_NONE;
-  return rv;
+  if (session != NULL && session->digest_context != CRYPT_HANDLE_NONE) {
+    cryptDestroyContext(session->digest_context);
+    session->digest_context = CRYPT_HANDLE_NONE;
+  }
+  return mutex_unlock_with_rv(rv, p11_global_mutex);
 }
 
 CK_RV C_SignInit(CK_SESSION_HANDLE hSession,
                  CK_MECHANISM_PTR pMechanism,
                  CK_OBJECT_HANDLE hKey)
 {
-  p11_session_t *session = p11_session_find(hSession);
+  p11_session_t *session;
   char keyid[CRYPT_MAX_HASHSIZE * 2 + 1];
   CRYPT_ALGO_TYPE sign_algo, hash_algo;
   unsigned hash_size = 0;
+  int need_cleanup = 0;
   int key_algo;
-  CK_RV rv;
+  CK_RV rv = CKR_OK;
 
-  if (session == NULL)
-    return CKR_SESSION_HANDLE_INVALID;
+  mutex_lock_or_fail(p11_global_mutex);
+
+  if ((session = p11_session_find(hSession)) == NULL)
+    lose(CKR_SESSION_HANDLE_INVALID);
 
   if (pMechanism == NULL)
-    return CKR_ARGUMENTS_BAD;
+    lose(CKR_ARGUMENTS_BAD);
 
   if (session->sign_key_context    != CRYPT_HANDLE_NONE ||
       session->sign_digest_context != CRYPT_HANDLE_NONE)
-    return CKR_OPERATION_ACTIVE;
+    lose(CKR_OPERATION_ACTIVE);
 
   if ((rv = p11_object_check_rights(session, hKey, p11_object_access_read)) != CKR_OK)
     goto fail;
@@ -3249,6 +3593,8 @@ CK_RV C_SignInit(CK_SESSION_HANDLE hSession,
 
   assert((hash_size & 7) == 0);
 
+  need_cleanup = 1;
+
   if (!p11_object_get_keyid(hKey, keyid, sizeof(keyid)) ||
       cryptlib_load_key(&session->sign_key_context, keyid) != CRYPT_OK ||
       cryptGetAttribute(session->sign_key_context, CRYPT_CTXINFO_ALGO, &key_algo) != CRYPT_OK)
@@ -3266,18 +3612,24 @@ CK_RV C_SignInit(CK_SESSION_HANDLE hSession,
                         CRYPT_CTXINFO_BLOCKSIZE, hash_size >> 3) != CRYPT_OK)
     lose(CKR_FUNCTION_FAILED);
 
-  return CKR_OK;
+  need_cleanup = 0;
+
+  rv = CKR_OK;                  /* Fall through */
 
  fail:
-  if (session->sign_key_context != CRYPT_HANDLE_NONE)
+  assert(!need_cleanup || session != NULL);
+
+  if (need_cleanup && session->sign_key_context != CRYPT_HANDLE_NONE) {
     cryptDestroyContext(session->sign_key_context);
-  session->sign_key_context = CRYPT_HANDLE_NONE;
+    session->sign_key_context = CRYPT_HANDLE_NONE;
+  }
 
-  if (session->sign_digest_context != CRYPT_HANDLE_NONE)
+  if (need_cleanup && session->sign_digest_context != CRYPT_HANDLE_NONE) {
     cryptDestroyContext(session->sign_digest_context);
-  session->sign_digest_context = CRYPT_HANDLE_NONE;
+    session->sign_digest_context = CRYPT_HANDLE_NONE;
+  }
 
-  return rv;
+  return mutex_unlock_with_rv(rv, p11_global_mutex);
 }
 
 CK_RV C_Sign(CK_SESSION_HANDLE hSession,
@@ -3286,18 +3638,20 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession,
              CK_BYTE_PTR pSignature,
              CK_ULONG_PTR pulSignatureLen)
 {
-  p11_session_t *session = p11_session_find(hSession);
+  p11_session_t *session;
   int len, algo;
   CK_RV rv;
 
-  if (session == NULL)
-    return CKR_SESSION_HANDLE_INVALID;
+  mutex_lock_or_fail(p11_global_mutex);
+
+  if ((session = p11_session_find(hSession)) == NULL)
+    lose(CKR_SESSION_HANDLE_INVALID);
 
   if (pData == NULL || pulSignatureLen == NULL)
-    return CKR_ARGUMENTS_BAD;
+    lose(CKR_ARGUMENTS_BAD);
 
   if (session->sign_key_context == CRYPT_HANDLE_NONE)
-    return CKR_OPERATION_NOT_INITIALIZED;
+    lose(CKR_OPERATION_NOT_INITIALIZED);
 
   if (pSignature == NULL) {
     /*
@@ -3421,14 +3775,17 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession,
 
  fail:
 
-  if (session->sign_digest_context != CRYPT_HANDLE_NONE)
+  if (session != NULL && session->sign_digest_context != CRYPT_HANDLE_NONE) {
     cryptDestroyContext(session->sign_digest_context);
-  session->sign_digest_context = CRYPT_HANDLE_NONE;
+    session->sign_digest_context = CRYPT_HANDLE_NONE;
+  }
 
-  cryptDestroyContext(session->sign_key_context);
-  session->sign_key_context = CRYPT_HANDLE_NONE;
+  if (session != NULL && session->sign_key_context != CRYPT_HANDLE_NONE) {
+    cryptDestroyContext(session->sign_key_context);
+    session->sign_key_context = CRYPT_HANDLE_NONE;
+  }
 
-  return rv;
+  return mutex_unlock_with_rv(rv, p11_global_mutex);
 }
 
 /*
@@ -3436,6 +3793,7 @@ CK_RV C_Sign(CK_SESSION_HANDLE hSession,
  * More general use presumably wants this for things like generating
  * symmetric keys for later wrapping by asymmetric keys.
  */
+
 CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession,
                     CK_MECHANISM_PTR pMechanism,
                     CK_ATTRIBUTE_PTR pTemplate,
@@ -3445,6 +3803,13 @@ CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession,
   return CKR_FUNCTION_NOT_SUPPORTED;
 }
 
+/*
+ * If there's any method in this entire package which really needs a
+ * more complex mutex structure than the single global mutex, it's
+ * probably this one.  Key generation can take a looooong time.
+ * Drive off that bridge when we get to it.
+ */
+
 CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession,
                         CK_MECHANISM_PTR pMechanism,
                         CK_ATTRIBUTE_PTR pPublicKeyTemplate,
@@ -3454,40 +3819,51 @@ CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession,
                         CK_OBJECT_HANDLE_PTR phPublicKey,
                         CK_OBJECT_HANDLE_PTR phPrivateKey)
 {
-  p11_session_t *session = p11_session_find(hSession);
+  p11_session_t *session;
+  CK_RV rv;
 
-  if (session == NULL)
-    return CKR_SESSION_HANDLE_INVALID;
+  mutex_lock_or_fail(p11_global_mutex);
+
+  if ((session = p11_session_find(hSession)) == NULL)
+    lose(CKR_SESSION_HANDLE_INVALID);
 
   if (pMechanism          == NULL ||
       pPublicKeyTemplate  == NULL || phPublicKey  == NULL ||
       pPrivateKeyTemplate == NULL || phPrivateKey == NULL)
-    return CKR_ARGUMENTS_BAD;
+    lose(CKR_ARGUMENTS_BAD);
 
   switch (pMechanism->mechanism) {
+
   case CKM_RSA_PKCS_KEY_PAIR_GEN:
-    return generate_keypair_rsa_pkcs(session, pMechanism,
-                                     pPublicKeyTemplate, ulPublicKeyAttributeCount,
-                                     pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
-                                     phPublicKey, phPrivateKey);
+    rv = generate_keypair_rsa_pkcs(session, pMechanism,
+                                   pPublicKeyTemplate, ulPublicKeyAttributeCount,
+                                   pPrivateKeyTemplate, ulPrivateKeyAttributeCount,
+                                   phPublicKey, phPrivateKey);
+    break;
+
   default:
-    return CKR_MECHANISM_INVALID;
+    lose(CKR_MECHANISM_INVALID);
   }
+
+ fail:
+  return mutex_unlock_with_rv(rv, p11_global_mutex);
 }
 
 CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession,
                        CK_BYTE_PTR RandomData,
                        CK_ULONG ulRandomLen)
 {
-  p11_session_t *session = p11_session_find(hSession);
+  p11_session_t *session;
   CRYPT_CONTEXT ctx = CRYPT_HANDLE_NONE;
   CK_RV rv = CKR_OK;
 
-  if (session == NULL)
-    return CKR_SESSION_HANDLE_INVALID;
+  mutex_lock_or_fail(p11_global_mutex);
+
+  if ((session = p11_session_find(hSession)) == NULL)
+    lose(CKR_SESSION_HANDLE_INVALID);
 
   if (RandomData == NULL)
-    return CKR_ARGUMENTS_BAD;
+    lose(CKR_ARGUMENTS_BAD);
 
   /*
    * Cryptlib doesn't expose the raw TRNG, but, per the manual, block
@@ -3508,7 +3884,7 @@ CK_RV C_GenerateRandom(CK_SESSION_HANDLE hSession,
   if (ctx != CRYPT_HANDLE_NONE)
     (void) cryptDestroyContext(ctx);
 
-  return rv;
+  return mutex_unlock_with_rv(rv, p11_global_mutex);
 }
 
 




More information about the Commits mailing list