]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Added gnutls_global_set_mutex() to allow setting
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 27 Jun 2010 17:22:07 +0000 (19:22 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Sun, 27 Jun 2010 17:22:07 +0000 (19:22 +0200)
alternative locking procedures. By default the system available
locking is used. In *NIX pthreads are used and in windows the
critical section API.

As a side effect this change avoids any API dependance on libgcrypt
even if threads are used.

NEWS
doc/cha-gtls-app.texi
lib/configure.ac
lib/gnutls_errors.c
lib/gnutls_global.c
lib/gnutls_global.h
lib/includes/gnutls/gnutls.h.in
lib/libgnutls.map
lib/nettle/rnd.c
lib/pkcs11.c

diff --git a/NEWS b/NEWS
index 9fa54896c056d9a93e06037ea8f214dcd68c0a48..89fcf94c344d195309d6ad4e105d7b79725188ae 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,11 @@ See the end for copying conditions.
 
 * Version 2.11.0 (unreleased)
 
+** libgnutls: Added gnutls_global_set_mutex() to allow setting
+alternative locking procedures. By default the system available
+locking is used. In *NIX pthreads are used and in windows the
+critical section API.
+
 ** libgnutls: Added support for reading DN from EV-certificates.
 New DN values:
 jurisdictionOfIncorporationLocalityName,
@@ -62,6 +67,7 @@ pkcs11:token=Root%20CA%20Certificates;serial=1%3AROOTS%3ADEFAULT;model=1%2E0;man
 gnutls_certificate_set_server_retrieve_function: DEPRECATED
 gnutls_certificate_set_client_retrieve_function: DEPRECATED
 gnutls_sign_callback_set: DEPRECATED
+gnutls_global_set_mutex: ADDED
 gnutls_pubkey_get_preferred_hash_algorithm: ADDED
 gnutls_x509_crt_get_preferred_hash_algorithm: ADDED
 gnutls_x509_privkey_export_rsa_raw2: ADDED
index a29a0924a582ee8f1e7c18ca327ad951ebb7682b..515859d93fe5febf84763e66a215477d67753440 100644 (file)
@@ -126,57 +126,39 @@ gcc -o foo foo.c `pkg-config gnutls --cflags --libs`
 @section Multi-Threaded Applications
 
 Although the @acronym{GnuTLS} library is thread safe by design, some
-parts of Libgcrypt, such as the random generator, are not.
-Applications have to register callback functions to ensure proper
-locking in the sensitive parts of @emph{libgcrypt}.
+parts of the cryptographic backend, such as the random generator, are not.
+Applications can either call @ref{gnutls_global_init} and use the default 
+operating system provided locks (i.e. @code{pthreads} on GNU/Linux), or
+specify manualy the locking system using the function @ref{gnutls_global_set_mutex}
+before calling @ref{gnutls_global_init}. Setting manually mutexes is recommended
+only to applications that have full control of the underlying libraries. If this
+is not the case, the use of the operating system defaults is recommended.
+
 
 There are helper macros to help you properly initialize the libraries.
 Examples are shown below.
 
 @itemize
 
-@item POSIX threads
+@item POSIX threads in GNU/Linux
 @example
 #include <gnutls.h>
-#include <gcrypt.h>
 #include <errno.h>
 #include <pthread.h>
-GCRY_THREAD_OPTION_PTHREAD_IMPL;
-
-int main()
-@{
-   /* The order matters.
-    */
-   gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
-   gnutls_global_init();
-@}
-@end example
-
-@item GNU PTH threads
-@example
-#include <gnutls.h>
-#include <gcrypt.h>
-#include <errno.h>
-#include <pth.h>
-GCRY_THREAD_OPTION_PTH_IMPL;
 
 int main()
 @{
-   gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
    gnutls_global_init();
 @}
 @end example
 
 @item Other thread packages
 @example
-/* The gcry_thread_cbs structure must have been
- * initialized.
- */
-static struct gcry_thread_cbs gcry_threads_other = @{ ... @};
 
 int main()
 @{
-   gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_other);
+   gnutls_global_mutex_set (mutex_init, mutex_deinit, mutex_lock, mutex_unlock);
+   gnutls_global_init();
 @}
 @end example
 @end itemize
index 55412c3ae7f83e217a9fc3eadaf80d65feae3e79..97252b559e886001c9daec9b3fa133f5c6110c7f 100644 (file)
@@ -82,6 +82,8 @@ fi
 
 lgl_INIT
 
