summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGoncalo Gomes <goncalo.gomes@youview.com>2022-09-01 11:40:34 +0100
committerMarge Bot <marge-bot@gnome.org>2022-09-12 15:46:51 +0000
commit13b9f541e0e2059de732049e994a5bdb27f232d3 (patch)
treee4afec4fc5b2590defaa8fd19c2581cd090b2490
parent4be360a85761e4b83aa851bc7413698b3155ffb3 (diff)
downloadglib-networking-13b9f541e0e2059de732049e994a5bdb27f232d3.tar.gz
Created a common implementation for TLS session cache
There are too many similarities between GnuTLS session ID and the session cache, so it is desirable to merge the implementations so that it is easier to maintain and leads to more similar behaviours across backends. This commit moves the OpenSSL backend session cache implementation to the base class as well as the session id calculation. In GnuTLS the session id is also used to assert that the copy session state is done properly (before handshake of the new class and after handshake of the old class). That behaviour was maintained but the session id is now computed when the base class is constructed. Adds as well some operations that need to be abstracted in order for the lifetime of the different objects in each backend to be maintained properly. Fixes #194 Part-of: <https://gitlab.gnome.org/GNOME/glib-networking/-/merge_requests/221>
-rw-r--r--tls/base/gtlsconnection-base.c120
-rw-r--r--tls/base/gtlsconnection-base.h2
-rw-r--r--tls/base/gtlssessioncache.c222
-rw-r--r--tls/base/gtlssessioncache.h45
-rw-r--r--tls/base/meson.build1
-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
-rw-r--r--tls/openssl/gtlsbackend-openssl.c168
-rw-r--r--tls/openssl/gtlsbackend-openssl.h5
-rw-r--r--tls/openssl/gtlsclientconnection-openssl.c108
-rw-r--r--tls/openssl/gtlsconnection-openssl.c2
-rw-r--r--tls/openssl/gtlsconnection-openssl.h2
-rw-r--r--tls/tests/connection.c18
16 files changed, 469 insertions, 456 deletions
diff --git a/tls/base/gtlsconnection-base.c b/tls/base/gtlsconnection-base.c
index 3b5c6ad..e839607 100644
--- a/tls/base/gtlsconnection-base.c
+++ b/tls/base/gtlsconnection-base.c
@@ -164,6 +164,9 @@ G_GNUC_END_IGNORE_DEPRECATIONS
GTlsProtocolVersion protocol_version;
gchar *ciphersuite_name;
+
+ gchar *session_id;
+ gboolean session_resumption_enabled;
} GTlsConnectionBasePrivate;
static void g_tls_connection_base_dtls_connection_iface_init (GDtlsConnectionInterface *iface);
@@ -217,6 +220,7 @@ enum
PROP_NEGOTIATED_PROTOCOL,
PROP_PROTOCOL_VERSION,
PROP_CIPHERSUITE_NAME,
+ PROP_SESSION_RESUMPTION_ENABLED,
PROP_SESSION_REUSED
};
@@ -236,6 +240,7 @@ g_tls_connection_base_init (GTlsConnectionBase *tls)
priv->need_handshake = TRUE;
priv->database_is_unset = TRUE;
priv->is_system_certdb = TRUE;
+ priv->session_resumption_enabled = !g_test_initialized ();
g_mutex_init (&priv->verify_certificate_mutex);
g_cond_init (&priv->verify_certificate_condition);
@@ -290,6 +295,8 @@ g_tls_connection_base_finalize (GObject *object)
g_clear_pointer (&priv->ciphersuite_name, g_free);
+ g_free (priv->session_id);
+
G_OBJECT_CLASS (g_tls_connection_base_parent_class)->finalize (object);
}
@@ -370,6 +377,10 @@ g_tls_connection_base_get_property (GObject *object,
case PROP_SESSION_REUSED:
g_value_set_boolean (value, FALSE);
break;
+
+ case PROP_SESSION_RESUMPTION_ENABLED:
+ g_value_set_boolean (value, priv->session_resumption_enabled);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -478,6 +489,10 @@ g_tls_connection_base_set_property (GObject *object,
g_assert_not_reached ();
break;
+ case PROP_SESSION_RESUMPTION_ENABLED:
+ priv->session_resumption_enabled = g_value_get_boolean (value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -1262,6 +1277,17 @@ g_tls_connection_base_condition_wait (GDatagramBased *datagram_based,
return !g_cancellable_set_error_if_cancelled (cancellable, error);
}
+static const gchar *
+get_server_identity (GSocketConnectable *server_identity)
+{
+ if (G_IS_NETWORK_ADDRESS (server_identity))
+ return g_network_address_get_hostname (G_NETWORK_ADDRESS (server_identity));
+ else if (G_IS_NETWORK_SERVICE (server_identity))
+ return g_network_service_get_domain (G_NETWORK_SERVICE (server_identity));
+ else
+ return NULL;
+}
+
static GTlsCertificateFlags
verify_peer_certificate (GTlsConnectionBase *tls,
GTlsCertificate *peer_certificate)
@@ -2776,6 +2802,90 @@ g_tls_connection_base_handshake_thread_buffer_application_data (GTlsConnectionBa
g_byte_array_append (priv->app_data_buf, data, length);
}
+gchar *
+g_tls_connection_base_get_session_id (GTlsConnectionBase *tls)
+{
+ GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
+ return priv->session_id;
+}
+
+static void
+g_tls_connection_base_constructed (GObject *object)
+{
+ GTlsConnectionBase *tls = G_TLS_CONNECTION_BASE (object);
+ if (G_IS_TLS_CLIENT_CONNECTION (tls))
+ {
+ GSocketConnection *base_conn;
+
+ /* 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.
+ */
+ g_object_get (G_OBJECT (tls), "base-io-stream", &base_conn, NULL);
+ if (G_IS_SOCKET_CONNECTION (base_conn))
+ {
+ GSocketAddress *remote_addr;
+ remote_addr = g_socket_connection_get_remote_address (base_conn, NULL);
+ if (G_IS_INET_SOCKET_ADDRESS (remote_addr))
+ {
+ const gchar *server_hostname = get_server_identity (!g_tls_connection_base_is_dtls (tls) ?
+ g_tls_client_connection_get_server_identity (G_TLS_CLIENT_CONNECTION (tls)) :
+ g_dtls_client_connection_get_server_identity (G_DTLS_CLIENT_CONNECTION (tls)));
+
+ if (server_hostname)
+ {
+ guint port;
+ GInetAddress *iaddr;
+ GTlsCertificate *cert = NULL;
+ GTlsConnectionBasePrivate *priv = NULL;
+ gchar *addrstr = NULL, *cert_hash = NULL;
+ GInetSocketAddress *isaddr = G_INET_SOCKET_ADDRESS (remote_addr);
+
+ priv = g_tls_connection_base_get_instance_private (tls);
+ port = g_inet_socket_address_get_port (isaddr);
+ iaddr = g_inet_socket_address_get_address (isaddr);
+ addrstr = g_inet_address_to_string (iaddr);
+
+ /* 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 (tls), "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);
+ }
+
+ priv->session_id = g_strdup_printf ("%s/%s/%d/%s", addrstr,
+ server_hostname ? server_hostname : "",
+ port,
+ cert_hash ? cert_hash : "");
+ g_free (addrstr);
+ g_free (cert_hash);
+ }
+ }
+ g_object_unref (remote_addr);
+ }
+ g_object_unref (base_conn);
+ }
+
+ if (G_OBJECT_CLASS (g_tls_connection_base_parent_class)->constructed)
+ G_OBJECT_CLASS (g_tls_connection_base_parent_class)->constructed (object);
+}
+
static void
g_tls_connection_base_class_init (GTlsConnectionBaseClass *klass)
{
@@ -2786,6 +2896,7 @@ g_tls_connection_base_class_init (GTlsConnectionBaseClass *klass)
gobject_class->get_property = g_tls_connection_base_get_property;
gobject_class->set_property = g_tls_connection_base_set_property;
gobject_class->finalize = g_tls_connection_base_finalize;
+ gobject_class->constructed = g_tls_connection_base_constructed;
connection_class->handshake = g_tls_connection_base_handshake;
connection_class->handshake_async = g_tls_connection_base_handshake_async;
@@ -2812,6 +2923,15 @@ g_tls_connection_base_class_init (GTlsConnectionBaseClass *klass)
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_SESSION_RESUMPTION_ENABLED,
+ g_param_spec_boolean ("session-resumption-enabled",
+ _("Session Reuse Enabled"),
+ _("Controls whether session should reuse a previous session or if it should be stored. In tests, this variable is false by default."),
+ !g_test_initialized (),
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_STATIC_STRINGS));
+
/* For GTlsConnection and GDtlsConnection: */
g_object_class_override_property (gobject_class, PROP_BASE_IO_STREAM, "base-io-stream");
g_object_class_override_property (gobject_class, PROP_BASE_SOCKET, "base-socket");
diff --git a/tls/base/gtlsconnection-base.h b/tls/base/gtlsconnection-base.h
index 0670660..7d98d93 100644
--- a/tls/base/gtlsconnection-base.h
+++ b/tls/base/gtlsconnection-base.h
@@ -216,4 +216,6 @@ void g_tls_connection_base_handshake_thread_buffer_applicat
guint8 *data,
gsize length);
+gchar *g_tls_connection_base_get_session_id (GTlsConnectionBase *tls);
+
G_END_DECLS
diff --git a/tls/base/gtlssessioncache.c b/tls/base/gtlssessioncache.c
new file mode 100644
index 0000000..607f569
--- /dev/null
+++ b/tls/base/gtlssessioncache.c
@@ -0,0 +1,222 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2022 YouView TV Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ */
+
+#include "config.h"
+#include "glib.h"
+
+#include "gtlssessioncache.h"
+
+#include <errno.h>
+#include <string.h>
+
+/* 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);
+static GHashTable *client_session_cache; /* (owned) GString -> (owned) GTlsCacheData */
+
+#define SESSION_CACHE_MAX_SIZE 50
+#define SESSION_CACHE_MAX_AGE (10ll * 60ll * G_USEC_PER_SEC) /* ten minutes */
+
+typedef struct {
+ gpointer tls1_2_session_ticket;
+ GQueue *tls1_3_session_tickets;
+ gint64 expiration_time;
+ SessionDup session_dup;
+ SessionAcquire inc_ref;
+ SessionRelease dec_ref;
+} GTlsCacheData;
+
+static void
+session_cache_cleanup (GHashTable *cache)
+{
+ gint64 time;
+ GHashTableIter iter;
+ gpointer key, value;
+ GTlsCacheData *cache_data;
+ gchar *session_id = NULL;
+ gint64 oldest_expiration_time = INT_MAX;
+ gboolean removed = FALSE;
+
+ time = g_get_monotonic_time ();
+
+ g_hash_table_iter_init (&iter, cache);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ cache_data = value;
+ if (cache_data->expiration_time < oldest_expiration_time)
+ {
+ oldest_expiration_time = cache_data->expiration_time;
+ session_id = key;
+ }
+
+ if (time > cache_data->expiration_time)
+ {
+ removed = TRUE;
+ g_hash_table_iter_remove (&iter);
+ }
+ }
+
+ if (!removed && session_id)
+ g_hash_table_remove (cache, session_id);
+}
+
+static void
+cache_data_free (GTlsCacheData *data)
+{
+ g_queue_free_full (data->tls1_3_session_tickets, (GDestroyNotify)data->dec_ref);
+
+ if (data->dec_ref && data->tls1_2_session_ticket)
+ data->dec_ref (data->tls1_2_session_ticket);
+
+ g_free (data);
+}
+
+static GHashTable *
+get_session_cache (gboolean create)
+{
+ if (!client_session_cache && create)
+ {
+ client_session_cache = g_hash_table_new_full ((GHashFunc)g_str_hash,
+ (GEqualFunc)g_str_equal,
+ (GDestroyNotify)g_free,
+ (GDestroyNotify)cache_data_free);
+ }
+ return client_session_cache;
+}
+
+void
+g_tls_store_session_data (gchar *session_id,
+ gpointer session_data,
+ SessionDup session_dup,
+ SessionAcquire inc_ref,
+ SessionRelease dec_ref,
+ GTlsProtocolVersion protocol_version)
+{
+ gpointer session_data_tmp = NULL;
+ GTlsCacheData *cache_data;
+ GHashTable *cache;
+
+ if (!session_id || !session_data)
+ return;
+
+ 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 (GTlsCacheData, 1);
+ cache_data->tls1_2_session_ticket = NULL;
+ cache_data->tls1_3_session_tickets = g_queue_new ();
+ cache_data->inc_ref = inc_ref;
+ cache_data->dec_ref = dec_ref;
+ cache_data->expiration_time = g_get_monotonic_time () + SESSION_CACHE_MAX_AGE;
+ g_hash_table_insert (cache, g_strdup (session_id), cache_data);
+ }
+
+ if (session_dup)
+ session_data_tmp = session_dup (session_data);
+
+ g_assert (session_data_tmp);
+
+ if ((protocol_version >= G_TLS_PROTOCOL_VERSION_TLS_1_3 &&
+ protocol_version < G_TLS_PROTOCOL_VERSION_DTLS_1_0) ||
+ protocol_version > G_TLS_PROTOCOL_VERSION_DTLS_1_2)
+ {
+ g_queue_push_tail (cache_data->tls1_3_session_tickets, session_data_tmp);
+ }
+ else
+ {
+ if (cache_data->dec_ref && cache_data->tls1_2_session_ticket)
+ dec_ref (cache_data->tls1_2_session_ticket);
+
+ cache_data->tls1_2_session_ticket = session_data_tmp;
+ }
+
+ G_UNLOCK (session_cache_lock);
+}
+
+gpointer
+g_tls_lookup_session_data (gchar *session_id)
+{
+ GTlsCacheData *cache_data;
+ gpointer session_data = NULL;
+ GHashTable *cache;
+
+ if (!session_id)
+ return NULL;
+
+ G_LOCK (session_cache_lock);
+
+ cache = get_session_cache (FALSE);
+ if (cache)
+ {
+ cache_data = g_hash_table_lookup (cache, session_id);
+ if (cache_data)
+ {
+ if (g_get_monotonic_time () > cache_data->expiration_time)
+ {
+ g_hash_table_remove (cache, session_id);
+ G_UNLOCK (session_cache_lock);
+ return NULL;
+ }
+
+ /* 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->tls1_3_session_tickets);
+
+ if (!session_data)
+ {
+ session_data = cache_data->tls1_2_session_ticket;
+ if (session_data && cache_data->inc_ref && !cache_data->inc_ref (session_data))
+ {
+ g_debug ("Failed to acquire cached TLS session, will not try to resume session");
+ session_data = NULL;
+ }
+ }
+
+ /* If the session data is NULL at this point, we do not have a valid
+ * session stored, so we can remove this entry from the cache
+ */
+ if (!session_data)
+ g_hash_table_remove (cache, session_id);
+ }
+ }
+
+ G_UNLOCK (session_cache_lock);
+
+ return session_data;
+}
diff --git a/tls/base/gtlssessioncache.h b/tls/base/gtlssessioncache.h
new file mode 100644
index 0000000..158c805
--- /dev/null
+++ b/tls/base/gtlssessioncache.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2022 YouView TV Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ */
+
+#pragma once
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+typedef gpointer (*SessionDup) (gpointer);
+typedef gint (*SessionAcquire) (gpointer);
+typedef void (*SessionRelease) (gpointer);
+
+void g_tls_store_session_data (gchar *session_id,
+ gpointer session_data,
+ SessionDup session_dup,
+ SessionAcquire inc_ref,
+ SessionRelease dec_ref,
+ GTlsProtocolVersion protocol_version
+ );
+
+gpointer g_tls_lookup_session_data (gchar *session_id);
+
+G_END_DECLS
diff --git a/tls/base/meson.build b/tls/base/meson.build
index f25cd35..be36f6f 100644
--- a/tls/base/meson.build
+++ b/tls/base/meson.build
@@ -4,6 +4,7 @@ tlsbase_sources = files(
'gtlsinputstream.c',
'gtlslog.c',
'gtlsoutputstream.c',
+ 'gtlssessioncache.c',
)
tlsbase = static_library('tlsbase',
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
diff --git a/tls/openssl/gtlsbackend-openssl.c b/tls/openssl/gtlsbackend-openssl.c
index aa08bd9..23cd8de 100644
--- a/tls/openssl/gtlsbackend-openssl.c
+++ b/tls/openssl/gtlsbackend-openssl.c
@@ -243,174 +243,6 @@ g_tls_backend_openssl_interface_init (GTlsBackendInterface *iface)
iface->get_dtls_server_connection_type = g_tls_server_connection_openssl_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);
-static GHashTable *client_session_cache; /* (owned) GString -> (owned) GTlsBackendOpensslCacheData */
-
-#define SESSION_CACHE_MAX_SIZE 50
-#define SESSION_CACHE_MAX_AGE (10ll * 60ll * G_USEC_PER_SEC) /* ten minutes */
-
-typedef struct {
- SSL_SESSION *session_ticket;
- gint64 expiration_time;
-} GTlsBackendOpensslCacheData;
-
-static void
-session_cache_cleanup (GHashTable *cache)
-{
- gint64 time;
- GHashTableIter iter;
- gpointer key, value;
- GTlsBackendOpensslCacheData *cache_data;
- GString *session_id = NULL;
- gint64 expiration_time = 0;
- gboolean removed = FALSE;
-
- time = g_get_monotonic_time ();
-
- g_hash_table_iter_init (&iter, cache);
- while (g_hash_table_iter_next (&iter, &key, &value))
- {
- cache_data = value;
- if (cache_data->expiration_time > expiration_time)
- {
- expiration_time = cache_data->expiration_time;
- session_id = key;
- }
-
- if (time > cache_data->expiration_time)
- {
- removed = TRUE;
- g_hash_table_iter_remove (&iter);
- }
- }
-
- if (!removed && session_id)
- g_hash_table_remove (cache, session_id);
-}
-
-static void
-cache_data_free (GTlsBackendOpensslCacheData *data)
-{
- SSL_SESSION_free (data->session_ticket);
- g_free (data);
-}
-
-static void
-string_free (GString *data)
-{
- g_string_free (data, TRUE);
-}
-
-static GHashTable *
-get_session_cache (gboolean create)
-{
- if (!client_session_cache && create)
- {
- client_session_cache = g_hash_table_new_full ((GHashFunc)g_string_hash,
- (GEqualFunc)g_string_equal,
- (GDestroyNotify)string_free,
- (GDestroyNotify)cache_data_free);
- }
- return client_session_cache;
-}
-
-void
-g_tls_backend_openssl_store_session_data (GString *session_id,
- SSL_SESSION *session_data)
-{
- GTlsBackendOpensslCacheData *cache_data;
- GHashTable *cache;
-
- if (!session_id || !session_data)
- return;
-
- 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);
-
- if (g_hash_table_size (cache) < SESSION_CACHE_MAX_SIZE)
- {
- cache_data = g_new (GTlsBackendOpensslCacheData, 1);
- cache_data->session_ticket = NULL;
- g_hash_table_insert (cache, g_string_new (session_id->str), cache_data);
- }
- }
-
- if (cache_data)
- {
- if (SSL_SESSION_up_ref (session_data))
- {
- SSL_SESSION_free (cache_data->session_ticket);
- cache_data->session_ticket = session_data;
- cache_data->expiration_time = g_get_monotonic_time () + SESSION_CACHE_MAX_AGE;
- }
- else
- g_warning ("Failed to acquire TLS session, will not be resumeable");
- }
-
- G_UNLOCK (session_cache_lock);
-}
-
-SSL_SESSION *
-g_tls_backend_openssl_lookup_session_data (GString *session_id)
-{
- GTlsBackendOpensslCacheData *cache_data;
- SSL_SESSION *session_data = NULL;
- GHashTable *cache;
-
- if (!session_id)
- return NULL;
-
- G_LOCK (session_cache_lock);
-
- cache = get_session_cache (FALSE);
- if (cache)
- {
- cache_data = g_hash_table_lookup (cache, session_id);
- if (cache_data)
- {
- if (g_get_monotonic_time () > cache_data->expiration_time)
- {
- g_hash_table_remove (cache, session_id);
- G_UNLOCK (session_cache_lock);
- return NULL;
- }
-
- session_data = cache_data->session_ticket;
- if (!SSL_SESSION_up_ref (session_data))
- {
- g_debug ("Failed to acquire cached TLS session, will not try to resume session");
- session_data = NULL;
- }
-
- /* 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.
- */
- if (SSL_SESSION_get_protocol_version (cache_data->session_ticket) == TLS1_3_VERSION)
- g_hash_table_remove (cache, session_id);
- }
- }
-
- G_UNLOCK (session_cache_lock);
-
- return session_data;
-}
-
void
g_tls_backend_openssl_register (GIOModule *module)
{
diff --git a/tls/openssl/gtlsbackend-openssl.h b/tls/openssl/gtlsbackend-openssl.h
index fa18df3..9e53806 100644
--- a/tls/openssl/gtlsbackend-openssl.h
+++ b/tls/openssl/gtlsbackend-openssl.h
@@ -26,7 +26,6 @@
#pragma once
#include <gio/gio.h>
-#include "openssl-include.h"
G_BEGIN_DECLS
@@ -36,8 +35,4 @@ G_DECLARE_FINAL_TYPE (GTlsBackendOpenssl, g_tls_backend_openssl, G, TLS_BACKEND_
void g_tls_backend_openssl_register (GIOModule *module);
-void g_tls_backend_openssl_store_session_data (GString *session_id,
- SSL_SESSION *session_data);
-SSL_SESSION *g_tls_backend_openssl_lookup_session_data (GString *session_id);
-
G_END_DECLS
diff --git a/tls/openssl/gtlsclientconnection-openssl.c b/tls/openssl/gtlsclientconnection-openssl.c
index 6a5a288..1c79aa0 100644
--- a/tls/openssl/gtlsclientconnection-openssl.c
+++ b/tls/openssl/gtlsclientconnection-openssl.c
@@ -30,9 +30,10 @@
#include <string.h>
#include "gtlsconnection-base.h"
+#include "gtlsconnection-openssl.h"
#include "gtlsbackend-openssl.h"
#include "gtlsclientconnection-openssl.h"
-#include "gtlsbackend-openssl.h"
+#include "gtlssessioncache.h"
#include "gtlscertificate-openssl.h"
#include "gtlsdatabase-openssl.h"
#include <glib/gi18n-lib.h>
@@ -45,7 +46,7 @@ struct _GTlsClientConnectionOpenssl
GSocketConnectable *server_identity;
gboolean use_ssl3;
gboolean session_reused;
- GString *session_id;
+ gboolean session_resumption_enabled;
STACK_OF (X509_NAME) *ca_list;
@@ -61,6 +62,7 @@ enum
PROP_SERVER_IDENTITY,
PROP_USE_SSL3,
PROP_ACCEPTED_CAS,
+ PROP_SESSION_RESUMPTION_ENABLED,
PROP_SESSION_REUSED
};
@@ -89,8 +91,6 @@ g_tls_client_connection_openssl_finalize (GObject *object)
SSL_CTX_free (openssl->ssl_ctx);
SSL_SESSION_free (openssl->session);
- g_string_free (openssl->session_id, TRUE);
-
G_OBJECT_CLASS (g_tls_client_connection_openssl_parent_class)->finalize (object);
}
@@ -106,75 +106,6 @@ get_server_identity (GTlsClientConnectionOpenssl *openssl)
}
static void
-g_tls_client_connection_openssl_constructed (GObject *object)
-{
- GTlsClientConnectionOpenssl *openssl = G_TLS_CLIENT_CONNECTION_OPENSSL (object);
- GSocketConnection *base_conn;
-
- /* 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.
- */
- g_object_get (G_OBJECT (openssl), "base-io-stream", &base_conn, NULL);
- if (G_IS_SOCKET_CONNECTION (base_conn))
- {
- GSocketAddress *remote_addr;
- remote_addr = g_socket_connection_get_remote_address (base_conn, NULL);
- if (G_IS_INET_SOCKET_ADDRESS (remote_addr))
- {
- guint port;
- GInetAddress *iaddr;
- GInetSocketAddress *isaddr = G_INET_SOCKET_ADDRESS (remote_addr);
- const gchar *server_hostname;
- gchar *addrstr = NULL, *cert_hash = NULL;
- GTlsCertificate *cert = 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 (openssl);
-
- /* 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 (openssl), "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);
- }
-
- openssl->session_id = g_string_new (NULL);
- g_string_printf (openssl->session_id, "%s/%s/%d/%s", addrstr,
- server_hostname ? server_hostname : "",
- port,
- cert_hash ? cert_hash : "");
- g_free (addrstr);
- g_free (cert_hash);
- }
- g_object_unref (remote_addr);
- }
- g_object_unref (base_conn);
-
- if (G_OBJECT_CLASS (g_tls_client_connection_openssl_parent_class)->constructed)
- G_OBJECT_CLASS (g_tls_client_connection_openssl_parent_class)->constructed (object);
-}
-
-static void
g_tls_client_connection_openssl_get_property (GObject *object,
guint prop_id,
GValue *value,
@@ -229,6 +160,10 @@ g_tls_client_connection_openssl_get_property (GObject *object,
g_value_set_boolean (value, openssl->session_reused);
break;
+ case PROP_SESSION_RESUMPTION_ENABLED:
+ g_value_set_boolean (value, openssl->session_resumption_enabled);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -258,6 +193,10 @@ g_tls_client_connection_openssl_set_property (GObject *object,
openssl->use_ssl3 = g_value_get_boolean (value);
break;
+ case PROP_SESSION_RESUMPTION_ENABLED:
+ openssl->session_resumption_enabled = g_value_get_boolean (value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -350,7 +289,6 @@ g_tls_client_connection_openssl_class_init (GTlsClientConnectionOpensslClass *kl
gobject_class->finalize = g_tls_client_connection_openssl_finalize;
gobject_class->get_property = g_tls_client_connection_openssl_get_property;
gobject_class->set_property = g_tls_client_connection_openssl_set_property;
- gobject_class->constructed = g_tls_client_connection_openssl_constructed;
base_class->complete_handshake = g_tls_client_connection_openssl_complete_handshake;
base_class->verify_peer_certificate = g_tls_client_connection_openssl_verify_peer_certificate;
@@ -362,11 +300,14 @@ g_tls_client_connection_openssl_class_init (GTlsClientConnectionOpensslClass *kl
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
g_tls_client_connection_openssl_init (GTlsClientConnectionOpenssl *openssl)
{
+ openssl->session_reused = FALSE;
+ openssl->session_resumption_enabled = !g_test_initialized ();
}
static void
@@ -515,7 +456,14 @@ set_curve_list (GTlsClientConnectionOpenssl *client)
static int g_tls_client_connection_openssl_new_session (SSL *s, SSL_SESSION *sess)
{
GTlsClientConnectionOpenssl *client = G_TLS_CLIENT_CONNECTION_OPENSSL (g_tls_connection_openssl_get_connection_from_ssl (s));
- g_tls_backend_openssl_store_session_data (client->session_id, sess);
+ if (client->session_resumption_enabled)
+ g_tls_store_session_data (g_tls_connection_base_get_session_id (G_TLS_CONNECTION_BASE (client)),
+ (gpointer)sess,
+ (SessionDup)SSL_SESSION_dup,
+ (SessionAcquire)SSL_SESSION_up_ref,
+ (SessionRelease)SSL_SESSION_free,
+ glib_protocol_version_from_openssl (SSL_SESSION_get_protocol_version (sess)));
+
return 0;
}
@@ -529,11 +477,15 @@ g_tls_client_connection_openssl_initable_init (GInitable *initable,
const char *hostname;
char error_buffer[256];
- client->session = g_tls_backend_openssl_lookup_session_data (client->session_id);
+ client->session = (SSL_SESSION *)g_tls_lookup_session_data (g_tls_connection_base_get_session_id (G_TLS_CONNECTION_BASE (client)));
if (!client->session)
- client->session = SSL_SESSION_new ();
+ {
+ client->session = SSL_SESSION_new ();
+ }
else
- client->session_reused = TRUE;
+ {
+ client->session_reused = TRUE;
+ }
client->ssl_ctx = SSL_CTX_new (g_tls_connection_base_is_dtls (G_TLS_CONNECTION_BASE (client))
#if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
diff --git a/tls/openssl/gtlsconnection-openssl.c b/tls/openssl/gtlsconnection-openssl.c
index 0232189..c96b389 100644
--- a/tls/openssl/gtlsconnection-openssl.c
+++ b/tls/openssl/gtlsconnection-openssl.c
@@ -517,7 +517,7 @@ g_tls_connection_openssl_verify_chain (GTlsConnectionBase *tls,
return errors;
}
-static GTlsProtocolVersion
+GTlsProtocolVersion
glib_protocol_version_from_openssl (int protocol_version)
{
switch (protocol_version)
diff --git a/tls/openssl/gtlsconnection-openssl.h b/tls/openssl/gtlsconnection-openssl.h
index 7b85fdc..1682eed 100644
--- a/tls/openssl/gtlsconnection-openssl.h
+++ b/tls/openssl/gtlsconnection-openssl.h
@@ -47,4 +47,6 @@ SSL *g_tls_connection_openssl_get_ssl (GTlsConnectionOpenssl *connection);
GTlsConnectionOpenssl *g_tls_connection_openssl_get_connection_from_ssl (SSL *ssl);
+GTlsProtocolVersion glib_protocol_version_from_openssl (int protocol_version);
+
G_END_DECLS
diff --git a/tls/tests/connection.c b/tls/tests/connection.c
index 7d514cb..1eaca65 100644
--- a/tls/tests/connection.c
+++ b/tls/tests/connection.c
@@ -611,6 +611,11 @@ test_connection_session_resume_ten_minute_expiry (TestConnection *test,
return;
#endif
+#if defined(G_OS_UNIX)
+ /* Expiry should be 10 min */
+ offset.tv_sec += 11 * 60;
+#endif
+
test->database = g_tls_file_database_new (tls_test_file_path ("ca-roots.pem"), &error);
g_assert_no_error (error);
g_assert_nonnull (test->database);
@@ -619,6 +624,7 @@ test_connection_session_resume_ten_minute_expiry (TestConnection *test,
test->client_connection = g_tls_client_connection_new (connection, test->identity, &error);
g_assert_no_error (error);
g_assert_nonnull (test->client_connection);
+ g_object_set (test->client_connection, "session-resumption-enabled", TRUE, NULL);
g_object_unref (connection);
cert = g_tls_certificate_new_from_file (tls_test_file_path ("client-and-key.pem"), &error);
@@ -646,7 +652,7 @@ test_connection_session_resume_ten_minute_expiry (TestConnection *test,
#if defined(G_OS_UNIX)
/* Expiry should be 10 min */
- offset.tv_sec = 11 * 60;
+ offset.tv_sec += 11 * 60;
#endif
/* Now start a new connection to the same server */
@@ -658,6 +664,7 @@ test_connection_session_resume_ten_minute_expiry (TestConnection *test,
test->client_connection = g_tls_client_connection_new (connection, test->identity, &error);
g_assert_no_error (error);
g_assert_nonnull (test->client_connection);
+ g_object_set (test->client_connection, "session-resumption-enabled", TRUE, NULL);
g_object_unref (connection);
cert = g_tls_certificate_new_from_file (tls_test_file_path ("client-and-key.pem"), &error);
@@ -680,7 +687,7 @@ test_connection_session_resume_ten_minute_expiry (TestConnection *test,
/* Second connection *DID NOT* reuse the first connection */
#if !defined(BACKEND_IS_GNUTLS)
- // FIXME: https://gitlab.gnome.org/GNOME/glib-networking/issues/194
+ // FIXME: https://gitlab.gnome.org/GNOME/glib-networking/issues/196
g_assert_false (reused);
#endif
}
@@ -703,6 +710,7 @@ test_connection_session_resume_multiple_times (TestConnection *test,
test->client_connection = g_tls_client_connection_new (connection, test->identity, &error);
g_assert_no_error (error);
g_assert_nonnull (test->client_connection);
+ g_object_set (test->client_connection, "session-resumption-enabled", TRUE, NULL);
g_object_unref (connection);
cert = g_tls_certificate_new_from_file (tls_test_file_path ("client-and-key.pem"), &error);
@@ -737,6 +745,7 @@ test_connection_session_resume_multiple_times (TestConnection *test,
test->client_connection = g_tls_client_connection_new (connection, test->identity, &error);
g_assert_no_error (error);
g_assert_nonnull (test->client_connection);
+ g_object_set (test->client_connection, "session-resumption-enabled", TRUE, NULL);
g_object_unref (connection);
cert = g_tls_certificate_new_from_file (tls_test_file_path ("client-and-key.pem"), &error);
@@ -761,7 +770,7 @@ test_connection_session_resume_multiple_times (TestConnection *test,
/* Second connection reused the first connection */
#if !defined(BACKEND_IS_GNUTLS)
- // FIXME: https://gitlab.gnome.org/GNOME/glib-networking/issues/194
+ // FIXME: https://gitlab.gnome.org/GNOME/glib-networking/issues/196
g_assert_true (reused);
#endif
@@ -774,6 +783,7 @@ test_connection_session_resume_multiple_times (TestConnection *test,
test->client_connection = g_tls_client_connection_new (connection, test->identity, &error);
g_assert_no_error (error);
g_assert_nonnull (test->client_connection);
+ g_object_set (test->client_connection, "session-resumption-enabled", TRUE, NULL);
g_object_unref (connection);
cert = g_tls_certificate_new_from_file (tls_test_file_path ("client-and-key.pem"), &error);
@@ -796,7 +806,7 @@ test_connection_session_resume_multiple_times (TestConnection *test,
/* Third connection reused the first connection */
#if !defined(BACKEND_IS_GNUTLS)
- // FIXME: https://gitlab.gnome.org/GNOME/glib-networking/issues/194
+ // FIXME: https://gitlab.gnome.org/GNOME/glib-networking/issues/196
g_assert_true (reused);
#endif
}