* 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,
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
@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
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)
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"),
#include <random.h>
#ifndef HAVE_LIBNETTLE
#include <gcrypt.h>
-
#define GNUTLS_MIN_LIBGCRYPT_VERSION "1.2.4"
#endif
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
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:
*
{
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)
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
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 *);
#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
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;
#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,
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;
}
do_trivia_source( 0);
do_device_source( 0);
- yarrow256_random(&yctx, datasize, data);
+ yarrow256_random(&yctx, datasize, data);
RND_UNLOCK;
return 0;
}
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: