[glib-networking] Remove IP port pairs from unique session ID when hostname exists
- From: Marge Bot <marge-bot src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking] Remove IP port pairs from unique session ID when hostname exists
- Date: Mon, 12 Sep 2022 15:58:16 +0000 (UTC)
commit 00dae0976a49e2b612b567c7c4d68336505caa80
Author: Goncalo Gomes <goncalo gomes youview com>
Date: Wed Sep 7 18:26:33 2022 +0100
Remove IP port pairs from unique session ID when hostname exists
Modern CDNs should be able to resume sessions even if the IP is different
Hence this commit allows usage of the same session ticket across the
infrastructure of the CDN, if the servers allow that.
In the case where CDN does not allow that, it will just fail to resume the
session. Possibly creating new session tickets for the next connections to
the same hostname.
In the tests we cannot assert that the connection has not been reused as the
allegedly random port might have been assigned multiple times by the OS
Part-of: <https://gitlab.gnome.org/GNOME/glib-networking/-/merge_requests/221>
tls/base/gtlsconnection-base.c | 83 +++++++++++++++++++++---------
tls/base/gtlsconnection-base.h | 5 ++
tls/gnutls/gtlsclientconnection-gnutls.c | 15 +++---
tls/openssl/gtlsclientconnection-openssl.c | 15 +++---
tls/tests/connection.c | 22 +++++---
5 files changed, 95 insertions(+), 45 deletions(-)
---
diff --git a/tls/base/gtlsconnection-base.c b/tls/base/gtlsconnection-base.c
index e8396072..559bf35b 100644
--- a/tls/base/gtlsconnection-base.c
+++ b/tls/base/gtlsconnection-base.c
@@ -232,6 +232,20 @@ g_tls_connection_base_is_dtls (GTlsConnectionBase *tls)
return priv->base_socket != NULL;
}
+gboolean
+g_tls_connection_base_get_session_resumption (GTlsConnectionBase *tls)
+{
+ GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
+ return priv->session_resumption_enabled;
+}
+
+void
+g_tls_connection_base_set_session_resumption (GTlsConnectionBase *tls, gboolean session_resumption_enabled)
+{
+ GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
+ priv->session_resumption_enabled = session_resumption_enabled;
+}
+
static void
g_tls_connection_base_init (GTlsConnectionBase *tls)
{
@@ -240,6 +254,22 @@ g_tls_connection_base_init (GTlsConnectionBase *tls)
priv->need_handshake = TRUE;
priv->database_is_unset = TRUE;
priv->is_system_certdb = TRUE;
+
+ /* 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).
+ *
+ * On top of that if using a hostname the session id would be used for all
+ * the connections in the tests.
+ *
+ * This variable allows tests to enable session resumption only when needed
+ * whilst keeping the feature enabled for other uses of the library.
+ */
priv->session_resumption_enabled = !g_test_initialized ();
g_mutex_init (&priv->verify_certificate_mutex);
@@ -2834,48 +2864,53 @@ g_tls_connection_base_constructed (GObject *object)
remote_addr = g_socket_connection_get_remote_address (base_conn, NULL);
if (G_IS_INET_SOCKET_ADDRESS (remote_addr))
{
+ gchar *cert_hash = NULL;
+ GTlsCertificate *cert = NULL;
+ GTlsConnectionBasePrivate *priv = NULL;
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)));
+ priv = g_tls_connection_base_get_instance_private (tls);
+
+ /* 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);
+ }
if (server_hostname)
+ {
+ priv->session_id = g_strdup_printf ("%s/%s", server_hostname,
+ cert_hash ? cert_hash : "");
+ }
+ else
{
guint port;
GInetAddress *iaddr;
- GTlsCertificate *cert = NULL;
- GTlsConnectionBasePrivate *priv = NULL;
- gchar *addrstr = NULL, *cert_hash = NULL;
+ gchar *addrstr = 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 : "",
+ priv->session_id = g_strdup_printf ("%s/%d/%s", addrstr,
port,
cert_hash ? cert_hash : "");
g_free (addrstr);
- g_free (cert_hash);
}
+ g_free (cert_hash);
}
g_object_unref (remote_addr);
}
diff --git a/tls/base/gtlsconnection-base.h b/tls/base/gtlsconnection-base.h
index 7d98d935..959018cd 100644
--- a/tls/base/gtlsconnection-base.h
+++ b/tls/base/gtlsconnection-base.h
@@ -218,4 +218,9 @@ void g_tls_connection_base_handshake_thread_buffer_applicat
gchar *g_tls_connection_base_get_session_id (GTlsConnectionBase *tls);
+gboolean g_tls_connection_base_get_session_resumption (GTlsConnectionBase *tls);
+
+void g_tls_connection_base_set_session_resumption (GTlsConnectionBase *tls,
+ gboolean
session_resumption_enabled);
+
G_END_DECLS
diff --git a/tls/gnutls/gtlsclientconnection-gnutls.c b/tls/gnutls/gtlsclientconnection-gnutls.c
index 17394d52..b22d7334 100644
--- a/tls/gnutls/gtlsclientconnection-gnutls.c
+++ b/tls/gnutls/gtlsclientconnection-gnutls.c
@@ -57,7 +57,6 @@ 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.
@@ -115,8 +114,6 @@ 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 *
@@ -143,7 +140,9 @@ handshake_thread_session_ticket_received_cb (gnutls_session_t session,
guint incoming,
const gnutls_datum_t *msg)
{
- GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (gnutls_session_get_ptr (session));
+ GTlsConnectionBase *tls = gnutls_transport_get_ptr (session);
+ GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (tls);
+
gnutls_datum_t session_datum;
if (gnutls_session_get_data2 (session, &session_datum) == GNUTLS_E_SUCCESS)
@@ -154,7 +153,7 @@ handshake_thread_session_ticket_received_cb (gnutls_session_t session,
(GDestroyNotify)gnutls_free,
session_datum.data);
- if (gnutls->session_resumption_enabled && gnutls->session_id)
+ if (g_tls_connection_base_get_session_resumption (tls) && gnutls->session_id)
{
g_tls_store_session_data (gnutls->session_id,
(gpointer)gnutls->session_data,
@@ -225,6 +224,7 @@ g_tls_client_connection_gnutls_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
+ GTlsConnectionBase *tls = G_TLS_CONNECTION_BASE (object);
GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (object);
GList *accepted_cas;
gint i;
@@ -262,7 +262,7 @@ g_tls_client_connection_gnutls_get_property (GObject *object,
break;
case PROP_SESSION_RESUMPTION_ENABLED:
- g_value_set_boolean (value, gnutls->session_resumption_enabled);
+ g_value_set_boolean (value, g_tls_connection_base_get_session_resumption (tls));
break;
default:
@@ -276,6 +276,7 @@ g_tls_client_connection_gnutls_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
+ GTlsConnectionBase *tls = G_TLS_CONNECTION_BASE (object);
GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (object);
const char *hostname;
@@ -317,7 +318,7 @@ g_tls_client_connection_gnutls_set_property (GObject *object,
break;
case PROP_SESSION_RESUMPTION_ENABLED:
- gnutls->session_resumption_enabled = g_value_get_boolean (value);
+ g_tls_connection_base_set_session_resumption (tls, g_value_get_boolean (value));
break;
default:
diff --git a/tls/openssl/gtlsclientconnection-openssl.c b/tls/openssl/gtlsclientconnection-openssl.c
index 1c79aa00..fbf100ba 100644
--- a/tls/openssl/gtlsclientconnection-openssl.c
+++ b/tls/openssl/gtlsclientconnection-openssl.c
@@ -46,7 +46,6 @@ struct _GTlsClientConnectionOpenssl
GSocketConnectable *server_identity;
gboolean use_ssl3;
gboolean session_reused;
- gboolean session_resumption_enabled;
STACK_OF (X509_NAME) *ca_list;
@@ -111,6 +110,7 @@ g_tls_client_connection_openssl_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
+ GTlsConnectionBase *tls = G_TLS_CONNECTION_BASE (object);
GTlsClientConnectionOpenssl *openssl = G_TLS_CLIENT_CONNECTION_OPENSSL (object);
GList *accepted_cas;
gint i;
@@ -161,7 +161,7 @@ g_tls_client_connection_openssl_get_property (GObject *object,
break;
case PROP_SESSION_RESUMPTION_ENABLED:
- g_value_set_boolean (value, openssl->session_resumption_enabled);
+ g_value_set_boolean (value, g_tls_connection_base_get_session_resumption (tls));
break;
default:
@@ -175,6 +175,7 @@ g_tls_client_connection_openssl_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
+ GTlsConnectionBase *tls = G_TLS_CONNECTION_BASE (object);
GTlsClientConnectionOpenssl *openssl = G_TLS_CLIENT_CONNECTION_OPENSSL (object);
switch (prop_id)
@@ -194,7 +195,7 @@ g_tls_client_connection_openssl_set_property (GObject *object,
break;
case PROP_SESSION_RESUMPTION_ENABLED:
- openssl->session_resumption_enabled = g_value_get_boolean (value);
+ g_tls_connection_base_set_session_resumption (tls, g_value_get_boolean (value));
break;
default:
@@ -306,8 +307,6 @@ g_tls_client_connection_openssl_class_init (GTlsClientConnectionOpensslClass *kl
static void
g_tls_client_connection_openssl_init (GTlsClientConnectionOpenssl *openssl)
{
- openssl->session_reused = FALSE;
- openssl->session_resumption_enabled = !g_test_initialized ();
}
static void
@@ -455,8 +454,12 @@ set_curve_list (GTlsClientConnectionOpenssl *client)
static int g_tls_client_connection_openssl_new_session (SSL *s, SSL_SESSION *sess)
{
+ GTlsConnectionBase *tls;
GTlsClientConnectionOpenssl *client = G_TLS_CLIENT_CONNECTION_OPENSSL
(g_tls_connection_openssl_get_connection_from_ssl (s));
- if (client->session_resumption_enabled)
+
+ tls = G_TLS_CONNECTION_BASE (client);
+
+ if (g_tls_connection_base_get_session_resumption (tls))
g_tls_store_session_data (g_tls_connection_base_get_session_id (G_TLS_CONNECTION_BASE (client)),
(gpointer)sess,
(SessionDup)SSL_SESSION_dup,
diff --git a/tls/tests/connection.c b/tls/tests/connection.c
index 1eaca655..b008dcd6 100644
--- a/tls/tests/connection.c
+++ b/tls/tests/connection.c
@@ -43,6 +43,7 @@
#if defined(G_OS_UNIX)
#include <dlfcn.h>
static struct timespec offset;
+static struct timespec session_time_offset;
#endif
static const gchar *
@@ -115,6 +116,16 @@ setup_connection (TestConnection *test, gconstpointer data)
#endif
}
+static void
+setup_session_connection (TestConnection *test, gconstpointer data)
+{
+ setup_connection (test, data);
+#if defined(G_OS_UNIX)
+ offset.tv_sec += 11 * 60 + session_time_offset.tv_sec;
+ session_time_offset.tv_sec += 11 * 60;
+#endif
+}
+
/* Waits about 10 seconds for @var to be NULL/FALSE */
#define WAIT_UNTIL_UNSET(var) \
if (var) \
@@ -611,11 +622,6 @@ 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);
@@ -647,11 +653,11 @@ test_connection_session_resume_ten_minute_expiry (TestConnection *test,
g_object_unref (test->client_connection);
g_clear_object (&test->server_connection);
- /* First connection was not reused */
g_assert_false (reused);
#if defined(G_OS_UNIX)
/* Expiry should be 10 min */
+ session_time_offset.tv_sec += 11 * 60;
offset.tv_sec += 11 * 60;
#endif
@@ -3382,9 +3388,9 @@ main (int argc,
#endif
g_test_add ("/tls/" BACKEND "/connection/session/resume_multiple_times", TestConnection, NULL,
- setup_connection, test_connection_session_resume_multiple_times, teardown_connection);
+ setup_session_connection, test_connection_session_resume_multiple_times, teardown_connection);
g_test_add ("/tls/" BACKEND "/connection/session/reuse_ten_minute_expiry", TestConnection, NULL,
- setup_connection, test_connection_session_resume_ten_minute_expiry, teardown_connection);
+ setup_session_connection, test_connection_session_resume_ten_minute_expiry,
teardown_connection);
g_test_add ("/tls/" BACKEND "/connection/basic", TestConnection, NULL,
setup_connection, test_basic_connection, teardown_connection);
g_test_add ("/tls/" BACKEND "/connection/verified", TestConnection, NULL,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]