1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3 * GIO - GLib Input, Output and Streaming Library
5 * Copyright 2010 Red Hat, Inc
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, see
19 * <http://www.gnu.org/licenses/>.
21 * In addition, when the library is used with OpenSSL, a special
22 * exception applies. Refer to the LICENSE_EXCEPTION file for details.
31 #include <gnutls/gnutls.h>
33 #include "gtlsbackend-gnutls.h"
34 #include "gtlscertificate-gnutls.h"
35 #include "gtlsclientconnection-gnutls.h"
36 #include "gtlsfiledatabase-gnutls.h"
37 #include "gtlsserverconnection-gnutls.h"
39 struct _GTlsBackendGnutls
41 GObject parent_instance;
44 GTlsDatabase *default_database;
47 static void g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface);
49 G_DEFINE_DYNAMIC_TYPE_EXTENDED (GTlsBackendGnutls, g_tls_backend_gnutls, G_TYPE_OBJECT, 0,
50 G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_TLS_BACKEND,
51 g_tls_backend_gnutls_interface_init);)
53 #ifdef GTLS_GNUTLS_DEBUG
55 gtls_log_func (int level, const char *msg)
57 g_print ("GTLS: %s", msg);
62 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 plugin = g_type_get_plugin (G_TYPE_TLS_BACKEND_GNUTLS);
76 g_type_plugin_use (plugin);
80 GNUTLS_SKIP_GLOBAL_INIT
82 static GOnce gnutls_inited = G_ONCE_INIT;
85 g_tls_backend_gnutls_init (GTlsBackendGnutls *backend)
87 /* Once we call gtls_gnutls_init(), we can't allow the module to be
88 * unloaded (since if gnutls gets unloaded but gcrypt doesn't, then
89 * gcrypt will have dangling pointers to gnutls's mutex functions).
90 * So we initialize it from here rather than at class init time so
91 * that it doesn't happen unless the app is actually using TLS (as
92 * opposed to just calling g_io_modules_scan_all_in_directory()).
94 g_once (&gnutls_inited, gtls_gnutls_init, NULL);
96 g_mutex_init (&backend->mutex);
100 g_tls_backend_gnutls_finalize (GObject *object)
102 GTlsBackendGnutls *backend = G_TLS_BACKEND_GNUTLS (object);
104 g_clear_object (&backend->default_database);
105 g_mutex_clear (&backend->mutex);
107 G_OBJECT_CLASS (g_tls_backend_gnutls_parent_class)->finalize (object);
111 g_tls_backend_gnutls_class_init (GTlsBackendGnutlsClass *backend_class)
113 GObjectClass *gobject_class = G_OBJECT_CLASS (backend_class);
115 gobject_class->finalize = g_tls_backend_gnutls_finalize;
119 g_tls_backend_gnutls_class_finalize (GTlsBackendGnutlsClass *backend_class)
123 static GTlsDatabase *
124 g_tls_backend_gnutls_get_default_database (GTlsBackend *backend)
126 GTlsBackendGnutls *self = G_TLS_BACKEND_GNUTLS (backend);
127 GTlsDatabase *result;
128 GError *error = NULL;
130 g_mutex_lock (&self->mutex);
132 if (self->default_database)
134 result = g_object_ref (self->default_database);
138 result = G_TLS_DATABASE (g_tls_database_gnutls_new (&error));
141 g_warning ("Failed to load TLS database: %s", error->message);
142 g_clear_error (&error);
147 self->default_database = g_object_ref (result);
151 g_mutex_unlock (&self->mutex);
157 g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface)
159 iface->get_certificate_type = g_tls_certificate_gnutls_get_type;
160 iface->get_client_connection_type = g_tls_client_connection_gnutls_get_type;
161 iface->get_server_connection_type = g_tls_server_connection_gnutls_get_type;
162 iface->get_file_database_type = g_tls_file_database_gnutls_get_type;
163 iface->get_default_database = g_tls_backend_gnutls_get_default_database;
164 iface->get_dtls_client_connection_type = g_tls_client_connection_gnutls_get_type;
165 iface->get_dtls_server_connection_type = g_tls_server_connection_gnutls_get_type;
168 /* Session cache support. We try to be careful of TLS session tracking
169 * and so have adopted the recommendations of arXiv:1810.07304 section 6
170 * in using a 10-minute cache lifetime and in never updating the
171 * expiration time of cache entries when they are accessed to ensure a
172 * new session gets used after 10 minutes even if the cached one was
173 * resumed more recently.
175 * https://arxiv.org/abs/1810.07304
178 G_LOCK_DEFINE_STATIC (session_cache_lock);
179 GHashTable *client_session_cache; /* (owned) GBytes -> (owned) GTlsBackendGnutlsCacheData */
181 #define SESSION_CACHE_MAX_SIZE 50
182 #define SESSION_CACHE_MAX_AGE (10ll * 60ll * G_USEC_PER_SEC) /* ten minutes */
185 GQueue *session_tickets; /* (owned) GBytes */
186 gint64 expiration_time;
187 } GTlsBackendGnutlsCacheData;
190 session_cache_cleanup (GHashTable *cache)
194 GTlsBackendGnutlsCacheData *cache_data;
196 g_hash_table_iter_init (&iter, cache);
197 while (g_hash_table_iter_next (&iter, &key, &value))
200 if (g_get_monotonic_time () > cache_data->expiration_time)
201 g_hash_table_iter_remove (&iter);
206 cache_data_free (GTlsBackendGnutlsCacheData *data)
208 g_queue_free_full (data->session_tickets, (GDestroyNotify)g_bytes_unref);
213 get_session_cache (gboolean create)
215 if (!client_session_cache && create)
217 client_session_cache = g_hash_table_new_full (g_bytes_hash, g_bytes_equal,
218 (GDestroyNotify)g_bytes_unref, (GDestroyNotify)cache_data_free);
220 return client_session_cache;
224 g_tls_backend_gnutls_store_session_data (GBytes *session_id,
225 GBytes *session_data)
227 GTlsBackendGnutlsCacheData *cache_data;
230 G_LOCK (session_cache_lock);
232 cache = get_session_cache (TRUE);
233 cache_data = g_hash_table_lookup (cache, session_id);
236 if (g_hash_table_size (cache) >= SESSION_CACHE_MAX_SIZE)
237 session_cache_cleanup (cache);
239 cache_data = g_new (GTlsBackendGnutlsCacheData, 1);
240 cache_data->session_tickets = g_queue_new ();
241 g_hash_table_insert (cache, g_bytes_ref (session_id), cache_data);
244 g_queue_push_tail (cache_data->session_tickets, g_bytes_ref (session_data));
245 cache_data->expiration_time = g_get_monotonic_time () + SESSION_CACHE_MAX_AGE;
247 G_UNLOCK (session_cache_lock);
251 g_tls_backend_gnutls_lookup_session_data (GBytes *session_id)
253 GTlsBackendGnutlsCacheData *cache_data;
254 GBytes *session_data = NULL;
257 G_LOCK (session_cache_lock);
259 cache = get_session_cache (FALSE);
262 cache_data = g_hash_table_lookup (cache, session_id);
265 /* Note that session tickets should be used only once since TLS 1.3,
266 * so we remove from the queue after retrieval. See RFC 8446 §C.4.
268 session_data = g_queue_pop_head (cache_data->session_tickets);
272 G_UNLOCK (session_cache_lock);
278 g_tls_backend_gnutls_register (GIOModule *module)
280 g_tls_backend_gnutls_register_type (G_TYPE_MODULE (module));
282 g_io_extension_point_register (G_TLS_BACKEND_EXTENSION_POINT_NAME);
283 g_io_extension_point_implement (G_TLS_BACKEND_EXTENSION_POINT_NAME,
284 g_tls_backend_gnutls_get_type (),