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/>.
26 #include <gnutls/gnutls.h>
28 #include "gtlsbackend-gnutls.h"
29 #include "gtlscertificate-gnutls.h"
30 #include "gtlsclientconnection-gnutls.h"
31 #include "gtlsfiledatabase-gnutls.h"
32 #include "gtlsserverconnection-gnutls.h"
34 struct _GTlsBackendGnutlsPrivate
37 GTlsDatabase *default_database;
40 static void gtls_gnutls_init (void);
41 static void g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface);
43 G_DEFINE_DYNAMIC_TYPE_EXTENDED (GTlsBackendGnutls, g_tls_backend_gnutls, G_TYPE_OBJECT, 0,
44 G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_TLS_BACKEND,
45 g_tls_backend_gnutls_interface_init);
49 #ifdef GTLS_GNUTLS_DEBUG
51 gtls_log_func (int level, const char *msg)
53 g_print ("GTLS: %s", msg);
58 gtls_gnutls_init (void)
60 gnutls_global_init ();
62 #ifdef GTLS_GNUTLS_DEBUG
63 gnutls_global_set_log_function (gtls_log_func);
64 gnutls_global_set_log_level (9);
66 /* Leak the module to keep it from being unloaded and breaking
67 * the pointer to gtls_log_func().
69 g_type_plugin_use (g_type_get_plugin (G_TYPE_TLS_BACKEND_GNUTLS));
74 g_tls_backend_gnutls_init (GTlsBackendGnutls *backend)
76 backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend, G_TYPE_TLS_BACKEND_GNUTLS, GTlsBackendGnutlsPrivate);
77 g_mutex_init (&backend->priv->mutex);
81 g_tls_backend_gnutls_finalize (GObject *object)
83 GTlsBackendGnutls *backend = G_TLS_BACKEND_GNUTLS (object);
85 if (backend->priv->default_database)
86 g_object_unref (backend->priv->default_database);
87 g_mutex_clear (&backend->priv->mutex);
89 G_OBJECT_CLASS (g_tls_backend_gnutls_parent_class)->finalize (object);
93 g_tls_backend_gnutls_real_create_database (GTlsBackendGnutls *self,
96 const gchar *anchor_file = NULL;
97 #ifdef GTLS_SYSTEM_CA_FILE
98 anchor_file = GTLS_SYSTEM_CA_FILE;
100 return g_tls_file_database_new (anchor_file, error);
104 g_tls_backend_gnutls_class_init (GTlsBackendGnutlsClass *backend_class)
106 GObjectClass *gobject_class = G_OBJECT_CLASS (backend_class);
107 gobject_class->finalize = g_tls_backend_gnutls_finalize;
108 backend_class->create_database = g_tls_backend_gnutls_real_create_database;
109 g_type_class_add_private (backend_class, sizeof (GTlsBackendGnutlsPrivate));
113 g_tls_backend_gnutls_class_finalize (GTlsBackendGnutlsClass *backend_class)
118 g_tls_backend_gnutls_get_default_database (GTlsBackend *backend)
120 GTlsBackendGnutls *self = G_TLS_BACKEND_GNUTLS (backend);
121 GTlsDatabase *result;
122 GError *error = NULL;
124 g_mutex_lock (&self->priv->mutex);
126 if (self->priv->default_database)
128 result = g_object_ref (self->priv->default_database);
132 g_assert (G_TLS_BACKEND_GNUTLS_GET_CLASS (self)->create_database);
133 result = G_TLS_BACKEND_GNUTLS_GET_CLASS (self)->create_database (self, &error);
136 g_warning ("couldn't load TLS file database: %s",
138 g_clear_error (&error);
143 self->priv->default_database = g_object_ref (result);
147 g_mutex_unlock (&self->priv->mutex);
153 g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface)
155 iface->get_certificate_type = g_tls_certificate_gnutls_get_type;
156 iface->get_client_connection_type = g_tls_client_connection_gnutls_get_type;
157 iface->get_server_connection_type = g_tls_server_connection_gnutls_get_type;
158 iface->get_file_database_type = g_tls_file_database_gnutls_get_type;
159 iface->get_default_database = g_tls_backend_gnutls_get_default_database;
162 /* Session cache support; all the details are sort of arbitrary. Note
163 * that having session_cache_cleanup() be a little bit slow isn't the
164 * end of the world, since it will still be faster than the network
165 * is. (NSS uses a linked list for its cache...)
168 G_LOCK_DEFINE_STATIC (session_cache_lock);
169 GHashTable *session_cache;
171 #define SESSION_CACHE_MAX_SIZE 50
172 #define SESSION_CACHE_MAX_AGE (60 * 60) /* one hour */
176 GByteArray *session_data;
178 } GTlsBackendGnutlsCacheData;
181 session_cache_cleanup (void)
185 GTlsBackendGnutlsCacheData *cache_data;
186 time_t expired = time (NULL) - SESSION_CACHE_MAX_AGE;
188 g_hash_table_iter_init (&iter, session_cache);
189 while (g_hash_table_iter_next (&iter, &key, &value))
192 if (cache_data->last_used < expired)
193 g_hash_table_iter_remove (&iter);
198 cache_data_free (gpointer data)
200 GTlsBackendGnutlsCacheData *cache_data = data;
202 g_free (cache_data->session_id);
203 g_byte_array_unref (cache_data->session_data);
204 g_slice_free (GTlsBackendGnutlsCacheData, cache_data);
208 g_tls_backend_gnutls_cache_session_data (const gchar *session_id,
209 guchar *session_data,
210 gsize session_data_length)
212 GTlsBackendGnutlsCacheData *cache_data;
214 G_LOCK (session_cache_lock);
217 session_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
218 NULL, cache_data_free);
220 cache_data = g_hash_table_lookup (session_cache, session_id);
223 if (cache_data->session_data->len == session_data_length &&
224 memcmp (cache_data->session_data->data,
225 session_data, session_data_length) == 0)
227 cache_data->last_used = time (NULL);
228 G_UNLOCK (session_cache_lock);
232 g_byte_array_set_size (cache_data->session_data, 0);
236 if (g_hash_table_size (session_cache) >= SESSION_CACHE_MAX_SIZE)
237 session_cache_cleanup ();
239 cache_data = g_slice_new (GTlsBackendGnutlsCacheData);
240 cache_data->session_id = g_strdup (session_id);
241 cache_data->session_data = g_byte_array_sized_new (session_data_length);
243 g_hash_table_insert (session_cache, cache_data->session_id, cache_data);
246 g_byte_array_append (cache_data->session_data,
247 session_data, session_data_length);
248 cache_data->last_used = time (NULL);
249 G_UNLOCK (session_cache_lock);
253 g_tls_backend_gnutls_uncache_session_data (const gchar *session_id)
255 G_LOCK (session_cache_lock);
257 g_hash_table_remove (session_cache, session_id);
258 G_UNLOCK (session_cache_lock);
262 g_tls_backend_gnutls_lookup_session_data (const gchar *session_id)
264 GTlsBackendGnutlsCacheData *cache_data;
265 GByteArray *session_data = NULL;
267 G_LOCK (session_cache_lock);
270 cache_data = g_hash_table_lookup (session_cache, session_id);
273 cache_data->last_used = time (NULL);
274 session_data = g_byte_array_ref (cache_data->session_data);
277 G_UNLOCK (session_cache_lock);
283 g_tls_backend_gnutls_register (GIOModule *module)
285 g_tls_backend_gnutls_register_type (G_TYPE_MODULE (module));
286 g_io_extension_point_implement (G_TLS_BACKEND_EXTENSION_POINT_NAME,
287 g_tls_backend_gnutls_get_type(),