From: Nikos Mavrogiannopoulos Date: Sun, 27 Jun 2010 17:22:07 +0000 (+0200) Subject: Added gnutls_global_set_mutex() to allow setting X-Git-Tag: gnutls_2_11_3~145 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fe1b3846c8c34a103da138e375f435f72fa042a6;p=thirdparty%2Fgnutls.git 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. As a side effect this change avoids any API dependance on libgcrypt even if threads are used. --- diff --git a/NEWS b/NEWS index 9fa54896c0..89fcf94c34 100644 --- 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 diff --git a/doc/cha-gtls-app.texi b/doc/cha-gtls-app.texi index a29a0924a5..515859d93f 100644 --- a/doc/cha-gtls-app.texi +++ b/doc/cha-gtls-app.texi @@ -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 -#include #include #include -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 -#include -#include -#include -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 diff --git a/lib/configure.ac b/lib/configure.ac index 55412c3ae7..97252b559e 100644 --- a/lib/configure.ac +++ b/lib/configure.ac @@ -82,6 +82,8 @@ fi lgl_INIT +AC_LIB_HAVE_LINKFLAGS(pthread,, [#include ], [pthread_mutex_lock (0);]) + LIBGNUTLS_LIBS="-L${libdir} -lgnutls $LIBS" LIBGNUTLS_CFLAGS="-I${includedir}" AC_SUBST(LIBGNUTLS_LIBS) diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c index 97d5386c22..9c71cd1e6d 100644 --- a/lib/gnutls_errors.c +++ b/lib/gnutls_errors.c @@ -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"), diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c index 69914e3091..bdbdc642bd 100644 --- a/lib/gnutls_global.c +++ b/lib/gnutls_global.c @@ -30,7 +30,6 @@ #include #ifndef HAVE_LIBNETTLE #include - #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 + +/* 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 + +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) diff --git a/lib/gnutls_global.h b/lib/gnutls_global.h index 081c20d464..e6bf08e408 100644 --- a/lib/gnutls_global.h +++ b/lib/gnutls_global.h @@ -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 diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 3c0889d0b1..bfd876a7e4 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -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 diff --git a/lib/libgnutls.map b/lib/libgnutls.map index cc93d6cd1f..47eed0cbcc 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -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; diff --git a/lib/nettle/rnd.c b/lib/nettle/rnd.c index 0a1066fe7d..2ae544fdf0 100644 --- a/lib/nettle/rnd.c +++ b/lib/nettle/rnd.c @@ -40,11 +40,10 @@ #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; } diff --git a/lib/pkcs11.c b/lib/pkcs11.c index ffb4c2116e..ebe4846d1b 100644 --- a/lib/pkcs11.c +++ b/lib/pkcs11.c @@ -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: