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/>.
19 * In addition, when the library is used with OpenSSL, a special
20 * exception applies. Refer to the LICENSE_EXCEPTION file for details.
29 #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"
39 struct _GTlsBackendGnutlsPrivate
42 GTlsDatabase *default_database;
45 static void g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface);
47 G_DEFINE_DYNAMIC_TYPE_EXTENDED (GTlsBackendGnutls, g_tls_backend_gnutls, G_TYPE_OBJECT, 0,
48 G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_TLS_BACKEND,
49 g_tls_backend_gnutls_interface_init);)
51 #ifdef GTLS_GNUTLS_DEBUG
53 gtls_log_func (int level, const char *msg)
55 #if ENABLE(TIZEN_DLOG)
56 TIZEN_LOGI("GTLS: %s", msg);
58 g_print ("GTLS: %s", msg);
64 gtls_gnutls_init (gpointer data)
66 gnutls_global_init ();
68 #ifdef GTLS_GNUTLS_DEBUG
69 gnutls_global_set_log_function (gtls_log_func);
70 gnutls_global_set_log_level (9);
73 /* Leak the module to keep it from being unloaded. */
74 g_type_plugin_use (g_type_get_plugin (G_TYPE_TLS_BACKEND_GNUTLS));
78 static GOnce gnutls_inited = G_ONCE_INIT;
81 g_tls_backend_gnutls_init (GTlsBackendGnutls *backend)
83 /* Once we call gtls_gnutls_init(), we can't allow the module to be
84 * unloaded (since if gnutls gets unloaded but gcrypt doesn't, then
85 * gcrypt will have dangling pointers to gnutls's mutex functions).
86 * So we initialize it from here rather than at class init time so
87 * that it doesn't happen unless the app is actually using TLS (as
88 * opposed to just calling g_io_modules_scan_all_in_directory()).
90 g_once (&gnutls_inited, gtls_gnutls_init, NULL);
92 backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (backend, G_TYPE_TLS_BACKEND_GNUTLS, GTlsBackendGnutlsPrivate);
93 g_mutex_init (&backend->priv->mutex);
97 g_tls_backend_gnutls_finalize (GObject *object)
99 GTlsBackendGnutls *backend = G_TLS_BACKEND_GNUTLS (object);
101 if (backend->priv->default_database)
102 g_object_unref (backend->priv->default_database);
103 g_mutex_clear (&backend->priv->mutex);
105 G_OBJECT_CLASS (g_tls_backend_gnutls_parent_class)->finalize (object);
109 g_tls_backend_gnutls_real_create_database (GTlsBackendGnutls *self,
112 const gchar *anchor_file = NULL;
113 #ifdef GTLS_SYSTEM_CA_FILE
114 anchor_file = GTLS_SYSTEM_CA_FILE;
116 return g_tls_file_database_new (anchor_file, error);
120 g_tls_backend_gnutls_class_init (GTlsBackendGnutlsClass *backend_class)
122 GObjectClass *gobject_class = G_OBJECT_CLASS (backend_class);
123 gobject_class->finalize = g_tls_backend_gnutls_finalize;
124 backend_class->create_database = g_tls_backend_gnutls_real_create_database;
125 g_type_class_add_private (backend_class, sizeof (GTlsBackendGnutlsPrivate));
129 g_tls_backend_gnutls_class_finalize (GTlsBackendGnutlsClass *backend_class)
134 g_tls_backend_gnutls_get_default_database (GTlsBackend *backend)
136 GTlsBackendGnutls *self = G_TLS_BACKEND_GNUTLS (backend);
137 GTlsDatabase *result;
138 GError *error = NULL;
140 g_mutex_lock (&self->priv->mutex);
142 if (self->priv->default_database)
144 result = g_object_ref (self->priv->default_database);
148 g_assert (G_TLS_BACKEND_GNUTLS_GET_CLASS (self)->create_database);
149 result = G_TLS_BACKEND_GNUTLS_GET_CLASS (self)->create_database (self, &error);
152 g_warning ("couldn't load TLS file database: %s",
154 g_clear_error (&error);
159 self->priv->default_database = g_object_ref (result);
163 g_mutex_unlock (&self->priv->mutex);
169 g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface)
171 iface->get_certificate_type = g_tls_certificate_gnutls_get_type;
172 iface->get_client_connection_type = g_tls_client_connection_gnutls_get_type;
173 iface->get_server_connection_type = g_tls_server_connection_gnutls_get_type;
174 iface->get_file_database_type = g_tls_file_database_gnutls_get_type;
175 iface->get_default_database = g_tls_backend_gnutls_get_default_database;
178 /* Session cache support; all the details are sort of arbitrary. Note
179 * that having session_cache_cleanup() be a little bit slow isn't the
180 * end of the world, since it will still be faster than the network
181 * is. (NSS uses a linked list for its cache...)
184 G_LOCK_DEFINE_STATIC (session_cache_lock);
185 GHashTable *client_session_cache, *server_session_cache;
187 #define SESSION_CACHE_MAX_SIZE 50
188 #define SESSION_CACHE_MAX_AGE (60 * 60) /* one hour */
192 GBytes *session_data;
194 } GTlsBackendGnutlsCacheData;
197 session_cache_cleanup (GHashTable *cache)
201 GTlsBackendGnutlsCacheData *cache_data;
202 time_t expired = time (NULL) - SESSION_CACHE_MAX_AGE;
204 g_hash_table_iter_init (&iter, cache);
205 while (g_hash_table_iter_next (&iter, &key, &value))
208 if (cache_data->last_used < expired)
209 g_hash_table_iter_remove (&iter);
214 cache_data_free (gpointer data)
216 GTlsBackendGnutlsCacheData *cache_data = data;
218 g_bytes_unref (cache_data->session_id);
219 g_bytes_unref (cache_data->session_data);
220 g_slice_free (GTlsBackendGnutlsCacheData, cache_data);
224 get_session_cache (unsigned int type,
227 GHashTable **cache_p;
229 cache_p = (type == GNUTLS_CLIENT) ? &client_session_cache : &server_session_cache;
230 if (!*cache_p && create)
232 *cache_p = g_hash_table_new_full (g_bytes_hash, g_bytes_equal,
233 NULL, cache_data_free);
239 g_tls_backend_gnutls_store_session (unsigned int type,
241 GBytes *session_data)
243 GTlsBackendGnutlsCacheData *cache_data;
246 G_LOCK (session_cache_lock);
248 cache = get_session_cache (type, TRUE);
249 cache_data = g_hash_table_lookup (cache, session_id);
252 if (!g_bytes_equal (cache_data->session_data, session_data))
254 g_bytes_unref (cache_data->session_data);
255 cache_data->session_data = g_bytes_ref (session_data);
260 if (g_hash_table_size (cache) >= SESSION_CACHE_MAX_SIZE)
261 session_cache_cleanup (cache);
263 cache_data = g_slice_new (GTlsBackendGnutlsCacheData);
264 cache_data->session_id = g_bytes_ref (session_id);
265 cache_data->session_data = g_bytes_ref (session_data);
267 g_hash_table_insert (cache, cache_data->session_id, cache_data);
269 cache_data->last_used = time (NULL);
271 G_UNLOCK (session_cache_lock);
275 g_tls_backend_gnutls_remove_session (unsigned int type,
280 G_LOCK (session_cache_lock);
282 cache = get_session_cache (type, FALSE);
284 g_hash_table_remove (cache, session_id);
286 G_UNLOCK (session_cache_lock);
290 g_tls_backend_gnutls_lookup_session (unsigned int type,
293 GTlsBackendGnutlsCacheData *cache_data;
294 GBytes *session_data = NULL;
297 G_LOCK (session_cache_lock);
299 cache = get_session_cache (type, FALSE);
302 cache_data = g_hash_table_lookup (cache, session_id);
305 cache_data->last_used = time (NULL);
306 session_data = g_bytes_ref (cache_data->session_data);
310 G_UNLOCK (session_cache_lock);
316 g_tls_backend_gnutls_register (GIOModule *module)
318 g_tls_backend_gnutls_register_type (G_TYPE_MODULE (module));
319 g_io_extension_point_implement (G_TLS_BACKEND_EXTENSION_POINT_NAME,
320 g_tls_backend_gnutls_get_type(),