Add new build option to use tizen default CA file
[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 #ifdef TIZEN_DEFAULT_CA_FILE
215       openssl_cert_file = TIZEN_DEFAULT_CA_FILE;
216 #else
217       openssl_cert_file = g_getenv (X509_get_default_cert_file_env ());
218 #endif
219       if (openssl_cert_file == NULL)
220         openssl_cert_file = X509_get_default_cert_file ();
221
222       anchor_file = g_strdup (openssl_cert_file);
223     }
224
225   database = g_tls_file_database_new (anchor_file, error);
226   g_free (anchor_file);
227
228   return database;
229 }
230
231 static void
232 g_tls_backend_openssl_class_init (GTlsBackendOpensslClass *klass)
233 {
234   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
235
236   gobject_class->finalize = g_tls_backend_openssl_finalize;
237
238   klass->create_database = g_tls_backend_openssl_real_create_database;
239 }
240
241 static void
242 g_tls_backend_openssl_class_finalize (GTlsBackendOpensslClass *backend_class)
243 {
244 }
245
246 static GTlsDatabase*
247 g_tls_backend_openssl_get_default_database (GTlsBackend *backend)
248 {
249   GTlsBackendOpenssl *openssl_backend = G_TLS_BACKEND_OPENSSL (backend);
250   GTlsBackendOpensslPrivate *priv;
251   GTlsDatabase *result;
252   GError *error = NULL;
253
254   priv = g_tls_backend_openssl_get_instance_private (openssl_backend);
255
256   g_mutex_lock (&priv->mutex);
257
258   if (priv->default_database)
259     {
260       result = g_object_ref (priv->default_database);
261     }
262   else
263     {
264       g_assert (G_TLS_BACKEND_OPENSSL_GET_CLASS (openssl_backend)->create_database);
265       result = G_TLS_BACKEND_OPENSSL_GET_CLASS (openssl_backend)->create_database (openssl_backend, &error);
266       if (error)
267         {
268           g_warning ("Couldn't load TLS file database: %s",
269                      error->message);
270           g_clear_error (&error);
271         }
272       else
273         {
274           g_assert (result);
275           priv->default_database = g_object_ref (result);
276         }
277     }
278
279   g_mutex_unlock (&priv->mutex);
280
281   return result;
282 }
283
284 static void
285 g_tls_backend_openssl_interface_init (GTlsBackendInterface *iface)
286 {
287   iface->get_certificate_type = g_tls_certificate_openssl_get_type;
288   iface->get_client_connection_type = g_tls_client_connection_openssl_get_type;
289   iface->get_server_connection_type = g_tls_server_connection_openssl_get_type;
290   iface->get_file_database_type = g_tls_file_database_openssl_get_type;
291   iface->get_default_database = g_tls_backend_openssl_get_default_database;
292 }
293
294 void
295 g_tls_backend_openssl_register (GIOModule *module)
296 {
297   g_tls_backend_openssl_register_type (G_TYPE_MODULE (module));
298   if (!module)
299     g_io_extension_point_register (G_TLS_BACKEND_EXTENSION_POINT_NAME);
300   g_io_extension_point_implement (G_TLS_BACKEND_EXTENSION_POINT_NAME,
301                                   g_tls_backend_openssl_get_type(),
302                                   "openssl",
303                                   -1);
304 }