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, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
26 #include <gnutls/gnutls.h>
32 #include "gtlsbackend-gnutls.h"
33 #include "gtlscertificate-gnutls.h"
34 #include "gtlsclientconnection-gnutls.h"
35 #include "gtlsserverconnection-gnutls.h"
37 static void g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface);
39 G_DEFINE_DYNAMIC_TYPE_EXTENDED (GTlsBackendGnutls, g_tls_backend_gnutls, G_TYPE_OBJECT, 0,
40 G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_TLS_BACKEND,
41 g_tls_backend_gnutls_interface_init);)
43 #if defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) && !defined(G_OS_WIN32)
44 GCRY_THREAD_OPTION_PTHREAD_IMPL;
50 gtls_gcry_win32_mutex_init (void **priv)
53 CRITICAL_SECTION *lock = (CRITICAL_SECTION*)malloc (sizeof (CRITICAL_SECTION));
58 InitializeCriticalSection (lock);
65 gtls_gcry_win32_mutex_destroy (void **lock)
67 DeleteCriticalSection ((CRITICAL_SECTION*)*lock);
73 gtls_gcry_win32_mutex_lock (void **lock)
75 EnterCriticalSection ((CRITICAL_SECTION*)*lock);
80 gtls_gcry_win32_mutex_unlock (void **lock)
82 LeaveCriticalSection ((CRITICAL_SECTION*)*lock);
87 static struct gcry_thread_cbs gtls_gcry_threads_win32 = { \
88 (GCRY_THREAD_OPTION_USER | (GCRY_THREAD_OPTION_VERSION << 8)), \
89 NULL, gtls_gcry_win32_mutex_init, gtls_gcry_win32_mutex_destroy, \
90 gtls_gcry_win32_mutex_lock, gtls_gcry_win32_mutex_unlock, \
91 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
96 gtls_gnutls_init (gpointer data)
98 #if defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) && !defined(G_OS_WIN32)
99 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
100 #elif defined(G_OS_WIN32)
101 gcry_control (GCRYCTL_SET_THREAD_CBS, >ls_gcry_threads_win32);
103 gnutls_global_init ();
105 /* Leak the module to keep it from being unloaded. */
106 g_type_plugin_use (g_type_get_plugin (G_TYPE_TLS_BACKEND_GNUTLS));
110 static GOnce gnutls_inited = G_ONCE_INIT;
113 g_tls_backend_gnutls_init (GTlsBackendGnutls *backend)
115 /* Once we call gtls_gnutls_init(), we can't allow the module to be
116 * unloaded, since that would break the pointers to the mutex
117 * functions we set for gcrypt. So we initialize it from here rather
118 * than at class init time so that it doesn't happen unless the app
119 * is actually using TLS (as opposed to just calling
120 * g_io_modules_scan_all_in_directory()).
122 g_once (&gnutls_inited, gtls_gnutls_init, NULL);
126 g_tls_backend_gnutls_class_init (GTlsBackendGnutlsClass *backend_class)
131 g_tls_backend_gnutls_class_finalize (GTlsBackendGnutlsClass *backend_class)
136 g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface)
138 iface->get_certificate_type = g_tls_certificate_gnutls_get_type;
139 iface->get_client_connection_type = g_tls_client_connection_gnutls_get_type;
140 iface->get_server_connection_type = g_tls_server_connection_gnutls_get_type;
143 #ifdef GTLS_SYSTEM_CA_FILE
144 /* Parsing the system CA list takes a noticeable amount of time.
145 * So we only do it once, and only when we actually need to see it.
148 get_ca_lists (gnutls_x509_crt_t **cas,
151 static gnutls_x509_crt_t *ca_list_gnutls;
152 static int ca_list_length;
153 static GList *ca_list;
155 if (g_once_init_enter ((volatile gsize *)&ca_list_gnutls))
157 GError *error = NULL;
158 gnutls_x509_crt_t *x509_crts;
162 ca_list = g_tls_certificate_list_new_from_file (GTLS_SYSTEM_CA_FILE, &error);
165 g_warning ("Failed to read system CA file %s: %s.",
166 GTLS_SYSTEM_CA_FILE, error->message);
167 g_error_free (error);
168 /* Note that this is not a security problem, since if
169 * G_TLS_VALIDATE_CA is set, then this just means validation
170 * will always fail, and if it isn't set, then it doesn't
171 * matter that we couldn't read the CAs.
175 ca_list_length = g_list_length (ca_list);
176 x509_crts = g_new (gnutls_x509_crt_t, ca_list_length);
177 for (c = ca_list, i = 0; c; c = c->next, i++)
178 x509_crts[i] = g_tls_certificate_gnutls_get_cert (c->data);
180 g_once_init_leave ((volatile gsize *)&ca_list_gnutls, GPOINTER_TO_SIZE (x509_crts));
184 *cas = ca_list_gnutls;
186 *num_cas = ca_list_length;
193 g_tls_backend_gnutls_get_system_ca_list_gtls (void)
195 #ifdef GTLS_SYSTEM_CA_FILE
196 return get_ca_lists (NULL, NULL);
203 g_tls_backend_gnutls_get_system_ca_list_gnutls (gnutls_x509_crt_t **cas,
206 #ifdef GTLS_SYSTEM_CA_FILE
207 get_ca_lists (cas, num_cas);
214 /* Session cache support; all the details are sort of arbitrary. Note
215 * that having session_cache_cleanup() be a little bit slow isn't the
216 * end of the world, since it will still be faster than the network
217 * is. (NSS uses a linked list for its cache...)
220 G_LOCK_DEFINE_STATIC (session_cache_lock);
221 GHashTable *session_cache;
223 #define SESSION_CACHE_MAX_SIZE 50
224 #define SESSION_CACHE_MAX_AGE (60 * 60) /* one hour */
228 GByteArray *session_data;
230 } GTlsBackendGnutlsCacheData;
233 session_cache_cleanup (void)
237 GTlsBackendGnutlsCacheData *cache_data;
238 time_t expired = time (NULL) - SESSION_CACHE_MAX_AGE;
240 g_hash_table_iter_init (&iter, session_cache);
241 while (g_hash_table_iter_next (&iter, &key, &value))
244 if (cache_data->last_used < expired)
245 g_hash_table_iter_remove (&iter);
250 cache_data_free (gpointer data)
252 GTlsBackendGnutlsCacheData *cache_data = data;
254 g_free (cache_data->session_id);
255 g_byte_array_unref (cache_data->session_data);
256 g_slice_free (GTlsBackendGnutlsCacheData, cache_data);
260 g_tls_backend_gnutls_cache_session_data (const gchar *session_id,
261 guchar *session_data,
262 gsize session_data_length)
264 GTlsBackendGnutlsCacheData *cache_data;
266 G_LOCK (session_cache_lock);
269 session_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
270 NULL, cache_data_free);
272 cache_data = g_hash_table_lookup (session_cache, session_id);
275 if (cache_data->session_data->len == session_data_length &&
276 memcmp (cache_data->session_data->data,
277 session_data, session_data_length) == 0)
279 cache_data->last_used = time (NULL);
280 G_UNLOCK (session_cache_lock);
284 g_byte_array_set_size (cache_data->session_data, 0);
288 if (g_hash_table_size (session_cache) >= SESSION_CACHE_MAX_SIZE)
289 session_cache_cleanup ();
291 cache_data = g_slice_new (GTlsBackendGnutlsCacheData);
292 cache_data->session_id = g_strdup (session_id);
293 cache_data->session_data = g_byte_array_sized_new (session_data_length);
295 g_hash_table_insert (session_cache, cache_data->session_id, cache_data);
298 g_byte_array_append (cache_data->session_data,
299 session_data, session_data_length);
300 cache_data->last_used = time (NULL);
301 G_UNLOCK (session_cache_lock);
305 g_tls_backend_gnutls_uncache_session_data (const gchar *session_id)
307 G_LOCK (session_cache_lock);
309 g_hash_table_remove (session_cache, session_id);
310 G_UNLOCK (session_cache_lock);
314 g_tls_backend_gnutls_lookup_session_data (const gchar *session_id)
316 GTlsBackendGnutlsCacheData *cache_data;
317 GByteArray *session_data = NULL;
319 G_LOCK (session_cache_lock);
322 cache_data = g_hash_table_lookup (session_cache, session_id);
325 cache_data->last_used = time (NULL);
326 session_data = g_byte_array_ref (cache_data->session_data);
329 G_UNLOCK (session_cache_lock);
335 g_tls_backend_gnutls_register (GIOModule *module)
337 g_tls_backend_gnutls_register_type (G_TYPE_MODULE (module));
338 g_io_extension_point_implement (G_TLS_BACKEND_EXTENSION_POINT_NAME,
339 g_tls_backend_gnutls_get_type(),