summaryrefslogtreecommitdiff
path: root/tls/gnutls
diff options
context:
space:
mode:
Diffstat (limited to 'tls/gnutls')
-rw-r--r--tls/gnutls/gtlsbackend-gnutls.c109
-rw-r--r--tls/gnutls/gtlsbackend-gnutls.h4
-rw-r--r--tls/gnutls/gtlsclientconnection-gnutls.c115
-rw-r--r--tls/gnutls/gtlsconnection-gnutls.c2
-rw-r--r--tls/gnutls/gtlsconnection-gnutls.h2
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