diff options
Diffstat (limited to 'tls/gnutls')
-rw-r--r-- | tls/gnutls/gtlsbackend-gnutls.c | 109 | ||||
-rw-r--r-- | tls/gnutls/gtlsbackend-gnutls.h | 4 | ||||
-rw-r--r-- | tls/gnutls/gtlsclientconnection-gnutls.c | 115 | ||||
-rw-r--r-- | tls/gnutls/gtlsconnection-gnutls.c | 2 | ||||
-rw-r--r-- | tls/gnutls/gtlsconnection-gnutls.h | 2 |
5 files changed, 32 insertions, 200 deletions
diff --git a/tls/gnutls/gtlsbackend-gnutls.c b/tls/gnutls/gtlsbackend-gnutls.c index 65a8db8..d5276cb 100644 --- a/tls/gnutls/gtlsbackend-gnutls.c +++ b/tls/gnutls/gtlsbackend-gnutls.c @@ -165,115 +165,6 @@ g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface) iface->get_dtls_server_connection_type = g_tls_server_connection_gnutls_get_type; } -/* Session cache support. We try to be careful of TLS session tracking - * and so have adopted the recommendations of arXiv:1810.07304 section 6 - * in using a 10-minute cache lifetime and in never updating the - * expiration time of cache entries when they are accessed to ensure a - * new session gets used after 10 minutes even if the cached one was - * resumed more recently. - * - * https://arxiv.org/abs/1810.07304 - */ - -G_LOCK_DEFINE_STATIC (session_cache_lock); -GHashTable *client_session_cache; /* (owned) GBytes -> (owned) GTlsBackendGnutlsCacheData */ - -#define SESSION_CACHE_MAX_SIZE 50 -#define SESSION_CACHE_MAX_AGE (10ll * 60ll * G_USEC_PER_SEC) /* ten minutes */ - -typedef struct { - GQueue *session_tickets; /* (owned) GBytes */ - gint64 expiration_time; -} GTlsBackendGnutlsCacheData; - -static void -session_cache_cleanup (GHashTable *cache) -{ - GHashTableIter iter; - gpointer key, value; - GTlsBackendGnutlsCacheData *cache_data; - - g_hash_table_iter_init (&iter, cache); - while (g_hash_table_iter_next (&iter, &key, &value)) - { - cache_data = value; - if (g_get_monotonic_time () > cache_data->expiration_time) - g_hash_table_iter_remove (&iter); - } -} - -static void -cache_data_free (GTlsBackendGnutlsCacheData *data) -{ - g_queue_free_full (data->session_tickets, (GDestroyNotify)g_bytes_unref); - g_free (data); -} - -static GHashTable * -get_session_cache (gboolean create) -{ - if (!client_session_cache && create) - { - client_session_cache = g_hash_table_new_full (g_bytes_hash, g_bytes_equal, - (GDestroyNotify)g_bytes_unref, (GDestroyNotify)cache_data_free); - } - return client_session_cache; -} - -void -g_tls_backend_gnutls_store_session_data (GBytes *session_id, - GBytes *session_data) -{ - GTlsBackendGnutlsCacheData *cache_data; - GHashTable *cache; - - G_LOCK (session_cache_lock); - - cache = get_session_cache (TRUE); - cache_data = g_hash_table_lookup (cache, session_id); - if (!cache_data) - { - if (g_hash_table_size (cache) >= SESSION_CACHE_MAX_SIZE) - session_cache_cleanup (cache); - - cache_data = g_new (GTlsBackendGnutlsCacheData, 1); - cache_data->session_tickets = g_queue_new (); - g_hash_table_insert (cache, g_bytes_ref (session_id), cache_data); - } - - g_queue_push_tail (cache_data->session_tickets, g_bytes_ref (session_data)); - cache_data->expiration_time = g_get_monotonic_time () + SESSION_CACHE_MAX_AGE; - - G_UNLOCK (session_cache_lock); -} - -GBytes * -g_tls_backend_gnutls_lookup_session_data (GBytes *session_id) -{ - GTlsBackendGnutlsCacheData *cache_data; - GBytes *session_data = NULL; - GHashTable *cache; - - G_LOCK (session_cache_lock); - - cache = get_session_cache (FALSE); - if (cache) - { - cache_data = g_hash_table_lookup (cache, session_id); - if (cache_data) - { - /* Note that session tickets should be used only once since TLS 1.3, - * so we remove from the queue after retrieval. See RFC 8446 §C.4. - */ - session_data = g_queue_pop_head (cache_data->session_tickets); - } - } - - G_UNLOCK (session_cache_lock); - - return session_data; -} - void g_tls_backend_gnutls_register (GIOModule *module) { diff --git a/tls/gnutls/gtlsbackend-gnutls.h b/tls/gnutls/gtlsbackend-gnutls.h index fb33361..b05f863 100644 --- a/tls/gnutls/gtlsbackend-gnutls.h +++ b/tls/gnutls/gtlsbackend-gnutls.h @@ -35,8 +35,4 @@ G_DECLARE_FINAL_TYPE (GTlsBackendGnutls, g_tls_backend_gnutls, G, TLS_BACKEND_GN void g_tls_backend_gnutls_register (GIOModule *module); -void g_tls_backend_gnutls_store_session_data (GBytes *session_id, - GBytes *session_data); -GBytes *g_tls_backend_gnutls_lookup_session_data (GBytes *session_id); - G_END_DECLS diff --git a/tls/gnutls/gtlsclientconnection-gnutls.c b/tls/gnutls/gtlsclientconnection-gnutls.c index 39b06d7..17394d5 100644 --- a/tls/gnutls/gtlsclientconnection-gnutls.c +++ b/tls/gnutls/gtlsclientconnection-gnutls.c @@ -31,6 +31,8 @@ #include <string.h> #include "gtlsconnection-base.h" +#include "gtlsconnection-gnutls.h" +#include "gtlssessioncache.h" #include "gtlsclientconnection-gnutls.h" #include "gtlsbackend-gnutls.h" #include "gtlscertificate-gnutls.h" @@ -43,6 +45,7 @@ enum PROP_SERVER_IDENTITY, PROP_USE_SSL3, PROP_ACCEPTED_CAS, + PROP_SESSION_RESUMPTION_ENABLED, PROP_SESSION_REUSED }; @@ -54,13 +57,14 @@ struct _GTlsClientConnectionGnutls GSocketConnectable *server_identity; gboolean use_ssl3; gboolean session_reused; + gboolean session_resumption_enabled; /* session_data is either the session ticket that was used to resume this * connection, or the most recent session ticket received from the server. * Because session ticket reuse is generally undesirable, it should only be * accessed if session_data_override is set. */ - GBytes *session_id; + gchar *session_id; GBytes *session_data; gboolean session_data_override; @@ -111,6 +115,8 @@ clear_gnutls_certificate_copy (gnutls_pcert_st **pcert, static void g_tls_client_connection_gnutls_init (GTlsClientConnectionGnutls *gnutls) { + gnutls->session_reused = FALSE; + gnutls->session_resumption_enabled = !g_test_initialized (); } static const gchar * @@ -124,85 +130,10 @@ get_server_identity (GTlsClientConnectionGnutls *gnutls) return NULL; } -static void -g_tls_client_connection_gnutls_compute_session_id (GTlsClientConnectionGnutls *gnutls) +static int session_inc_ref (gpointer data) { - GSocketConnection *base_conn; - GSocketAddress *remote_addr; - GInetAddress *iaddr; - guint port; - - /* The testsuite expects handshakes to actually happen. E.g. a test might - * check to see that a handshake succeeds and then later check that a new - * handshake fails. If we get really unlucky and the same port number is - * reused for the server socket between connections, then we'll accidentally - * resume the old session and skip certificate verification. Such failures - * are difficult to debug because they require running the tests hundreds of - * times simultaneously to reproduce (the port number does not get reused - * quickly enough if the tests are run sequentially). - * - * So session resumption will just need to be tested manually. - */ - if (g_test_initialized ()) - return; - - /* Create a TLS "session ID." We base it on the IP address since - * different hosts serving the same hostname/service will probably - * not share the same session cache. We base it on the - * server-identity because at least some servers will fail (rather - * than just failing to resume the session) if we don't. - * (https://bugs.launchpad.net/bugs/823325) - * - * Note that our session IDs have no relation to TLS protocol - * session IDs, e.g. as provided by gnutls_session_get_id2(). Unlike - * our session IDs, actual TLS session IDs can no longer be used for - * session resumption. - */ - g_object_get (G_OBJECT (gnutls), "base-io-stream", &base_conn, NULL); - if (G_IS_SOCKET_CONNECTION (base_conn)) - { - remote_addr = g_socket_connection_get_remote_address (base_conn, NULL); - if (G_IS_INET_SOCKET_ADDRESS (remote_addr)) - { - GInetSocketAddress *isaddr = G_INET_SOCKET_ADDRESS (remote_addr); - const gchar *server_hostname; - gchar *addrstr, *session_id; - GTlsCertificate *cert = NULL; - gchar *cert_hash = NULL; - - iaddr = g_inet_socket_address_get_address (isaddr); - port = g_inet_socket_address_get_port (isaddr); - - addrstr = g_inet_address_to_string (iaddr); - server_hostname = get_server_identity (gnutls); - - /* If we have a certificate, make its hash part of the session ID, so - * that different connections to the same server can use different - * certificates. - */ - g_object_get (G_OBJECT (gnutls), "certificate", &cert, NULL); - if (cert) - { - GByteArray *der = NULL; - g_object_get (G_OBJECT (cert), "certificate", &der, NULL); - if (der) - { - cert_hash = g_compute_checksum_for_data (G_CHECKSUM_SHA256, der->data, der->len); - g_byte_array_unref (der); - } - g_object_unref (cert); - } - session_id = g_strdup_printf ("%s/%s/%d/%s", addrstr, - server_hostname ? server_hostname : "", - port, - cert_hash ? cert_hash : ""); - gnutls->session_id = g_bytes_new_take (session_id, strlen (session_id)); - g_free (addrstr); - g_free (cert_hash); - } - g_object_unref (remote_addr); - } - g_clear_object (&base_conn); + g_bytes_ref (data); + return 1; } static int @@ -223,10 +154,14 @@ handshake_thread_session_ticket_received_cb (gnutls_session_t session, (GDestroyNotify)gnutls_free, session_datum.data); - if (gnutls->session_id) + if (gnutls->session_resumption_enabled && gnutls->session_id) { - g_tls_backend_gnutls_store_session_data (gnutls->session_id, - gnutls->session_data); + g_tls_store_session_data (gnutls->session_id, + (gpointer)gnutls->session_data, + (SessionDup)g_bytes_ref, + (SessionAcquire)session_inc_ref, + (SessionRelease)g_bytes_unref, + glib_protocol_version_from_gnutls (gnutls_protocol_get_version (session))); } } @@ -240,7 +175,6 @@ g_tls_client_connection_gnutls_finalize (GObject *object) g_clear_object (&gnutls->server_identity); g_clear_pointer (&gnutls->accepted_cas, g_ptr_array_unref); - g_clear_pointer (&gnutls->session_id, g_bytes_unref); g_clear_pointer (&gnutls->session_data, g_bytes_unref); clear_gnutls_certificate_copy (&gnutls->pcert, &gnutls->pcert_length, &gnutls->pkey); @@ -327,6 +261,10 @@ g_tls_client_connection_gnutls_get_property (GObject *object, g_value_set_boolean (value, gnutls->session_reused); break; + case PROP_SESSION_RESUMPTION_ENABLED: + g_value_set_boolean (value, gnutls->session_resumption_enabled); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -378,6 +316,10 @@ g_tls_client_connection_gnutls_set_property (GObject *object, gnutls->use_ssl3 = g_value_get_boolean (value); break; + case PROP_SESSION_RESUMPTION_ENABLED: + gnutls->session_resumption_enabled = g_value_get_boolean (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -470,7 +412,7 @@ g_tls_client_connection_gnutls_prepare_handshake (GTlsConnectionBase *tls, { GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (tls); - g_tls_client_connection_gnutls_compute_session_id (gnutls); + gnutls->session_id = g_tls_connection_base_get_session_id (G_TLS_CONNECTION_BASE (gnutls)); if (gnutls->session_data_override) { @@ -483,7 +425,7 @@ g_tls_client_connection_gnutls_prepare_handshake (GTlsConnectionBase *tls, { GBytes *session_data; - session_data = g_tls_backend_gnutls_lookup_session_data (gnutls->session_id); + session_data = (GBytes *)g_tls_lookup_session_data (gnutls->session_id); if (session_data) { gnutls_session_set_data (g_tls_connection_gnutls_get_session (G_TLS_CONNECTION_GNUTLS (tls)), @@ -565,7 +507,7 @@ g_tls_client_connection_gnutls_copy_session_state (GTlsClientConnection *conn, g_return_if_fail (!gnutls->session_data); /* Prefer to use a new session ticket, if possible. */ - gnutls->session_data = g_tls_backend_gnutls_lookup_session_data (gnutls_source->session_id); + gnutls->session_data = g_tls_lookup_session_data (gnutls_source->session_id); if (!gnutls->session_data && gnutls_source->session_data) { @@ -609,6 +551,7 @@ g_tls_client_connection_gnutls_class_init (GTlsClientConnectionGnutlsClass *klas g_object_class_override_property (gobject_class, PROP_USE_SSL3, "use-ssl3"); g_object_class_override_property (gobject_class, PROP_ACCEPTED_CAS, "accepted-cas"); g_object_class_override_property (gobject_class, PROP_SESSION_REUSED, "session-reused"); + g_object_class_override_property (gobject_class, PROP_SESSION_RESUMPTION_ENABLED, "session-resumption-enabled"); } static void diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c index 56bb37f..984520c 100644 --- a/tls/gnutls/gtlsconnection-gnutls.c +++ b/tls/gnutls/gtlsconnection-gnutls.c @@ -1069,7 +1069,7 @@ g_tls_connection_gnutls_verify_chain (GTlsConnectionBase *tls, return errors; } -static GTlsProtocolVersion +GTlsProtocolVersion glib_protocol_version_from_gnutls (gnutls_protocol_t protocol_version) { switch (protocol_version) diff --git a/tls/gnutls/gtlsconnection-gnutls.h b/tls/gnutls/gtlsconnection-gnutls.h index 16ec747..3a14103 100644 --- a/tls/gnutls/gtlsconnection-gnutls.h +++ b/tls/gnutls/gtlsconnection-gnutls.h @@ -53,4 +53,6 @@ void g_tls_connection_gnutls_handshake_thread_get_certificate (GTlsConne unsigned int *pcert_length, gnutls_privkey_t *pkey); +GTlsProtocolVersion glib_protocol_version_from_gnutls (gnutls_protocol_t protocol_version); + G_END_DECLS |