+AC_LIB_HAVE_LINKFLAGS(pthread,, [#include <pthread.h>], [pthread_mutex_lock (0);])
+
 LIBGNUTLS_LIBS="-L${libdir} -lgnutls $LIBS"
 LIBGNUTLS_CFLAGS="-I${includedir}"
 AC_SUBST(LIBGNUTLS_LIBS)
index 97d5386c22bf3b3ffc55af79ea26fe6f119c0fdd..9c71cd1e6d4e27c0242dd25c4ec5eb98ba1fc296 100644 (file)
@@ -288,8 +288,8 @@ static const gnutls_error_entry error_algorithms[] = {
               GNUTLS_E_PKCS11_ERROR, 1),
   ERROR_ENTRY (N_("PKCS #11 error in slot"),
        GNUTLS_E_PKCS11_SLOT_ERROR, 1),
-  ERROR_ENTRY (N_("PKCS #11 locking error"),
-       GNUTLS_E_PKCS11_LOCKING_ERROR, 1),
+  ERROR_ENTRY (N_("Thread locking error"),
+       GNUTLS_E_LOCKING_ERROR, 1),
   ERROR_ENTRY (N_("PKCS #11 error in attribute"),
     GNUTLS_E_PKCS11_ATTRIBUTE_ERROR, 1),
   ERROR_ENTRY (N_("PKCS #11 error in device"),
index 69914e30916287f43a74aac4eff0bd75e1aa1c69..bdbdc642bdff1dfe651f6b6159d2f9474904b73c 100644 (file)
@@ -30,7 +30,6 @@
 #include <random.h>
 #ifndef HAVE_LIBNETTLE
 #include <gcrypt.h>
-
 #define GNUTLS_MIN_LIBGCRYPT_VERSION "1.2.4"
 
 #endif
@@ -55,6 +54,139 @@ ASN1_TYPE _gnutls_gnutls_asn;
 gnutls_log_func _gnutls_log_func;
 int _gnutls_log_level = 0;     /* default log level */
 
+#ifdef _WIN32
+
+# include <windows.h>
+
+/* FIXME: win32 locks are untested */
+static int gnutls_system_mutex_init (void **priv)
+{
+  CRITICAL_SECTION *lock = malloc (sizeof (CRITICAL_SECTION));
+  int ret;
+
+  if (lock==NULL)
+    return GNUTLS_E_MEMORY_ERROR;
+
+  InitializeCriticalSection(lock);
+     
+  *priv = lock;
+  
+  return 0;
+}
+
+static void gnutls_system_mutex_deinit (void *priv)
+{
+  DeleteCriticalSection(priv);
+  free(priv);
+}
+
+static int gnutls_system_mutex_lock (void *priv)
+{
+  EnterCriticalSection(priv);
+  return 0;
+}
+
+static int gnutls_system_mutex_unlock (void *priv)
+{
+  LeaveCriticalSection(priv);
+  return 0;
+}
+
+#else
+
+# ifdef HAVE_LIBPTHREAD
+#  include <pthread.h>
+
+static int gnutls_system_mutex_init (void **priv)
+{
+  pthread_mutex_t *lock = malloc (sizeof (pthread_mutex_t));
+  int ret;
+
+  if (lock==NULL)
+    return GNUTLS_E_MEMORY_ERROR;
+
+   ret = pthread_mutex_init (lock, NULL);
+   if (ret)
+     {
+       free(lock);
+       gnutls_assert();
+       return GNUTLS_E_LOCKING_ERROR;
+     }
+     
+  *priv = lock;
+  
+  return 0;
+}
+
+static void gnutls_system_mutex_deinit (void *priv)
+{
+  pthread_mutex_destroy(priv);
+  free(priv);
+}
+
+static int gnutls_system_mutex_lock (void *priv)
+{
+  if (pthread_mutex_lock(priv))
+    {
+        gnutls_assert();
+        return GNUTLS_E_LOCKING_ERROR;
+    }
+
+  return 0;
+}
+
+static int gnutls_system_mutex_unlock (void *priv)
+{
+  if (pthread_mutex_unlock(priv))
+    {
+        gnutls_assert();
+        return GNUTLS_E_LOCKING_ERROR;
+    }
+
+  return 0;
+}
+
+# else
+
+#define gnutls_system_mutex_init NULL
+#define gnutls_system_mutex_deinit NULL
+#define gnutls_system_mutex_lock NULL
+#define gnutls_mutex_unlock NULL
+
+# endif /* PTHREAD */
+
+#endif
+
+mutex_init_func gnutls_mutex_init = gnutls_system_mutex_init;
+mutex_deinit_func gnutls_mutex_deinit = gnutls_system_mutex_deinit;
+mutex_lock_func gnutls_mutex_lock = gnutls_system_mutex_lock;
+mutex_unlock_func gnutls_mutex_unlock = gnutls_system_mutex_unlock;
+
+/**
+ * gnutls_global_set_mutex:
+ * @init: mutex initialization function
+ * @deinit: mutex deinitialization function
+ * @lock: mutex locking function
+ * @unlock: mutex unlocking function
+ *
+ * With this function you are allowed to override the default mutex
+ * locks used in some parts of gnutls and dependent libraries. This function
+ * should be used if you have complete control of your program and libraries.
+ * Do not call this function from a library. Instead only initialize gnutls and
+ * the default OS mutex locks will be used.
+ * 
+ * This function must be called before gnutls_global_init().
+ *
+ **/
+void gnutls_global_set_mutex(mutex_init_func init, mutex_deinit_func deinit, 
+        mutex_lock_func lock, mutex_unlock_func unlock)
+{
+  gnutls_mutex_init = init;
+  gnutls_mutex_deinit = deinit;
+  gnutls_mutex_lock = lock;
+  gnutls_mutex_unlock = unlock;
+}
+
 /**
  * gnutls_global_set_log_function:
  * @log_func: it's a log function
@@ -142,6 +274,36 @@ gnutls_global_set_mem_functions (gnutls_alloc_function alloc_func,
 
 static int _gnutls_init = 0;
 
+#ifndef HAVE_LIBNETTLE
+static struct gcry_thread_cbs gct = {
+  .option = (GCRY_THREAD_OPTION_PTH | (GCRY_THREAD_OPTION_VERSION << 8)),
+  .init = NULL,
+  .select = NULL,
+  .waitpid = NULL,
+  .accept = NULL,
+  .connect = NULL,
+  .sendmsg = NULL,
+  .recvmsg = NULL,
+};
+
+static int wrap_gcry_mutex_lock(void** m)
+{
+  return gnutls_mutex_lock(*m);
+}
+
+static int wrap_gcry_mutex_unlock(void** m)
+{
+  return gnutls_mutex_unlock(*m);
+}
+
+static int wrap_gcry_mutex_deinit(void** m)
+{
+  gnutls_mutex_deinit(*m);
+  return 0;
+}
+
+#endif
+
 /**
  * gnutls_global_init:
  *
@@ -194,6 +356,16 @@ gnutls_global_init (void)
     {
       const char *p;
 
+      if (gnutls_mutex_init != NULL)
+        {
+          gct.mutex_init = gnutls_mutex_init;
+          gct.mutex_destroy = wrap_gcry_mutex_deinit;
+          gct.mutex_lock = wrap_gcry_mutex_lock;
+          gct.mutex_unlock = wrap_gcry_mutex_unlock;
+
+          gcry_control (GCRYCTL_SET_THREAD_CBS, &gct);
+        }
+
       p = gcry_check_version (GNUTLS_MIN_LIBGCRYPT_VERSION);
 
       if (p == NULL)
index 081c20d464a8d74df1fae0121af54fcb44559cec..e6bf08e408fa28bc6fcff2c451a9611f389bfc20 100644 (file)
@@ -43,4 +43,9 @@ extern ASN1_TYPE _gnutls_gnutls_asn;
 extern gnutls_log_func _gnutls_log_func;
 extern int _gnutls_log_level;
 
+extern mutex_init_func gnutls_mutex_init;
+extern mutex_deinit_func gnutls_mutex_deinit;
+extern mutex_lock_func gnutls_mutex_lock;
+extern mutex_unlock_func gnutls_mutex_unlock;
+
 #endif
index 3c0889d0b18833e6961551ba9f4653cc282cb9b0..bfd876a7e4916b22236d5d34891ca2c700a1ef5e 100644 (file)
@@ -1122,6 +1122,14 @@ extern "C"
   int gnutls_global_init (void);
   void gnutls_global_deinit (void);
 
+  typedef int (*mutex_init_func)(void** mutex);
+  typedef int (*mutex_lock_func)(void* mutex);
+  typedef int (*mutex_unlock_func)(void* mutex);
+  typedef void (*mutex_deinit_func)(void* mutex);
+  
+  void gnutls_global_set_mutex(mutex_init_func init, mutex_deinit_func, 
+    mutex_lock_func, mutex_unlock_func);
+
   typedef void *(*gnutls_alloc_function) (size_t);
   typedef void *(*gnutls_calloc_function) (size_t, size_t);
   typedef int (*gnutls_is_secure_function) (const void *);
@@ -1739,7 +1747,7 @@ extern "C"
 #define GNUTLS_E_PKCS11_PIN_SAVE -304
 
 #define GNUTLS_E_PKCS11_SLOT_ERROR -305
-#define GNUTLS_E_PKCS11_LOCKING_ERROR -306
+#define GNUTLS_E_LOCKING_ERROR -306
 #define GNUTLS_E_PKCS11_ATTRIBUTE_ERROR -307
 #define GNUTLS_E_PKCS11_DEVICE_ERROR -308
 #define GNUTLS_E_PKCS11_DATA_ERROR -309
index cc93d6cd1f7200e33bb790e2748f46287d90390b..47eed0cbcc3b7a374d6098e685d3ecb0c9d9d108 100644 (file)
@@ -674,6 +674,7 @@ GNUTLS_2_11
        gnutls_x509_privkey_export_rsa_raw2;
        gnutls_pubkey_get_preferred_hash_algorithm;
        gnutls_x509_crt_get_preferred_hash_algorithm;
+       gnutls_global_set_mutex;
 
        gnutls_sec_param_to_pk_bits;
        gnutls_sec_param_get_name;
index 0a1066fe7ddf7dc4ae9ddf2929986903d17f6efb..2ae544fdf090a0eb9a098888e1102afea6f6af88 100644 (file)
 
 #define SOURCES 2
 
-static pthread_mutex_t rnd_mutex = PTHREAD_MUTEX_INITIALIZER;
+static void* rnd_mutex;
 
-#define RND_LOCK_INIT
-#define RND_LOCK if (pthread_mutex_lock(&rnd_mutex)!=0) abort()
-#define RND_UNLOCK if (pthread_mutex_unlock(&rnd_mutex)!=0) abort()
+#define RND_LOCK if (gnutls_mutex_lock && gnutls_mutex_lock(&rnd_mutex)!=0) abort()
+#define RND_UNLOCK if (gnutls_mutex_unlock && gnutls_mutex_unlock(&rnd_mutex)!=0) abort()
 
 enum {
        RANDOM_SOURCE_TRIVIA=0,
@@ -176,15 +175,25 @@ static void wrap_nettle_rnd_deinit(void* ctx)
 
 static int wrap_nettle_rnd_init(void **ctx)
 {
-       RND_LOCK_INIT;
-       
-    yarrow256_init(&yctx, SOURCES, ysources);
+int ret;
+
+       if (gnutls_mutex_init)
+         {
+           ret = gnutls_mutex_init(&rnd_mutex);
+           if (ret < 0)
+             {
+               gnutls_assert();
+               return ret;
+             }
+         }
+
+       yarrow256_init(&yctx, SOURCES, ysources);
        do_device_source(1);
        do_trivia_source(1);
 
        yarrow256_slow_reseed(&yctx);
 
-    return 0;
+       return 0;
 }
 
 
@@ -196,7 +205,7 @@ wrap_nettle_rnd(void *_ctx, int level, void *data, size_t datasize)
        do_trivia_source( 0);
        do_device_source( 0);
 
-    yarrow256_random(&yctx, datasize, data);
+       yarrow256_random(&yctx, datasize, data);
        RND_UNLOCK;
        return 0;
 }
index ffb4c2116e01e8aa4d07842611e4508c2e548364..ebe4846d1b37a49e89c4f747a739335106087923 100644 (file)
@@ -86,7 +86,7 @@ int pkcs11_rv_to_err(ck_rv_t rv)
         case CKR_FUNCTION_NOT_PARALLEL:
         case CKR_MUTEX_BAD:
         case CKR_MUTEX_NOT_LOCKED:
-            return GNUTLS_E_PKCS11_LOCKING_ERROR;
+            return GNUTLS_E_LOCKING_ERROR;
         case CKR_ATTRIBUTE_READ_ONLY:
         case CKR_ATTRIBUTE_SENSITIVE:
         case CKR_ATTRIBUTE_TYPE_INVALID: