openssl: Add mutex for data_index
[platform/upstream/glib-networking.git] / tls / openssl / gtlsclientconnection-openssl.c
1 /*
2  * gtlsclientconnection-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 #include "gtlsconnection-base.h"
33 #include "gtlsclientconnection-openssl.h"
34 #include "gtlsbackend-openssl.h"
35 #include "gtlscertificate-openssl.h"
36 #include <glib/gi18n-lib.h>
37
38 #define DEFAULT_CIPHER_LIST "HIGH:!DSS:!aNULL@STRENGTH"
39
40 typedef struct _GTlsClientConnectionOpensslPrivate
41 {
42   GTlsCertificateFlags validation_flags;
43   GSocketConnectable *server_identity;
44   gboolean use_ssl3;
45   gboolean session_data_override;
46
47   GBytes *session_id;
48   GBytes *session_data;
49
50   STACK_OF (X509_NAME) *ca_list;
51
52   SSL_SESSION *session;
53   SSL *ssl;
54   SSL_CTX *ssl_ctx;
55 } GTlsClientConnectionOpensslPrivate;
56
57 enum
58 {
59   PROP_0,
60   PROP_VALIDATION_FLAGS,
61   PROP_SERVER_IDENTITY,
62   PROP_USE_SSL3,
63   PROP_ACCEPTED_CAS
64 };
65
66 static void g_tls_client_connection_openssl_initable_interface_init (GInitableIface  *iface);
67
68 static void g_tls_client_connection_openssl_client_connection_interface_init (GTlsClientConnectionInterface *iface);
69
70 static GInitableIface *g_tls_client_connection_openssl_parent_initable_iface;
71
72 G_DEFINE_TYPE_WITH_CODE (GTlsClientConnectionOpenssl, g_tls_client_connection_openssl, G_TYPE_TLS_CONNECTION_OPENSSL,
73                          G_ADD_PRIVATE (GTlsClientConnectionOpenssl)
74                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
75                                                 g_tls_client_connection_openssl_initable_interface_init)
76                          G_IMPLEMENT_INTERFACE (G_TYPE_TLS_CLIENT_CONNECTION,
77                                                 g_tls_client_connection_openssl_client_connection_interface_init))
78
79 static void
80 g_tls_client_connection_openssl_finalize (GObject *object)
81 {
82   GTlsClientConnectionOpenssl *openssl = G_TLS_CLIENT_CONNECTION_OPENSSL (object);
83   GTlsClientConnectionOpensslPrivate *priv;
84
85   priv = g_tls_client_connection_openssl_get_instance_private (openssl);
86
87   g_clear_object (&priv->server_identity);
88   g_clear_pointer (&priv->session_id, g_bytes_unref);
89   g_clear_pointer (&priv->session_data, g_bytes_unref);
90
91   SSL_free (priv->ssl);
92   SSL_CTX_free (priv->ssl_ctx);
93   SSL_SESSION_free (priv->session);
94
95   G_OBJECT_CLASS (g_tls_client_connection_openssl_parent_class)->finalize (object);
96 }
97
98 static const gchar *
99 get_server_identity (GTlsClientConnectionOpenssl *openssl)
100 {
101   GTlsClientConnectionOpensslPrivate *priv;
102
103   priv = g_tls_client_connection_openssl_get_instance_private (openssl);
104
105   if (G_IS_NETWORK_ADDRESS (priv->server_identity))
106     return g_network_address_get_hostname (G_NETWORK_ADDRESS (priv->server_identity));
107   else if (G_IS_NETWORK_SERVICE (priv->server_identity))
108     return g_network_service_get_domain (G_NETWORK_SERVICE (priv->server_identity));
109   else
110     return NULL;
111 }
112
113 static void
114 g_tls_client_connection_openssl_get_property (GObject    *object,
115                                              guint       prop_id,
116                                              GValue     *value,
117                                              GParamSpec *pspec)
118 {
119   GTlsClientConnectionOpenssl *openssl = G_TLS_CLIENT_CONNECTION_OPENSSL (object);
120   GTlsClientConnectionOpensslPrivate *priv;
121   GList *accepted_cas;
122   gint i;
123
124   priv = g_tls_client_connection_openssl_get_instance_private (openssl);
125
126   switch (prop_id)
127     {
128     case PROP_VALIDATION_FLAGS:
129       g_value_set_flags (value, priv->validation_flags);
130       break;
131
132     case PROP_SERVER_IDENTITY:
133       g_value_set_object (value, priv->server_identity);
134       break;
135
136     case PROP_USE_SSL3:
137       g_value_set_boolean (value, priv->use_ssl3);
138       break;
139
140     case PROP_ACCEPTED_CAS:
141       accepted_cas = NULL;
142       if (priv->ca_list)
143         {
144           for (i = 0; i < sk_X509_NAME_num (priv->ca_list); ++i)
145             {
146               int size;
147
148               size = i2d_X509_NAME (sk_X509_NAME_value (priv->ca_list, i), NULL);
149               if (size > 0)
150                 {
151                   unsigned char *ca;
152
153                   ca = g_malloc (size);
154                   size = i2d_X509_NAME (sk_X509_NAME_value (priv->ca_list, i), &ca);
155                   if (size > 0)
156                     accepted_cas = g_list_prepend (accepted_cas, g_byte_array_new_take (
157                                                    ca, size));
158                   else
159                     g_free (ca);
160                 }
161             }
162           accepted_cas = g_list_reverse (accepted_cas);
163         }
164       g_value_set_pointer (value, accepted_cas);
165       break;
166
167     default:
168       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
169     }
170 }
171
172 static void
173 g_tls_client_connection_openssl_set_property (GObject      *object,
174                                              guint         prop_id,
175                                              const GValue *value,
176                                              GParamSpec   *pspec)
177 {
178   GTlsClientConnectionOpenssl *openssl = G_TLS_CLIENT_CONNECTION_OPENSSL (object);
179   GTlsClientConnectionOpensslPrivate *priv;
180
181   priv = g_tls_client_connection_openssl_get_instance_private (openssl);
182
183   switch (prop_id)
184     {
185     case PROP_VALIDATION_FLAGS:
186       priv->validation_flags = g_value_get_flags (value);
187       break;
188
189     case PROP_SERVER_IDENTITY:
190       if (priv->server_identity)
191         g_object_unref (priv->server_identity);
192       priv->server_identity = g_value_dup_object (value);
193       break;
194
195     case PROP_USE_SSL3:
196       priv->use_ssl3 = g_value_get_boolean (value);
197       break;
198
199     default:
200       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
201     }
202 }
203
204 static void
205 g_tls_client_connection_openssl_constructed (GObject *object)
206 {
207   GTlsClientConnectionOpenssl *openssl = G_TLS_CLIENT_CONNECTION_OPENSSL (object);
208   GTlsClientConnectionOpensslPrivate *priv;
209   GSocketConnection *base_conn;
210   GSocketAddress *remote_addr;
211   GInetAddress *iaddr;
212   guint port;
213
214   priv = g_tls_client_connection_openssl_get_instance_private (openssl);
215
216   /* Create a TLS session ID. We base it on the IP address since
217    * different hosts serving the same hostname/service will probably
218    * not share the same session cache. We base it on the
219    * server-identity because at least some servers will fail (rather
220    * than just failing to resume the session) if we don't.
221    * (https://bugs.launchpad.net/bugs/823325)
222    */
223   g_object_get (G_OBJECT (openssl), "base-io-stream", &base_conn, NULL);
224   if (G_IS_SOCKET_CONNECTION (base_conn))
225     {
226       remote_addr = g_socket_connection_get_remote_address (base_conn, NULL);
227       if (G_IS_INET_SOCKET_ADDRESS (remote_addr))
228         {
229           GInetSocketAddress *isaddr = G_INET_SOCKET_ADDRESS (remote_addr);
230           const gchar *server_hostname;
231           gchar *addrstr, *session_id;
232
233           iaddr = g_inet_socket_address_get_address (isaddr);
234           port = g_inet_socket_address_get_port (isaddr);
235
236           addrstr = g_inet_address_to_string (iaddr);
237           server_hostname = get_server_identity (openssl);
238           session_id = g_strdup_printf ("%s/%s/%d", addrstr,
239                                         server_hostname ? server_hostname : "",
240                                         port);
241           priv->session_id = g_bytes_new_take (session_id, strlen (session_id));
242           g_free (addrstr);
243         }
244       g_object_unref (remote_addr);
245     }
246   g_object_unref (base_conn);
247
248   G_OBJECT_CLASS (g_tls_client_connection_openssl_parent_class)->constructed (object);
249 }
250
251 static GTlsConnectionBaseStatus
252 g_tls_client_connection_openssl_handshake (GTlsConnectionBase  *tls,
253                                            GCancellable        *cancellable,
254                                            GError             **error)
255 {
256   return G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_openssl_parent_class)->
257     handshake (tls, cancellable, error);
258 }
259
260 static GTlsConnectionBaseStatus
261 g_tls_client_connection_openssl_complete_handshake (GTlsConnectionBase  *tls,
262                                                     GError             **error)
263 {
264   GTlsConnectionBaseStatus status;
265
266   status = G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_openssl_parent_class)->
267     complete_handshake (tls, error);
268
269   return status;
270 }
271
272 static SSL *
273 g_tls_client_connection_openssl_get_ssl (GTlsConnectionOpenssl *connection)
274 {
275   GTlsClientConnectionOpenssl *client = G_TLS_CLIENT_CONNECTION_OPENSSL (connection);
276   GTlsClientConnectionOpensslPrivate *priv;
277
278   priv = g_tls_client_connection_openssl_get_instance_private (client);
279
280   return priv->ssl;
281 }
282
283 static void
284 g_tls_client_connection_openssl_class_init (GTlsClientConnectionOpensslClass *klass)
285 {
286   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
287   GTlsConnectionBaseClass *base_class = G_TLS_CONNECTION_BASE_CLASS (klass);
288   GTlsConnectionOpensslClass *connection_class = G_TLS_CONNECTION_OPENSSL_CLASS (klass);
289
290   gobject_class->finalize     = g_tls_client_connection_openssl_finalize;
291   gobject_class->get_property = g_tls_client_connection_openssl_get_property;
292   gobject_class->set_property = g_tls_client_connection_openssl_set_property;
293   gobject_class->constructed  = g_tls_client_connection_openssl_constructed;
294
295   base_class->handshake          = g_tls_client_connection_openssl_handshake;
296   base_class->complete_handshake = g_tls_client_connection_openssl_complete_handshake;
297
298   connection_class->get_ssl = g_tls_client_connection_openssl_get_ssl;
299
300   g_object_class_override_property (gobject_class, PROP_VALIDATION_FLAGS, "validation-flags");
301   g_object_class_override_property (gobject_class, PROP_SERVER_IDENTITY, "server-identity");
302   g_object_class_override_property (gobject_class, PROP_USE_SSL3, "use-ssl3");
303   g_object_class_override_property (gobject_class, PROP_ACCEPTED_CAS, "accepted-cas");
304 }
305
306 static void
307 g_tls_client_connection_openssl_init (GTlsClientConnectionOpenssl *openssl)
308 {
309 }
310
311
312 static void
313 g_tls_client_connection_openssl_copy_session_state (GTlsClientConnection *conn,
314                                                     GTlsClientConnection *source)
315 {
316 }
317
318 static void
319 g_tls_client_connection_openssl_client_connection_interface_init (GTlsClientConnectionInterface *iface)
320 {
321   iface->copy_session_state = g_tls_client_connection_openssl_copy_session_state;
322 }
323
324 static int data_index = -1;
325 #ifdef TIZEN_EXT
326 G_LOCK_DEFINE_STATIC(data_index);
327 #define DATA_INDEX_LOCK(m) G_LOCK(m)
328 #define DATA_INDEX_UNLOCK(m) G_UNLOCK(m)
329 #else
330 #define DATA_INDEX_LOCK(m)
331 #define DATA_INDEX_UNLOCK(m)
332 #endif
333
334 static int
335 retrieve_certificate (SSL       *ssl,
336                       X509     **x509,
337                       EVP_PKEY **pkey)
338 {
339   GTlsClientConnectionOpenssl *client;
340   GTlsClientConnectionOpensslPrivate *priv;
341   GTlsConnectionBase *tls;
342   GTlsConnectionOpenssl *openssl;
343   GTlsCertificate *cert;
344   gboolean set_certificate = FALSE;
345
346   DATA_INDEX_LOCK(data_index);
347   int idx = data_index;
348   client = SSL_get_ex_data (ssl, data_index);
349   DATA_INDEX_UNLOCK(data_index);
350   if (!client)
351     {
352       TIZEN_LOGE("SSL_get_ex_data(%p) returns NULL.", ssl);
353       return 0;
354     }
355
356   tls = G_TLS_CONNECTION_BASE (client);
357   openssl = G_TLS_CONNECTION_OPENSSL (client);
358
359   priv = g_tls_client_connection_openssl_get_instance_private (client);
360
361   TIZEN_LOGI("ssl[%p] client[%p] tls[%p] openssl[%p] priv[%p] data_index[%d]",
362         ssl, client, tls, openssl, priv, idx);
363
364   tls->certificate_requested = TRUE;
365
366   priv->ca_list = SSL_get_client_CA_list (priv->ssl);
367   g_object_notify (G_OBJECT (client), "accepted-cas");
368
369   cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (client));
370   if (cert != NULL)
371     set_certificate = TRUE;
372   else
373     {
374       g_clear_error (&tls->certificate_error);
375       if (g_tls_connection_openssl_request_certificate (openssl, &tls->certificate_error))
376         {
377           cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (client));
378           set_certificate = (cert != NULL);
379         }
380     }
381
382   if (set_certificate)
383     {
384       EVP_PKEY *key;
385
386       key = g_tls_certificate_openssl_get_key (G_TLS_CERTIFICATE_OPENSSL (cert));
387       /* increase ref count */
388 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
389       CRYPTO_add (&key->references, 1, CRYPTO_LOCK_EVP_PKEY);
390 #else
391       EVP_PKEY_up_ref (key);
392 #endif
393       *pkey = key;
394
395       *x509 = X509_dup (g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (cert)));
396
397       return 1;
398     }
399
400   return 0;
401 }
402
403 static int
404 generate_session_id (SSL           *ssl,
405                      unsigned char *id,
406                      unsigned int  *id_len)
407 {
408   GTlsClientConnectionOpenssl *client;
409   GTlsClientConnectionOpensslPrivate *priv;
410   int len;
411
412   DATA_INDEX_LOCK(data_index);
413   int idx = data_index;
414   client = SSL_get_ex_data (ssl, data_index);
415   DATA_INDEX_UNLOCK(data_index);
416   priv = g_tls_client_connection_openssl_get_instance_private (client);
417
418   TIZEN_LOGI("ssl[%p] client[%p] priv[%p] data_index[%d]",
419                   ssl, client, priv, idx);
420
421   len = MIN (*id_len, g_bytes_get_size (priv->session_id));
422   memcpy (id, g_bytes_get_data (priv->session_id, NULL), len);
423
424   return 1;
425 }
426
427 static gboolean
428 set_cipher_list (GTlsClientConnectionOpenssl  *client,
429                  GError                      **error)
430 {
431   GTlsClientConnectionOpensslPrivate *priv;
432   const gchar *cipher_list;
433
434   priv = g_tls_client_connection_openssl_get_instance_private (client);
435
436   cipher_list = g_getenv ("G_TLS_OPENSSL_CIPHER_LIST");
437   if (cipher_list == NULL)
438     cipher_list = DEFAULT_CIPHER_LIST;
439
440   if (!SSL_CTX_set_cipher_list (priv->ssl_ctx, cipher_list))
441     {
442       g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
443                    _("Could not create TLS context: %s"),
444                    ERR_error_string (ERR_get_error (), NULL));
445       return FALSE;
446     }
447
448   return TRUE;
449 }
450
451 #ifdef SSL_CTX_set1_sigalgs_list
452 static void
453 set_signature_algorithm_list (GTlsClientConnectionOpenssl *client)
454 {
455   GTlsClientConnectionOpensslPrivate *priv;
456   const gchar *signature_algorithm_list;
457
458   priv = g_tls_client_connection_openssl_get_instance_private (client);
459
460   signature_algorithm_list = g_getenv ("G_TLS_OPENSSL_SIGNATURE_ALGORITHM_LIST");
461   if (signature_algorithm_list == NULL)
462     return;
463
464   SSL_CTX_set1_sigalgs_list (priv->ssl_ctx, signature_algorithm_list);
465 }
466 #endif
467
468 #ifdef SSL_CTX_set1_curves_list
469 static void
470 set_curve_list (GTlsClientConnectionOpenssl *client)
471 {
472   GTlsClientConnectionOpensslPrivate *priv;
473   const gchar *curve_list;
474
475   priv = g_tls_client_connection_openssl_get_instance_private (client);
476
477   curve_list = g_getenv ("G_TLS_OPENSSL_CURVE_LIST");
478   if (curve_list == NULL)
479     return;
480
481   SSL_CTX_set1_curves_list (priv->ssl_ctx, curve_list);
482 }
483 #endif
484
485 static gboolean
486 use_ocsp (void)
487 {
488   return g_getenv ("G_TLS_OPENSSL_OCSP_ENABLED") != NULL;
489 }
490
491 static gboolean
492 g_tls_client_connection_openssl_initable_init (GInitable       *initable,
493                                                GCancellable    *cancellable,
494                                                GError         **error)
495 {
496   GTlsClientConnectionOpenssl *client = G_TLS_CLIENT_CONNECTION_OPENSSL (initable);
497   GTlsClientConnectionOpensslPrivate *priv;
498   long options;
499   const char *hostname;
500
501   priv = g_tls_client_connection_openssl_get_instance_private (client);
502
503   priv->session = SSL_SESSION_new ();
504
505   priv->ssl_ctx = SSL_CTX_new (SSLv23_client_method ());
506   if (priv->ssl_ctx == NULL)
507     {
508       g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
509                    _("Could not create TLS context: %s"),
510                    ERR_error_string (ERR_get_error (), NULL));
511       return FALSE;
512     }
513
514   if (!set_cipher_list (client, error))
515     return FALSE;
516
517   /* Only TLS 1.2 or higher */
518   options = SSL_OP_NO_TICKET |
519             SSL_OP_NO_COMPRESSION |
520 #ifdef SSL_OP_NO_TLSv1_1
521             SSL_OP_NO_TLSv1_1 |
522 #endif
523             SSL_OP_NO_SSLv2 |
524             SSL_OP_NO_SSLv3 |
525             SSL_OP_NO_TLSv1;
526   SSL_CTX_set_options (priv->ssl_ctx, options);
527
528   SSL_CTX_clear_options (priv->ssl_ctx, SSL_OP_LEGACY_SERVER_CONNECT);
529
530   hostname = get_server_identity (client);
531
532 #if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined (LIBRESSL_VERSION_NUMBER)
533   if (hostname)
534     {
535       X509_VERIFY_PARAM *param;
536
537       param = X509_VERIFY_PARAM_new ();
538       X509_VERIFY_PARAM_set1_host (param, hostname, 0);
539       SSL_CTX_set1_param (priv->ssl_ctx, param);
540       X509_VERIFY_PARAM_free (param);
541     }
542 #endif
543
544   SSL_CTX_set_generate_session_id (priv->ssl_ctx, (GEN_SESSION_CB)generate_session_id);
545
546   SSL_CTX_add_session (priv->ssl_ctx, priv->session);
547
548   SSL_CTX_set_client_cert_cb (priv->ssl_ctx, retrieve_certificate);
549
550 #ifdef SSL_CTX_set1_sigalgs_list
551   set_signature_algorithm_list (client);
552 #endif
553
554 #ifdef SSL_CTX_set1_curves_list
555   set_curve_list (client);
556 #endif
557
558   priv->ssl = SSL_new (priv->ssl_ctx);
559   if (priv->ssl == NULL)
560     {
561       g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
562                    _("Could not create TLS connection: %s"),
563                    ERR_error_string (ERR_get_error (), NULL));
564       return FALSE;
565     }
566   DATA_INDEX_LOCK(data_index);
567   if (data_index == -1) {
568       data_index = SSL_get_ex_new_index (0, (void *)"gtlsclientconnection", NULL, NULL, NULL);
569           TIZEN_LOGI("new data_index[%d]", data_index);
570   } else {
571           TIZEN_LOGI("data_index[%d] is already exist", data_index);
572   }
573   SSL_set_ex_data (priv->ssl, data_index, client);
574   TIZEN_LOGI("[SSL] set extra data: priv->ssl[%p] data_index[%d] client[%p]", priv->ssl, data_index, client);
575   DATA_INDEX_UNLOCK(data_index);
576 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
577   if (hostname)
578     SSL_set_tlsext_host_name (priv->ssl, hostname);
579 #endif
580
581   SSL_set_connect_state (priv->ssl);
582
583 #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
584     !defined(OPENSSL_NO_OCSP)
585   if (use_ocsp())
586     SSL_set_tlsext_status_type (priv->ssl, TLSEXT_STATUSTYPE_ocsp);
587 #endif
588
589   if (!g_tls_client_connection_openssl_parent_initable_iface->
590       init (initable, cancellable, error))
591     return FALSE;
592
593   return TRUE;
594 }
595
596 static void
597 g_tls_client_connection_openssl_initable_interface_init (GInitableIface  *iface)
598 {
599   g_tls_client_connection_openssl_parent_initable_iface = g_type_interface_peek_parent (iface);
600
601   iface->init = g_tls_client_connection_openssl_initable_init;
602 }