Imported Upstream version 2.72.alpha
[platform/upstream/glib-networking.git] / tls / gnutls / gtlsbackend-gnutls.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3  * GIO - GLib Input, Output and Streaming Library
4  *
5  * Copyright 2010 Red Hat, Inc
6  *
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.
11  *
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.
16  *
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/>.
20  *
21  * In addition, when the library is used with OpenSSL, a special
22  * exception applies. Refer to the LICENSE_EXCEPTION file for details.
23  */
24
25 #include "config.h"
26 #include "glib.h"
27
28 #include <errno.h>
29 #include <string.h>
30
31 #include <gnutls/gnutls.h>
32
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"
38
39 struct _GTlsBackendGnutls
40 {
41   GObject parent_instance;
42
43   GMutex mutex;
44   GTlsDatabase *default_database;
45 };
46
47 static void g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface);
48
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);)
52
53 #ifdef GTLS_GNUTLS_DEBUG
54 static void
55 gtls_log_func (int level, const char *msg)
56 {
57   g_print ("GTLS: %s", msg);
58 }
59 #endif
60
61 static gpointer
62 gtls_gnutls_init (gpointer data)
63 {
64   GTypePlugin *plugin;
65
66   gnutls_global_init ();
67
68 #ifdef GTLS_GNUTLS_DEBUG
69   gnutls_global_set_log_function (gtls_log_func);
70   gnutls_global_set_log_level (9);
71 #endif
72
73   /* Leak the module to keep it from being unloaded. */
74   plugin = g_type_get_plugin (G_TYPE_TLS_BACKEND_GNUTLS);
75   if (plugin)
76     g_type_plugin_use (plugin);
77   return NULL;
78 }
79
80 GNUTLS_SKIP_GLOBAL_INIT
81
82 static GOnce gnutls_inited = G_ONCE_INIT;
83
84 static void
85 g_tls_backend_gnutls_init (GTlsBackendGnutls *backend)
86 {
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()).
93    */
94   g_once (&gnutls_inited, gtls_gnutls_init, NULL);
95
96   g_mutex_init (&backend->mutex);
97 }
98
99 static void
100 g_tls_backend_gnutls_finalize (GObject *object)
101 {
102   GTlsBackendGnutls *backend = G_TLS_BACKEND_GNUTLS (object);
103
104   g_clear_object (&backend->default_database);
105   g_mutex_clear (&backend->mutex);
106
107   G_OBJECT_CLASS (g_tls_backend_gnutls_parent_class)->finalize (object);
108 }
109
110 static void
111 g_tls_backend_gnutls_class_init (GTlsBackendGnutlsClass *backend_class)
112 {
113   GObjectClass *gobject_class = G_OBJECT_CLASS (backend_class);
114
115   gobject_class->finalize = g_tls_backend_gnutls_finalize;
116 }
117
118 static void
119 g_tls_backend_gnutls_class_finalize (GTlsBackendGnutlsClass *backend_class)
120 {
121 }
122
123 static GTlsDatabase *
124 g_tls_backend_gnutls_get_default_database (GTlsBackend *backend)
125 {
126   GTlsBackendGnutls *self = G_TLS_BACKEND_GNUTLS (backend);
127   GTlsDatabase *result;
128   GError *error = NULL;
129
130   g_mutex_lock (&self->mutex);
131
132   if (self->default_database)
133     {
134       result = g_object_ref (self->default_database);
135     }
136   else
137     {
138       result = G_TLS_DATABASE (g_tls_database_gnutls_new (&error));
139       if (error)
140         {
141           g_warning ("Failed to load TLS database: %s", error->message);
142           g_clear_error (&error);
143         }
144       else
145         {
146           g_assert (result);
147           self->default_database = g_object_ref (result);
148         }
149     }
150
151   g_mutex_unlock (&self->mutex);
152
153   return result;
154 }
155
156 static void
157 g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface)
158 {
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;
166 }
167
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.
174  *
175  * https://arxiv.org/abs/1810.07304
176  */
177
178 G_LOCK_DEFINE_STATIC (session_cache_lock);
179 GHashTable *client_session_cache; /* (owned) GBytes -> (owned) GTlsBackendGnutlsCacheData */
180
181 #define SESSION_CACHE_MAX_SIZE 50
182 #define SESSION_CACHE_MAX_AGE (10ll * 60ll * G_USEC_PER_SEC) /* ten minutes */
183
184 typedef struct {
185   GQueue *session_tickets; /* (owned) GBytes */
186   gint64  expiration_time;
187 } GTlsBackendGnutlsCacheData;
188
189 static void
190 session_cache_cleanup (GHashTable *cache)
191 {
192   GHashTableIter iter;
193   gpointer key, value;
194   GTlsBackendGnutlsCacheData *cache_data;
195
196   g_hash_table_iter_init (&iter, cache);
197   while (g_hash_table_iter_next (&iter, &key, &value))
198     {
199       cache_data = value;
200       if (g_get_monotonic_time () > cache_data->expiration_time)
201         g_hash_table_iter_remove (&iter);
202     }
203 }
204
205 static void
206 cache_data_free (GTlsBackendGnutlsCacheData *data)
207 {
208   g_queue_free_full (data->session_tickets, (GDestroyNotify)g_bytes_unref);
209   g_free (data);
210 }
211
212 static GHashTable *
213 get_session_cache (gboolean create)
214 {
215   if (!client_session_cache && create)
216     {
217       client_session_cache = g_hash_table_new_full (g_bytes_hash, g_bytes_equal,
218                                                     (GDestroyNotify)g_bytes_unref, (GDestroyNotify)cache_data_free);
219     }
220   return client_session_cache;
221 }
222
223 void
224 g_tls_backend_gnutls_store_session_data (GBytes *session_id,
225                                          GBytes *session_data)
226 {
227   GTlsBackendGnutlsCacheData *cache_data;
228   GHashTable *cache;
229
230   G_LOCK (session_cache_lock);
231
232   cache = get_session_cache (TRUE);
233   cache_data = g_hash_table_lookup (cache, session_id);
234   if (!cache_data)
235     {
236       if (g_hash_table_size (cache) >= SESSION_CACHE_MAX_SIZE)
237         session_cache_cleanup (cache);
238
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);
242     }
243
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;
246
247   G_UNLOCK (session_cache_lock);
248 }
249
250 GBytes *
251 g_tls_backend_gnutls_lookup_session_data (GBytes *session_id)
252 {
253   GTlsBackendGnutlsCacheData *cache_data;
254   GBytes *session_data = NULL;
255   GHashTable *cache;
256
257   G_LOCK (session_cache_lock);
258
259   cache = get_session_cache (FALSE);
260   if (cache)
261     {
262       cache_data = g_hash_table_lookup (cache, session_id);
263       if (cache_data)
264         {
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.
267            */
268           session_data = g_queue_pop_head (cache_data->session_tickets);
269         }
270     }
271
272   G_UNLOCK (session_cache_lock);
273
274   return session_data;
275 }
276
277 void
278 g_tls_backend_gnutls_register (GIOModule *module)
279 {
280   g_tls_backend_gnutls_register_type (G_TYPE_MODULE (module));
281   if (!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 (),
285                                   "gnutls",
286                                   0);
287 }