abff7bb61dc0c5364be086ecc38847997e62e6ba
[platform/upstream/glib-networking.git] / tls / openssl / gtlsbackend-openssl.c
1 /*
2  * gtlsbackend-openssl.c
3  *
4  * Copyright (C) 2015 NICE s.r.l.
5  *
6  * This file is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This file is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  *
19  * In addition, when the library is used with OpenSSL, a special
20  * exception applies. Refer to the LICENSE_EXCEPTION file for details.
21  *
22  * Authors: Ignacio Casal Quinteiro
23  */
24
25 #include "config.h"
26 #include "glib.h"
27
28 #include <errno.h>
29 #include <string.h>
30
31 #include "openssl-include.h"
32
33 #include "gtlsbackend-openssl.h"
34 #include "gtlscertificate-openssl.h"
35 #include "gtlsserverconnection-openssl.h"
36 #include "gtlsclientconnection-openssl.h"
37 #include "gtlsfiledatabase-openssl.h"
38
39 typedef struct _GTlsBackendOpensslPrivate
40 {
41   GMutex mutex;
42   GTlsDatabase *default_database;
43 } GTlsBackendOpensslPrivate;
44
45 static void g_tls_backend_openssl_interface_init (GTlsBackendInterface *iface);
46
47 G_DEFINE_DYNAMIC_TYPE_EXTENDED (GTlsBackendOpenssl, g_tls_backend_openssl, G_TYPE_OBJECT, 0,
48                                 G_ADD_PRIVATE_DYNAMIC (GTlsBackendOpenssl)
49                                 G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_TLS_BACKEND,
50                                                                g_tls_backend_openssl_interface_init))
51
52 static GMutex *mutex_array = NULL;
53
54 struct CRYPTO_dynlock_value {
55   GMutex mutex;
56 };
57
58 #if defined(__GNUC__)
59 #pragma GCC diagnostic push
60 #pragma GCC diagnostic ignored "-Wunused-function"
61 #endif
62
63 static unsigned long
64 id_cb (void)
65 {
66   return (unsigned long) g_thread_self ();
67 }
68
69 static void
70 locking_cb (int         mode,
71             int         n,
72             const char *file,
73             int         line)
74 {
75   if (mode & CRYPTO_LOCK)
76     g_mutex_lock (&mutex_array[n]);
77   else
78     g_mutex_unlock (&mutex_array[n]);
79 }
80
81 static struct CRYPTO_dynlock_value *
82 dyn_create_cb (const char *file,
83                int         line)
84 {
85   struct CRYPTO_dynlock_value *value = g_try_new (struct CRYPTO_dynlock_value, 1);
86
87   if (value)
88     g_mutex_init (&value->mutex);
89
90   return value;
91 }
92
93 static void
94 dyn_lock_cb (int                          mode,
95              struct CRYPTO_dynlock_value *l,
96              const char                  *file,
97              int                          line)
98 {
99   if (mode & CRYPTO_LOCK)
100     g_mutex_lock (&l->mutex);
101   else
102     g_mutex_unlock (&l->mutex);
103 }
104
105 static void
106 dyn_destroy_cb (struct CRYPTO_dynlock_value *l,
107                 const char                  *file,
108                 int                          line)
109 {
110   g_mutex_clear (&l->mutex);
111   g_free (l);
112 }
113
114 #if defined(__GNUC__)
115 #pragma GCC diagnostic pop
116 #endif
117
118 static gpointer
119 gtls_openssl_init (gpointer data)
120 {
121   int i;
122   GTypePlugin *plugin;
123
124   /* Initialize openssl threading */
125   mutex_array = g_malloc_n (CRYPTO_num_locks(), sizeof (GMutex));
126   for (i = 0; i < CRYPTO_num_locks (); ++i)
127     g_mutex_init(&mutex_array[i]);
128
129   CRYPTO_set_id_callback (id_cb);
130   CRYPTO_set_locking_callback (locking_cb);
131   CRYPTO_set_dynlock_create_callback (dyn_create_cb);
132   CRYPTO_set_dynlock_lock_callback (dyn_lock_cb);
133   CRYPTO_set_dynlock_destroy_callback (dyn_destroy_cb);
134
135   SSL_library_init ();
136   SSL_load_error_strings ();
137   OpenSSL_add_all_algorithms ();
138
139   /* Leak the module to keep it from being unloaded. */
140   plugin = g_type_get_plugin (G_TYPE_TLS_BACKEND_OPENSSL);
141   if (plugin != NULL)
142     g_type_plugin_use (plugin);
143   return NULL;
144 }
145
146 static GOnce openssl_inited = G_ONCE_INIT;
147
148 static void
149 g_tls_backend_openssl_init (GTlsBackendOpenssl *backend)
150 {
151   GTlsBackendOpensslPrivate *priv;
152
153   priv = g_tls_backend_openssl_get_instance_private (backend);
154
155   /* Once we call gtls_openssl_init(), we can't allow the module to be
156    * unloaded (since if openssl gets unloaded but gcrypt doesn't, then
157    * gcrypt will have dangling pointers to openssl's mutex functions).
158    * So we initialize it from here rather than at class init time so
159    * that it doesn't happen unless the app is actually using TLS (as
160    * opposed to just calling g_io_modules_scan_all_in_directory()).
161    */
162   g_once (&openssl_inited, gtls_openssl_init, NULL);
163
164   g_mutex_init (&priv->mutex);
165 }
166
167 static void
168 g_tls_backend_openssl_finalize (GObject *object)
169 {
170   int i;
171
172   GTlsBackendOpenssl *backend = G_TLS_BACKEND_OPENSSL (object);
173   GTlsBackendOpensslPrivate *priv;
174
175   priv = g_tls_backend_openssl_get_instance_private (backend);
176
177   g_clear_object (&priv->default_database);
178   g_mutex_clear (&priv->mutex);
179
180   CRYPTO_set_id_callback (NULL);
181   CRYPTO_set_locking_callback (NULL);
182   CRYPTO_set_dynlock_create_callback (NULL);
183   CRYPTO_set_dynlock_lock_callback (NULL);
184   CRYPTO_set_dynlock_destroy_callback (NULL);
185   for (i = 0; i < CRYPTO_num_locks(); ++i)
186     g_mutex_clear (&mutex_array[i]);
187   g_free (mutex_array);
188
189   G_OBJECT_CLASS (g_tls_backend_openssl_parent_class)->finalize (object);
190 }
191
192 static GTlsDatabase *
193 g_tls_backend_openssl_real_create_database (GTlsBackendOpenssl  *self,
194                                             GError             **error)
195 {
196   gchar *anchor_file = NULL;
197   GTlsDatabase *database;
198
199 #ifdef G_OS_WIN32
200   if (g_getenv ("G_TLS_OPENSSL_HANDLE_CERT_RELOCATABLE") != NULL)
201     {
202       gchar *module_dir;
203
204       module_dir = g_win32_get_package_installation_directory_of_module (NULL);
205       anchor_file = g_build_filename (module_dir, "bin", "cert.pem", NULL);
206       g_free (module_dir);
207     }
208 #endif
209
210   if (anchor_file == NULL)
211     {
212       const gchar *openssl_cert_file;
213
214       openssl_cert_file = g_getenv (X509_get_default_cert_file_env ());
215       if (openssl_cert_file == NULL)
216         openssl_cert_file = X509_get_default_cert_file ();
217
218       anchor_file = g_strdup (openssl_cert_file);
219     }
220
221   database = g_tls_file_database_new (anchor_file, error);
222   g_free (anchor_file);
223
224   return database;
225 }
226
227 static void
228 g_tls_backend_openssl_class_init (GTlsBackendOpensslClass *klass)
229 {
230   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
231
232   gobject_class->finalize = g_tls_backend_openssl_finalize;
233
234   klass->create_database = g_tls_backend_openssl_real_create_database;
235 }
236
237 static void
238 g_tls_backend_openssl_class_finalize (GTlsBackendOpensslClass *backend_class)
239 {
240 }
241
242 static GTlsDatabase*
243 g_tls_backend_openssl_get_default_database (GTlsBackend *backend)
244 {
245   GTlsBackendOpenssl *openssl_backend = G_TLS_BACKEND_OPENSSL (backend);
246   GTlsBackendOpensslPrivate *priv;
247   GTlsDatabase *result;
248   GError *error = NULL;
249
250   priv = g_tls_backend_openssl_get_instance_private (openssl_backend);
251
252   g_mutex_lock (&priv->mutex);
253
254   if (priv->default_database)
255     {
256       result = g_object_ref (priv->default_database);
257     }
258   else
259     {
260       g_assert (G_TLS_BACKEND_OPENSSL_GET_CLASS (openssl_backend)->create_database);
261       result = G_TLS_BACKEND_OPENSSL_GET_CLASS (openssl_backend)->create_database (openssl_backend, &error);
262       if (error)
263         {
264           g_warning ("Couldn't load TLS file database: %s",
265                      error->message);
266           g_clear_error (&error);
267         }
268       else
269         {
270           g_assert (result);
271           priv->default_database = g_object_ref (result);
272         }
273     }
274
275   g_mutex_unlock (&priv->mutex);
276
277   return result;
278 }
279
280 static void
281 g_tls_backend_openssl_interface_init (GTlsBackendInterface *iface)
282 {
283   iface->get_certificate_type = g_tls_certificate_openssl_get_type;
284   iface->get_client_connection_type = g_tls_client_connection_openssl_get_type;
285   iface->get_server_connection_type = g_tls_server_connection_openssl_get_type;
286   iface->get_file_database_type = g_tls_file_database_openssl_get_type;
287   iface->get_default_database = g_tls_backend_openssl_get_default_database;
288 }
289
290 void
291 g_tls_backend_openssl_register (GIOModule *module)
292 {
293   g_tls_backend_openssl_register_type (G_TYPE_MODULE (module));
294   if (!module)
295     g_io_extension_point_register (G_TLS_BACKEND_EXTENSION_POINT_NAME);
296   g_io_extension_point_implement (G_TLS_BACKEND_EXTENSION_POINT_NAME,
297                                   g_tls_backend_openssl_get_type(),
298                                   "openssl",
299                                   -1);
300 }