Add tizen dlog for debugging
[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 #include "TIZEN.h"
40
41 struct _GTlsBackendGnutls
42 {
43   GObject parent_instance;
44
45   GMutex mutex;
46   GTlsDatabase *default_database;
47 };
48
49 static void g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface);
50
51 G_DEFINE_DYNAMIC_TYPE_EXTENDED (GTlsBackendGnutls, g_tls_backend_gnutls, G_TYPE_OBJECT, 0,
52                                 G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_TLS_BACKEND,
53                                                                g_tls_backend_gnutls_interface_init);)
54
55 #ifdef GTLS_GNUTLS_DEBUG
56 static void
57 gtls_log_func (int level, const char *msg)
58 {
59   g_print ("GTLS: %s", msg);
60 }
61 #endif
62
63 static gpointer
64 gtls_gnutls_init (gpointer data)
65 {
66   GTypePlugin *plugin;
67
68   gnutls_global_init ();
69
70 #ifdef GTLS_GNUTLS_DEBUG
71   gnutls_global_set_log_function (gtls_log_func);
72   gnutls_global_set_log_level (9);
73 #endif
74
75   /* Leak the module to keep it from being unloaded. */
76   plugin = g_type_get_plugin (G_TYPE_TLS_BACKEND_GNUTLS);
77   if (plugin != NULL)
78     g_type_plugin_use (plugin);
79   return NULL;
80 }
81
82 GNUTLS_SKIP_GLOBAL_INIT
83
84 static GOnce gnutls_inited = G_ONCE_INIT;
85
86 static void
87 g_tls_backend_gnutls_init (GTlsBackendGnutls *backend)
88 {
89   /* Once we call gtls_gnutls_init(), we can't allow the module to be
90    * unloaded (since if gnutls gets unloaded but gcrypt doesn't, then
91    * gcrypt will have dangling pointers to gnutls's mutex functions).
92    * So we initialize it from here rather than at class init time so
93    * that it doesn't happen unless the app is actually using TLS (as
94    * opposed to just calling g_io_modules_scan_all_in_directory()).
95    */
96   g_once (&gnutls_inited, gtls_gnutls_init, NULL);
97
98   g_mutex_init (&backend->mutex);
99 }
100
101 static void
102 g_tls_backend_gnutls_finalize (GObject *object)
103 {
104   GTlsBackendGnutls *backend = G_TLS_BACKEND_GNUTLS (object);
105
106   g_clear_object (&backend->default_database);
107   g_mutex_clear (&backend->mutex);
108
109   G_OBJECT_CLASS (g_tls_backend_gnutls_parent_class)->finalize (object);
110 }
111
112 static void
113 g_tls_backend_gnutls_class_init (GTlsBackendGnutlsClass *backend_class)
114 {
115   GObjectClass *gobject_class = G_OBJECT_CLASS (backend_class);
116
117   gobject_class->finalize = g_tls_backend_gnutls_finalize;
118 }
119
120 static void
121 g_tls_backend_gnutls_class_finalize (GTlsBackendGnutlsClass *backend_class)
122 {
123 }
124
125 static GTlsDatabase*
126 g_tls_backend_gnutls_get_default_database (GTlsBackend *backend)
127 {
128   GTlsBackendGnutls *self = G_TLS_BACKEND_GNUTLS (backend);
129   GTlsDatabase *result;
130   GError *error = NULL;
131
132   g_mutex_lock (&self->mutex);
133
134   if (self->default_database)
135     {
136       result = g_object_ref (self->default_database);
137     }
138   else
139     {
140       result = G_TLS_DATABASE (g_tls_database_gnutls_new (&error));
141       if (error)
142         {
143           g_warning ("Failed to load TLS database: %s", error->message);
144           g_clear_error (&error);
145         }
146       else
147         {
148           g_assert (result);
149           self->default_database = g_object_ref (result);
150         }
151     }
152
153   g_mutex_unlock (&self->mutex);
154
155   return result;
156 }
157
158 static void
159 g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface)
160 {
161   iface->get_certificate_type       = g_tls_certificate_gnutls_get_type;
162   iface->get_client_connection_type = g_tls_client_connection_gnutls_get_type;
163   iface->get_server_connection_type = g_tls_server_connection_gnutls_get_type;
164   iface->get_file_database_type =     g_tls_file_database_gnutls_get_type;
165   iface->get_default_database =       g_tls_backend_gnutls_get_default_database;
166   iface->get_dtls_client_connection_type = g_tls_client_connection_gnutls_get_type;
167   iface->get_dtls_server_connection_type = g_tls_server_connection_gnutls_get_type;
168 }
169
170 /* Session cache support; all the details are sort of arbitrary. Note
171  * that having session_cache_cleanup() be a little bit slow isn't the
172  * end of the world, since it will still be faster than the network
173  * is. (NSS uses a linked list for its cache...)
174  */
175
176 G_LOCK_DEFINE_STATIC (session_cache_lock);
177 GHashTable *client_session_cache, *server_session_cache;
178
179 #define SESSION_CACHE_MAX_SIZE 50
180 #define SESSION_CACHE_MAX_AGE (60 * 60) /* one hour */
181
182 typedef struct {
183   GBytes *session_id;
184   GBytes *session_data;
185   time_t  last_used;
186 } GTlsBackendGnutlsCacheData;
187
188 static void
189 session_cache_cleanup (GHashTable *cache)
190 {
191   GHashTableIter iter;
192   gpointer key, value;
193   GTlsBackendGnutlsCacheData *cache_data;
194   time_t expired = time (NULL) - SESSION_CACHE_MAX_AGE;
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 (cache_data->last_used < expired)
201         g_hash_table_iter_remove (&iter);
202     }
203 }
204
205 static void
206 cache_data_free (gpointer data)
207 {
208   GTlsBackendGnutlsCacheData *cache_data = data;
209
210   g_bytes_unref (cache_data->session_id);
211   g_bytes_unref (cache_data->session_data);
212   g_free (cache_data);
213 }
214
215 static GHashTable *
216 get_session_cache (unsigned int            type,
217                    gboolean                create)
218 {
219   GHashTable **cache_p;
220
221   cache_p = (type == GNUTLS_CLIENT) ? &client_session_cache : &server_session_cache;
222   if (!*cache_p && create)
223     {
224       *cache_p = g_hash_table_new_full (g_bytes_hash, g_bytes_equal,
225                                         NULL, cache_data_free);
226     }
227   return *cache_p;
228 }
229
230 void
231 g_tls_backend_gnutls_store_session (unsigned int             type,
232                                     GBytes                  *session_id,
233                                     GBytes                  *session_data)
234 {
235   GTlsBackendGnutlsCacheData *cache_data;
236   GHashTable *cache;
237
238   G_LOCK (session_cache_lock);
239
240   cache = get_session_cache (type, TRUE);
241   cache_data = g_hash_table_lookup (cache, session_id);
242   if (cache_data)
243     {
244       if (!g_bytes_equal (cache_data->session_data, session_data))
245         {
246           g_bytes_unref (cache_data->session_data);
247           cache_data->session_data = g_bytes_ref (session_data);
248         }
249     }
250   else
251     {
252       if (g_hash_table_size (cache) >= SESSION_CACHE_MAX_SIZE)
253         session_cache_cleanup (cache);
254
255       cache_data = g_new (GTlsBackendGnutlsCacheData, 1);
256       cache_data->session_id = g_bytes_ref (session_id);
257       cache_data->session_data = g_bytes_ref (session_data);
258
259       g_hash_table_insert (cache, cache_data->session_id, cache_data);
260     }
261   cache_data->last_used = time (NULL);
262
263   G_UNLOCK (session_cache_lock);
264 }
265
266 void
267 g_tls_backend_gnutls_remove_session (unsigned int             type,
268                                      GBytes                  *session_id)
269 {
270   GHashTable *cache;
271
272   G_LOCK (session_cache_lock);
273
274   cache = get_session_cache (type, FALSE);
275   if (cache)
276     g_hash_table_remove (cache, session_id);
277
278   G_UNLOCK (session_cache_lock);
279 }
280
281 GBytes *
282 g_tls_backend_gnutls_lookup_session (unsigned int             type,
283                                      GBytes                  *session_id)
284 {
285   GTlsBackendGnutlsCacheData *cache_data;
286   GBytes *session_data = NULL;
287   GHashTable *cache;
288
289   G_LOCK (session_cache_lock);
290
291   cache = get_session_cache (type, FALSE);
292   if (cache)
293     {
294       cache_data = g_hash_table_lookup (cache, session_id);
295       if (cache_data)
296         {
297           cache_data->last_used = time (NULL);
298           session_data = g_bytes_ref (cache_data->session_data);
299         }
300     }
301
302   G_UNLOCK (session_cache_lock);
303
304   return session_data;
305 }
306
307 void
308 g_tls_backend_gnutls_register (GIOModule *module)
309 {
310   g_tls_backend_gnutls_register_type (G_TYPE_MODULE (module));
311   if (module == NULL)
312     g_io_extension_point_register (G_TLS_BACKEND_EXTENSION_POINT_NAME);
313   g_io_extension_point_implement (G_TLS_BACKEND_EXTENSION_POINT_NAME,
314                                   g_tls_backend_gnutls_get_type(),
315                                   "gnutls",
316                                   0);
317 }