1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright 2010 Red Hat, Inc
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see
17 * <http://www.gnu.org/licenses/>.
25 #include <gnutls/gnutls.h>
31 #include "gtlsbackend-gnutls.h"
32 #include "gtlscertificate-gnutls.h"
33 #include "gtlsclientconnection-gnutls.h"
34 #include "gtlsfiledatabase-gnutls.h"
35 #include "gtlsserverconnection-gnutls.h"
37 struct _GTlsBackendGnutlsPrivate
40 GTlsDatabase *default_database;
43 static void g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface);
45 G_DEFINE_DYNAMIC_TYPE_EXTENDED (GTlsBackendGnutls, g_tls_backend_gnutls, G_TYPE_OBJECT, 0,
46 G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_TLS_BACKEND,
47 g_tls_backend_gnutls_interface_init);)
49 #if defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) && !defined(G_OS_WIN32)
50 GCRY_THREAD_OPTION_PTHREAD_IMPL;
56 gtls_gcry_win32_mutex_init (void **priv)
59 CRITICAL_SECTION *lock = (CRITICAL_SECTION*)malloc (sizeof (CRITICAL_SECTION));
64 InitializeCriticalSection (lock);
71 gtls_gcry_win32_mutex_destroy (void **lock)
73 DeleteCriticalSection ((CRITICAL_SECTION*)*lock);
79 gtls_gcry_win32_mutex_lock (void **lock)
81 EnterCriticalSection ((CRITICAL_SECTION*)*lock);
86 gtls_gcry_win32_mutex_unlock (void **lock)
88 LeaveCriticalSection ((CRITICAL_SECTION*)*lock);
93 static struct gcry_thread_cbs gtls_gcry_threads_win32 = { \
94 (GCRY_THREAD_OPTION_USER | (GCRY_THREAD_OPTION_VERSION << 8)), \
95 NULL, gtls_gcry_win32_mutex_init, gtls_gcry_win32_mutex_destroy, \
96 gtls_gcry_win32_mutex_lock, gtls_gcry_win32_mutex_unlock, \
97 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
101 #ifdef GTLS_GNUTLS_DEBUG
103 gtls_log_func (int level, const char *msg)
105 g_print ("GTLS: %s", msg);
110 gtls_gnutls_init (gpointer data)
112 #if defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) && !defined(G_OS_WIN32)
113 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
114 #elif defined(G_OS_WIN32)
115 gcry_control (GCRYCTL_SET_THREAD_CBS, >ls_gcry_threads_win32);
117 gnutls_global_init ();
119 #ifdef GTLS_GNUTLS_DEBUG
120 gnutls_global_set_log_function (gtls_log_func);
121 gnutls_global_set_log_level (9);
124 /* Leak the module to keep it from being unloaded. */
125 g_type_plugin_use (g_type_get_plugin (G_TYPE_TLS_BACKEND_GNUTLS));
129 static GOnce gnutls_inited = G_ONCE_INIT;
132 g_tls_backend_gnutls_init (GTlsBackendGnutls *backend)
134 /* Once we call gtls_gnutls_init(), we can't allow the module to be
135 * unloaded, since that would break the pointers to the mutex
136 * functions we set for gcrypt. So we initialize it from here rather
137 * than at class init time so that it doesn't happen unless the app
138 * is actually using TLS (as opposed to just calling
139 * g_io_modules_scan_all_in_directory()).
141 g_once (&gnutls_inited, gtls_gnutls_init, NULL);
143 backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend, G_TYPE_TLS_BACKEND_GNUTLS, GTlsBackendGnutlsPrivate);
144 backend->priv->mutex = g_mutex_new ();
148 g_tls_backend_gnutls_finalize (GObject *object)
150 GTlsBackendGnutls *backend = G_TLS_BACKEND_GNUTLS (object);
152 if (backend->priv->default_database)
153 g_object_unref (backend->priv->default_database);
154 g_mutex_free (backend->priv->mutex);
156 G_OBJECT_CLASS (g_tls_backend_gnutls_parent_class)->finalize (object);
160 g_tls_backend_gnutls_class_init (GTlsBackendGnutlsClass *backend_class)
162 GObjectClass *gobject_class = G_OBJECT_CLASS (backend_class);
163 gobject_class->finalize = g_tls_backend_gnutls_finalize;
164 g_type_class_add_private (backend_class, sizeof (GTlsBackendGnutlsPrivate));
168 g_tls_backend_gnutls_class_finalize (GTlsBackendGnutlsClass *backend_class)
173 g_tls_backend_gnutls_get_default_database (GTlsBackend *backend)
175 GTlsBackendGnutls *self = G_TLS_BACKEND_GNUTLS (backend);
176 const gchar *anchor_file = NULL;
177 GTlsDatabase *result;
178 GError *error = NULL;
180 g_mutex_lock (self->priv->mutex);
182 if (self->priv->default_database)
184 result = g_object_ref (self->priv->default_database);
188 #ifdef GTLS_SYSTEM_CA_FILE
189 anchor_file = GTLS_SYSTEM_CA_FILE;
191 result = g_tls_file_database_new (anchor_file, &error);
194 g_warning ("couldn't load TLS file database: %s",
196 g_clear_error (&error);
200 self->priv->default_database = g_object_ref (result);
204 g_mutex_unlock (self->priv->mutex);
210 g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface)
212 iface->get_certificate_type = g_tls_certificate_gnutls_get_type;
213 iface->get_client_connection_type = g_tls_client_connection_gnutls_get_type;
214 iface->get_server_connection_type = g_tls_server_connection_gnutls_get_type;
215 iface->get_file_database_type = g_tls_file_database_gnutls_get_type;
216 iface->get_default_database = g_tls_backend_gnutls_get_default_database;
219 /* Session cache support; all the details are sort of arbitrary. Note
220 * that having session_cache_cleanup() be a little bit slow isn't the
221 * end of the world, since it will still be faster than the network
222 * is. (NSS uses a linked list for its cache...)
225 G_LOCK_DEFINE_STATIC (session_cache_lock);
226 GHashTable *session_cache;
228 #define SESSION_CACHE_MAX_SIZE 50
229 #define SESSION_CACHE_MAX_AGE (60 * 60) /* one hour */
233 GByteArray *session_data;
235 } GTlsBackendGnutlsCacheData;
238 session_cache_cleanup (void)
242 GTlsBackendGnutlsCacheData *cache_data;
243 time_t expired = time (NULL) - SESSION_CACHE_MAX_AGE;
245 g_hash_table_iter_init (&iter, session_cache);
246 while (g_hash_table_iter_next (&iter, &key, &value))
249 if (cache_data->last_used < expired)
250 g_hash_table_iter_remove (&iter);
255 cache_data_free (gpointer data)
257 GTlsBackendGnutlsCacheData *cache_data = data;
259 g_free (cache_data->session_id);
260 g_byte_array_unref (cache_data->session_data);
261 g_slice_free (GTlsBackendGnutlsCacheData, cache_data);
265 g_tls_backend_gnutls_cache_session_data (const gchar *session_id,
266 guchar *session_data,
267 gsize session_data_length)
269 GTlsBackendGnutlsCacheData *cache_data;
271 G_LOCK (session_cache_lock);
274 session_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
275 NULL, cache_data_free);
277 cache_data = g_hash_table_lookup (session_cache, session_id);
280 if (cache_data->session_data->len == session_data_length &&
281 memcmp (cache_data->session_data->data,
282 session_data, session_data_length) == 0)
284 cache_data->last_used = time (NULL);
285 G_UNLOCK (session_cache_lock);
289 g_byte_array_set_size (cache_data->session_data, 0);
293 if (g_hash_table_size (session_cache) >= SESSION_CACHE_MAX_SIZE)
294 session_cache_cleanup ();
296 cache_data = g_slice_new (GTlsBackendGnutlsCacheData);
297 cache_data->session_id = g_strdup (session_id);
298 cache_data->session_data = g_byte_array_sized_new (session_data_length);
300 g_hash_table_insert (session_cache, cache_data->session_id, cache_data);
303 g_byte_array_append (cache_data->session_data,
304 session_data, session_data_length);
305 cache_data->last_used = time (NULL);
306 G_UNLOCK (session_cache_lock);
310 g_tls_backend_gnutls_uncache_session_data (const gchar *session_id)
312 G_LOCK (session_cache_lock);
314 g_hash_table_remove (session_cache, session_id);
315 G_UNLOCK (session_cache_lock);
319 g_tls_backend_gnutls_lookup_session_data (const gchar *session_id)
321 GTlsBackendGnutlsCacheData *cache_data;
322 GByteArray *session_data = NULL;
324 G_LOCK (session_cache_lock);
327 cache_data = g_hash_table_lookup (session_cache, session_id);
330 cache_data->last_used = time (NULL);
331 session_data = g_byte_array_ref (cache_data->session_data);
334 G_UNLOCK (session_cache_lock);
340 g_tls_backend_gnutls_register (GIOModule *module)
342 g_tls_backend_gnutls_register_type (G_TYPE_MODULE (module));
343 g_io_extension_point_implement (G_TLS_BACKEND_EXTENSION_POINT_NAME,
344 g_tls_backend_gnutls_get_type(),