1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3 * GIO - GLib Input, Output and Streaming Library
5 * Copyright 2010 Red Hat, Inc
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.
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.
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/>.
21 * In addition, when the library is used with OpenSSL, a special
22 * exception applies. Refer to the LICENSE_EXCEPTION file for details.
29 #include <gnutls/gnutls.h>
30 #include <gnutls/x509.h>
33 #include "gtlsconnection-base.h"
34 #include "gtlsclientconnection-gnutls.h"
35 #include "gtlsbackend-gnutls.h"
36 #include "gtlscertificate-gnutls.h"
37 #include <glib/gi18n-lib.h>
42 PROP_VALIDATION_FLAGS,
48 struct _GTlsClientConnectionGnutls
50 GTlsConnectionGnutls parent_instance;
52 GTlsCertificateFlags validation_flags;
53 GSocketConnectable *server_identity;
56 /* session_data is either the session ticket that was used to resume this
57 * connection, or the most recent session ticket received from the server.
58 * Because session ticket reuse is generally undesirable, it should only be
59 * accessed if session_data_override is set.
63 gboolean session_data_override;
65 GPtrArray *accepted_cas;
66 gboolean accepted_cas_changed;
68 gnutls_pcert_st *pcert;
69 unsigned int pcert_length;
70 gnutls_privkey_t pkey;
73 static void g_tls_client_connection_gnutls_initable_interface_init (GInitableIface *iface);
75 static void g_tls_client_connection_gnutls_client_connection_interface_init (GTlsClientConnectionInterface *iface);
76 static void g_tls_client_connection_gnutls_dtls_client_connection_interface_init (GDtlsClientConnectionInterface *iface);
78 static int g_tls_client_connection_gnutls_handshake_thread_retrieve_function (gnutls_session_t session,
79 const gnutls_datum_t *req_ca_rdn,
81 const gnutls_pk_algorithm_t *pk_algos,
83 gnutls_pcert_st **pcert,
84 unsigned int *pcert_length,
85 gnutls_privkey_t *pkey);
87 static GInitableIface *g_tls_client_connection_gnutls_parent_initable_iface;
89 G_DEFINE_TYPE_WITH_CODE (GTlsClientConnectionGnutls, g_tls_client_connection_gnutls, G_TYPE_TLS_CONNECTION_GNUTLS,
90 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
91 g_tls_client_connection_gnutls_initable_interface_init)
92 G_IMPLEMENT_INTERFACE (G_TYPE_TLS_CLIENT_CONNECTION,
93 g_tls_client_connection_gnutls_client_connection_interface_init);
94 G_IMPLEMENT_INTERFACE (G_TYPE_DTLS_CLIENT_CONNECTION,
95 g_tls_client_connection_gnutls_dtls_client_connection_interface_init));
98 clear_gnutls_certificate_copy (gnutls_pcert_st **pcert,
100 gnutls_privkey_t *pkey)
102 g_tls_certificate_gnutls_copy_free (*pcert, *pcert_length, *pkey);
110 g_tls_client_connection_gnutls_init (GTlsClientConnectionGnutls *gnutls)
115 get_server_identity (GTlsClientConnectionGnutls *gnutls)
117 if (G_IS_NETWORK_ADDRESS (gnutls->server_identity))
118 return g_network_address_get_hostname (G_NETWORK_ADDRESS (gnutls->server_identity));
119 else if (G_IS_NETWORK_SERVICE (gnutls->server_identity))
120 return g_network_service_get_domain (G_NETWORK_SERVICE (gnutls->server_identity));
126 g_tls_client_connection_gnutls_compute_session_id (GTlsClientConnectionGnutls *gnutls)
128 GSocketConnection *base_conn;
129 GSocketAddress *remote_addr;
133 /* The testsuite expects handshakes to actually happen. E.g. a test might
134 * check to see that a handshake succeeds and then later check that a new
135 * handshake fails. If we get really unlucky and the same port number is
136 * reused for the server socket between connections, then we'll accidentally
137 * resume the old session and skip certificate verification. Such failures
138 * are difficult to debug because they require running the tests hundreds of
139 * times simultaneously to reproduce (the port number does not get reused
140 * quickly enough if the tests are run sequentially).
142 * So session resumption will just need to be tested manually.
144 if (g_test_initialized ())
147 /* Create a TLS "session ID." We base it on the IP address since
148 * different hosts serving the same hostname/service will probably
149 * not share the same session cache. We base it on the
150 * server-identity because at least some servers will fail (rather
151 * than just failing to resume the session) if we don't.
152 * (https://bugs.launchpad.net/bugs/823325)
154 * Note that our session IDs have no relation to TLS protocol
155 * session IDs, e.g. as provided by gnutls_session_get_id2(). Unlike
156 * our session IDs, actual TLS session IDs can no longer be used for
157 * session resumption.
159 g_object_get (G_OBJECT (gnutls), "base-io-stream", &base_conn, NULL);
160 if (G_IS_SOCKET_CONNECTION (base_conn))
162 remote_addr = g_socket_connection_get_remote_address (base_conn, NULL);
163 if (G_IS_INET_SOCKET_ADDRESS (remote_addr))
165 GInetSocketAddress *isaddr = G_INET_SOCKET_ADDRESS (remote_addr);
166 const gchar *server_hostname;
167 gchar *addrstr, *session_id;
168 GTlsCertificate *cert = NULL;
169 gchar *cert_hash = NULL;
171 iaddr = g_inet_socket_address_get_address (isaddr);
172 port = g_inet_socket_address_get_port (isaddr);
174 addrstr = g_inet_address_to_string (iaddr);
175 server_hostname = get_server_identity (gnutls);
177 /* If we have a certificate, make its hash part of the session ID, so
178 * that different connections to the same server can use different
181 g_object_get (G_OBJECT (gnutls), "certificate", &cert, NULL);
184 GByteArray *der = NULL;
185 g_object_get (G_OBJECT (cert), "certificate", &der, NULL);
188 cert_hash = g_compute_checksum_for_data (G_CHECKSUM_SHA256, der->data, der->len);
189 g_byte_array_unref (der);
191 g_object_unref (cert);
193 session_id = g_strdup_printf ("%s/%s/%d/%s", addrstr,
194 server_hostname ? server_hostname : "",
196 cert_hash ? cert_hash : "");
197 gnutls->session_id = g_bytes_new_take (session_id, strlen (session_id));
201 g_object_unref (remote_addr);
203 g_clear_object (&base_conn);
207 handshake_thread_session_ticket_received_cb (gnutls_session_t session,
211 const gnutls_datum_t *msg)
213 GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (gnutls_session_get_ptr (session));
214 gnutls_datum_t session_datum;
216 if (gnutls_session_get_data2 (session, &session_datum) == GNUTLS_E_SUCCESS)
218 g_clear_pointer (&gnutls->session_data, g_bytes_unref);
219 gnutls->session_data = g_bytes_new_with_free_func (session_datum.data,
221 (GDestroyNotify)gnutls_free,
224 if (gnutls->session_id)
226 g_tls_backend_gnutls_store_session_data (gnutls->session_id,
227 gnutls->session_data);
235 g_tls_client_connection_gnutls_finalize (GObject *object)
237 GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (object);
239 g_clear_object (&gnutls->server_identity);
240 g_clear_pointer (&gnutls->accepted_cas, g_ptr_array_unref);
241 g_clear_pointer (&gnutls->session_id, g_bytes_unref);
242 g_clear_pointer (&gnutls->session_data, g_bytes_unref);
244 clear_gnutls_certificate_copy (&gnutls->pcert, &gnutls->pcert_length, &gnutls->pkey);
246 G_OBJECT_CLASS (g_tls_client_connection_gnutls_parent_class)->finalize (object);
250 g_tls_client_connection_gnutls_initable_init (GInitable *initable,
251 GCancellable *cancellable,
254 GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (initable);
255 gnutls_session_t session;
256 const gchar *hostname;
257 gnutls_certificate_credentials_t creds;
259 if (!g_tls_client_connection_gnutls_parent_initable_iface->init (initable, cancellable, error))
262 creds = g_tls_connection_gnutls_get_credentials (G_TLS_CONNECTION_GNUTLS (gnutls));
263 gnutls_certificate_set_retrieve_function2 (creds, g_tls_client_connection_gnutls_handshake_thread_retrieve_function);
265 session = g_tls_connection_gnutls_get_session (gnutls);
266 hostname = get_server_identity (G_TLS_CLIENT_CONNECTION_GNUTLS (gnutls));
269 gchar *normalized_hostname = g_strdup (hostname);
271 if (hostname[strlen (hostname) - 1] == '.')
272 normalized_hostname[strlen (hostname) - 1] = '\0';
274 gnutls_server_name_set (session, GNUTLS_NAME_DNS,
275 normalized_hostname, strlen (normalized_hostname));
277 g_free (normalized_hostname);
280 gnutls_handshake_set_hook_function (session, GNUTLS_HANDSHAKE_NEW_SESSION_TICKET,
281 GNUTLS_HOOK_POST, handshake_thread_session_ticket_received_cb);
287 g_tls_client_connection_gnutls_get_property (GObject *object,
292 GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (object);
298 case PROP_VALIDATION_FLAGS:
299 g_value_set_flags (value, gnutls->validation_flags);
302 case PROP_SERVER_IDENTITY:
303 g_value_set_object (value, gnutls->server_identity);
307 g_value_set_boolean (value, gnutls->use_ssl3);
310 case PROP_ACCEPTED_CAS:
312 if (gnutls->accepted_cas)
314 for (i = 0; i < gnutls->accepted_cas->len; ++i)
316 accepted_cas = g_list_prepend (accepted_cas, g_byte_array_ref (
317 gnutls->accepted_cas->pdata[i]));
319 accepted_cas = g_list_reverse (accepted_cas);
321 g_value_set_pointer (value, accepted_cas);
325 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
330 g_tls_client_connection_gnutls_set_property (GObject *object,
335 GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (object);
336 const char *hostname;
340 case PROP_VALIDATION_FLAGS:
341 gnutls->validation_flags = g_value_get_flags (value);
344 case PROP_SERVER_IDENTITY:
345 if (gnutls->server_identity)
346 g_object_unref (gnutls->server_identity);
347 gnutls->server_identity = g_value_dup_object (value);
349 hostname = get_server_identity (gnutls);
350 if (hostname && !g_hostname_is_ip_address (hostname))
352 gnutls_session_t session = g_tls_connection_gnutls_get_session (G_TLS_CONNECTION_GNUTLS (gnutls));
354 /* This will only be triggered if the identity is set after
358 gchar *normalized_hostname = g_strdup (hostname);
360 if (hostname[strlen (hostname) - 1] == '.')
361 normalized_hostname[strlen (hostname) - 1] = '\0';
363 gnutls_server_name_set (session, GNUTLS_NAME_DNS,
364 normalized_hostname, strlen (normalized_hostname));
366 g_free (normalized_hostname);
372 gnutls->use_ssl3 = g_value_get_boolean (value);
376 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
381 g_tls_client_connection_gnutls_handshake_thread_retrieve_function (gnutls_session_t session,
382 const gnutls_datum_t *req_ca_rdn,
384 const gnutls_pk_algorithm_t *pk_algos,
386 gnutls_pcert_st **pcert,
387 unsigned int *pcert_length,
388 gnutls_privkey_t *pkey)
390 GTlsConnectionBase *tls = gnutls_transport_get_ptr (session);
391 GTlsClientConnectionGnutls *gnutls = gnutls_transport_get_ptr (session);
392 GTlsConnectionGnutls *conn = G_TLS_CONNECTION_GNUTLS (gnutls);
393 GPtrArray *accepted_cas;
394 gboolean had_accepted_cas;
398 /* FIXME: Here we are supposed to ensure that the certificate supports one of
399 * the algorithms given in pk_algos.
402 had_accepted_cas = gnutls->accepted_cas != NULL;
404 accepted_cas = g_ptr_array_new_with_free_func ((GDestroyNotify)g_byte_array_unref);
405 for (i = 0; i < nreqs; i++)
407 dn = g_byte_array_new ();
408 g_byte_array_append (dn, req_ca_rdn[i].data, req_ca_rdn[i].size);
409 g_ptr_array_add (accepted_cas, dn);
412 if (gnutls->accepted_cas)
413 g_ptr_array_unref (gnutls->accepted_cas);
414 gnutls->accepted_cas = accepted_cas;
416 gnutls->accepted_cas_changed = gnutls->accepted_cas || had_accepted_cas;
418 clear_gnutls_certificate_copy (&gnutls->pcert, &gnutls->pcert_length, &gnutls->pkey);
419 g_tls_connection_gnutls_handshake_thread_get_certificate (conn, pcert, pcert_length, pkey);
421 if (*pcert_length == 0)
423 clear_gnutls_certificate_copy (pcert, pcert_length, pkey);
425 if (g_tls_connection_base_handshake_thread_request_certificate (tls))
426 g_tls_connection_gnutls_handshake_thread_get_certificate (conn, pcert, pcert_length, pkey);
428 if (*pcert_length == 0)
430 clear_gnutls_certificate_copy (pcert, pcert_length, pkey);
432 /* If there is still no client certificate, this connection will
433 * probably fail, but we must not give up yet. The certificate might
434 * be optional, e.g. if the server is using
435 * G_TLS_AUTHENTICATION_REQUESTED, not G_TLS_AUTHENTICATION_REQUIRED.
437 g_tls_connection_base_handshake_thread_set_missing_requested_client_certificate (tls);
444 clear_gnutls_certificate_copy (pcert, pcert_length, pkey);
446 /* No private key. GnuTLS expects it to be non-null if pcert_length is
447 * nonzero, so we have to abort now.
449 g_tls_connection_base_handshake_thread_set_missing_requested_client_certificate (tls);
453 /* We'll assume ownership. The return values are unowned. */
454 gnutls->pcert = *pcert;
455 gnutls->pcert_length = *pcert_length;
456 gnutls->pkey = *pkey;
462 g_tls_client_connection_gnutls_prepare_handshake (GTlsConnectionBase *tls,
463 gchar **advertised_protocols)
465 GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (tls);
467 g_tls_client_connection_gnutls_compute_session_id (gnutls);
469 if (gnutls->session_data_override)
471 g_assert (gnutls->session_data);
472 gnutls_session_set_data (g_tls_connection_gnutls_get_session (G_TLS_CONNECTION_GNUTLS (tls)),
473 g_bytes_get_data (gnutls->session_data, NULL),
474 g_bytes_get_size (gnutls->session_data));
476 else if (gnutls->session_id)
478 GBytes *session_data;
480 session_data = g_tls_backend_gnutls_lookup_session_data (gnutls->session_id);
483 gnutls_session_set_data (g_tls_connection_gnutls_get_session (G_TLS_CONNECTION_GNUTLS (tls)),
484 g_bytes_get_data (session_data, NULL),
485 g_bytes_get_size (session_data));
486 g_clear_pointer (&gnutls->session_data, g_bytes_unref);
487 gnutls->session_data = g_steal_pointer (&session_data);
491 G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_gnutls_parent_class)->
492 prepare_handshake (tls, advertised_protocols);
496 g_tls_client_connection_gnutls_complete_handshake (GTlsConnectionBase *tls,
497 gboolean handshake_succeeded,
498 gchar **negotiated_protocol,
499 GTlsProtocolVersion *protocol_version,
500 gchar **ciphersuite_name,
503 GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (tls);
504 gnutls_session_t session;
505 gnutls_protocol_t version;
507 G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_gnutls_parent_class)->complete_handshake (tls,
514 /* It may have changed during the handshake, but we have to wait until here
515 * because we can't emit notifies on the handshake thread.
517 if (gnutls->accepted_cas_changed)
518 g_object_notify (G_OBJECT (gnutls), "accepted-cas");
520 if (handshake_succeeded)
522 /* If we're not using TLS 1.3, store the session ticket here. We
523 * don't normally perform session resumption in TLS 1.2, but we still
524 * support it if the application calls copy_session_state() (which
525 * doesn't exist for DTLS, so do this for TLS only).
527 * Note to distant future: remove this when dropping TLS 1.2 support.
529 session = g_tls_connection_gnutls_get_session (G_TLS_CONNECTION_GNUTLS (tls));
530 version = gnutls_protocol_get_version (session);
531 if (version <= GNUTLS_TLS1_2 && !g_tls_connection_base_is_dtls (tls))
533 gnutls_datum_t session_datum;
535 if (gnutls_session_get_data2 (g_tls_connection_gnutls_get_session (G_TLS_CONNECTION_GNUTLS (tls)),
536 &session_datum) == 0)
538 g_clear_pointer (&gnutls->session_data, g_bytes_unref);
539 gnutls->session_data = g_bytes_new_with_free_func (session_datum.data,
541 (GDestroyNotify)gnutls_free,
549 g_tls_client_connection_gnutls_copy_session_state (GTlsClientConnection *conn,
550 GTlsClientConnection *source)
552 GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (conn);
553 GTlsClientConnectionGnutls *gnutls_source = G_TLS_CLIENT_CONNECTION_GNUTLS (source);
555 /* Precondition: source has handshaked, conn has not. */
556 g_return_if_fail (!gnutls->session_id);
557 g_return_if_fail (gnutls_source->session_id);
558 g_return_if_fail (!gnutls->session_data);
560 /* Prefer to use a new session ticket, if possible. */
561 gnutls->session_data = g_tls_backend_gnutls_lookup_session_data (gnutls_source->session_id);
563 if (!gnutls->session_data && gnutls_source->session_data)
565 /* If it's not possible, we'll try to reuse the old ticket, even though
566 * this is a privacy risk. Applications should not use this function
567 * unless they need us to try as hard as possible to resume a session,
568 * even at the cost of privacy.
570 gnutls->session_data = g_bytes_ref (gnutls_source->session_data);
573 gnutls->session_data_override = !!gnutls->session_data;
577 g_tls_client_connection_gnutls_update_credentials (GTlsConnectionGnutls *gnutls,
578 gnutls_certificate_credentials_t credentials)
580 gnutls_certificate_set_retrieve_function2 (credentials, g_tls_client_connection_gnutls_handshake_thread_retrieve_function);
584 g_tls_client_connection_gnutls_class_init (GTlsClientConnectionGnutlsClass *klass)
586 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
587 GTlsConnectionBaseClass *base_class = G_TLS_CONNECTION_BASE_CLASS (klass);
588 GTlsConnectionGnutlsClass *gnutls_class = G_TLS_CONNECTION_GNUTLS_CLASS (klass);
590 gobject_class->get_property = g_tls_client_connection_gnutls_get_property;
591 gobject_class->set_property = g_tls_client_connection_gnutls_set_property;
592 gobject_class->finalize = g_tls_client_connection_gnutls_finalize;
594 base_class->prepare_handshake = g_tls_client_connection_gnutls_prepare_handshake;
595 base_class->complete_handshake = g_tls_client_connection_gnutls_complete_handshake;
597 gnutls_class->update_credentials = g_tls_client_connection_gnutls_update_credentials;
599 g_object_class_override_property (gobject_class, PROP_VALIDATION_FLAGS, "validation-flags");
600 g_object_class_override_property (gobject_class, PROP_SERVER_IDENTITY, "server-identity");
601 g_object_class_override_property (gobject_class, PROP_USE_SSL3, "use-ssl3");
602 g_object_class_override_property (gobject_class, PROP_ACCEPTED_CAS, "accepted-cas");
606 g_tls_client_connection_gnutls_client_connection_interface_init (GTlsClientConnectionInterface *iface)
608 iface->copy_session_state = g_tls_client_connection_gnutls_copy_session_state;
612 g_tls_client_connection_gnutls_initable_interface_init (GInitableIface *iface)
614 g_tls_client_connection_gnutls_parent_initable_iface = g_type_interface_peek_parent (iface);
616 iface->init = g_tls_client_connection_gnutls_initable_init;
620 g_tls_client_connection_gnutls_dtls_client_connection_interface_init (GDtlsClientConnectionInterface *iface)