[glib-networking/glib-2-54] gnutls: Fix using different client certs for different connections
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking/glib-2-54] gnutls: Fix using different client certs for different connections
- Date: Sat, 21 Oct 2017 15:56:27 +0000 (UTC)
commit c188f74cfc874833b79c457bac318f2a440580d4
Author: Martin Pitt <martin piware de>
Date: Mon Apr 24 16:23:28 2017 +0200
gnutls: Fix using different client certs for different connections
Up to now, a GTlsClientConnectionGnutls' session ID was built only from
the address and port. This led to overly aggressive caching of the TLS
session data and ignored the set client certificate of any subsequent
connection to the same server/port.
Move computation of the session ID from _constructed() to
_begin_handshake() when we actually need it; at that point we have the
client certificate already set. Append the certificate's hash to the
session ID to disambiguate connections with different client
certificates while still retaining the caching for multiple connections
with the same cert.
Add a second client certificate with a different modulus to the test
files and expand the connection /tls/connection/client-auth* tests to
cover this case.
Also extend /tls/connection/client-auth-failure to do a connection with
a good certificate after a failed attempt without a cert, to ensure that
our session caching doesn't attempt to re-use the failed session for
that.
https://bugzilla.gnome.org/show_bug.cgi?id=781578
tls/gnutls/gtlsclientconnection-gnutls.c | 33 +++++++++---
tls/tests/connection.c | 80 ++++++++++++++++++++++++++++++
tls/tests/files/client2-and-key.pem | 45 +++++++++++++++++
tls/tests/files/client2-key.pem | 27 ++++++++++
tls/tests/files/client2.pem | 18 +++++++
tls/tests/files/create-files.sh | 8 +++
6 files changed, 203 insertions(+), 8 deletions(-)
---
diff --git a/tls/gnutls/gtlsclientconnection-gnutls.c b/tls/gnutls/gtlsclientconnection-gnutls.c
index d5d63fa..26424ee 100644
--- a/tls/gnutls/gtlsclientconnection-gnutls.c
+++ b/tls/gnutls/gtlsclientconnection-gnutls.c
@@ -100,9 +100,8 @@ get_server_identity (GTlsClientConnectionGnutls *gnutls)
}
static void
-g_tls_client_connection_gnutls_constructed (GObject *object)
+g_tls_client_connection_gnutls_compute_session_id (GTlsClientConnectionGnutls *gnutls)
{
- GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (object);
GSocketConnection *base_conn;
GSocketAddress *remote_addr;
GInetAddress *iaddr;
@@ -124,24 +123,41 @@ g_tls_client_connection_gnutls_constructed (GObject *object)
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);
- session_id = g_strdup_printf ("%s/%s/%d", addrstr,
+
+ /* 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);
+ port,
+ cert_hash ?: "");
gnutls->priv->session_id = g_bytes_new_take (session_id, strlen (session_id));
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_gnutls_parent_class)->constructed)
- G_OBJECT_CLASS (g_tls_client_connection_gnutls_parent_class)->constructed (object);
}
static void
@@ -326,6 +342,8 @@ g_tls_client_connection_gnutls_begin_handshake (GTlsConnectionGnutls *conn)
{
GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (conn);
+ g_tls_client_connection_gnutls_compute_session_id (gnutls);
+
/* Try to get a cached session */
if (gnutls->priv->session_data_override)
{
@@ -434,7 +452,6 @@ g_tls_client_connection_gnutls_class_init (GTlsClientConnectionGnutlsClass *klas
gobject_class->get_property = g_tls_client_connection_gnutls_get_property;
gobject_class->set_property = g_tls_client_connection_gnutls_set_property;
- gobject_class->constructed = g_tls_client_connection_gnutls_constructed;
gobject_class->finalize = g_tls_client_connection_gnutls_finalize;
connection_gnutls_class->failed = g_tls_client_connection_gnutls_failed;
diff --git a/tls/tests/connection.c b/tls/tests/connection.c
index d2bf8cb..4aa4944 100644
--- a/tls/tests/connection.c
+++ b/tls/tests/connection.c
@@ -918,6 +918,7 @@ test_client_auth_connection (TestConnection *test,
GTlsCertificate *cert;
GTlsCertificate *peer;
gboolean cas_changed;
+ GSocketClient *client;
test->database = g_tls_file_database_new (tls_test_file_path ("ca-roots.pem"), &error);
g_assert_no_error (error);
@@ -956,6 +957,36 @@ test_client_auth_connection (TestConnection *test,
g_assert (cas_changed == TRUE);
g_object_unref (cert);
+ g_object_unref (test->database);
+ g_object_unref (test->client_connection);
+
+ /* Now start a new connection to the same server with a different client cert */
+ client = g_socket_client_new ();
+ connection = G_IO_STREAM (g_socket_client_connect (client, G_SOCKET_CONNECTABLE (test->address),
+ NULL, &error));
+ g_assert_no_error (error);
+ g_object_unref (client);
+ test->client_connection = g_tls_client_connection_new (connection, test->identity, &error);
+ g_object_unref (connection);
+
+ g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (test->client_connection),
+ 0);
+ cert = g_tls_certificate_new_from_file (tls_test_file_path ("client2-and-key.pem"), &error);
+ g_assert_no_error (error);
+ g_tls_connection_set_certificate (G_TLS_CONNECTION (test->client_connection), cert);
+ g_object_unref (cert);
+ g_tls_connection_set_database (G_TLS_CONNECTION (test->client_connection), test->database);
+
+ read_test_data_async (test);
+ g_main_loop_run (test->loop);
+
+ g_assert_no_error (test->read_error);
+ g_assert_no_error (test->server_error);
+
+ /* peer should see the second client cert */
+ peer = g_tls_connection_get_peer_certificate (G_TLS_CONNECTION (test->server_connection));
+ g_assert (peer != NULL);
+ g_assert (g_tls_certificate_is_same (peer, cert));
}
static void
@@ -973,6 +1004,10 @@ test_client_auth_failure (TestConnection *test,
GIOStream *connection;
GError *error = NULL;
gboolean accepted_changed;
+ GSocketClient *client;
+ GTlsCertificate *cert;
+ GTlsCertificate *peer;
+ GTlsInteraction *interaction;
test->database = g_tls_file_database_new (tls_test_file_path ("ca-roots.pem"), &error);
g_assert_no_error (error);
@@ -1003,6 +1038,51 @@ test_client_auth_failure (TestConnection *test,
g_assert_error (test->server_error, G_TLS_ERROR, G_TLS_ERROR_CERTIFICATE_REQUIRED);
g_assert (accepted_changed == TRUE);
+
+ g_object_unref (test->client_connection);
+ g_object_unref (test->database);
+ g_clear_error (&test->read_error);
+ g_clear_error (&test->server_error);
+
+ /* Now start a new connection to the same server with a valid client cert;
+ * this should succeed, and not use the cached failed session from above */
+ client = g_socket_client_new ();
+ connection = G_IO_STREAM (g_socket_client_connect (client, G_SOCKET_CONNECTABLE (test->address),
+ NULL, &error));
+ g_assert_no_error (error);
+ g_object_unref (client);
+ test->client_connection = g_tls_client_connection_new (connection, test->identity, &error);
+ g_object_unref (connection);
+
+ g_tls_connection_set_database (G_TLS_CONNECTION (test->client_connection), test->database);
+
+ /* Have the interaction return a certificate */
+ cert = g_tls_certificate_new_from_file (tls_test_file_path ("client-and-key.pem"), &error);
+ g_assert_no_error (error);
+ interaction = mock_interaction_new_static_certificate (cert);
+ g_tls_connection_set_interaction (G_TLS_CONNECTION (test->client_connection), interaction);
+ g_object_unref (interaction);
+
+ /* All validation in this test */
+ g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (test->client_connection),
+ G_TLS_CERTIFICATE_VALIDATE_ALL);
+
+ accepted_changed = FALSE;
+ g_signal_connect (test->client_connection, "notify::accepted-cas",
+ G_CALLBACK (on_notify_accepted_cas), &accepted_changed);
+
+ read_test_data_async (test);
+ g_main_loop_run (test->loop);
+
+ g_assert_no_error (test->read_error);
+ g_assert_no_error (test->server_error);
+
+ peer = g_tls_connection_get_peer_certificate (G_TLS_CONNECTION (test->server_connection));
+ g_assert (peer != NULL);
+ g_assert (g_tls_certificate_is_same (peer, cert));
+ g_assert (accepted_changed == TRUE);
+
+ g_object_unref (cert);
}
static void
diff --git a/tls/tests/files/client2-and-key.pem b/tls/tests/files/client2-and-key.pem
new file mode 100644
index 0000000..0f1e98d
--- /dev/null
+++ b/tls/tests/files/client2-and-key.pem
@@ -0,0 +1,45 @@
+-----BEGIN CERTIFICATE-----
+MIIC3DCCAkUCAQEwDQYJKoZIhvcNAQELBQAwgYYxEzARBgoJkiaJk/IsZAEZFgND
+T00xFzAVBgoJkiaJk/IsZAEZFgdFWEFNUExFMR4wHAYDVQQLDBVDZXJ0aWZpY2F0
+ZSBBdXRob3JpdHkxFzAVBgNVBAMMDmNhLmV4YW1wbGUuY29tMR0wGwYJKoZIhvcN
+AQkBFg5jYUBleGFtcGxlLmNvbTAeFw0xNzA0MjEwODUwMjdaFw00MjA0MTUwODUw
+MjdaMGIxEzARBgoJkiaJk/IsZAEZFgNDT00xFzAVBgoJkiaJk/IsZAEZFgdFWEFN
+UExFMQ8wDQYDVQQDDAZDbGllbnQxITAfBgkqhkiG9w0BCQEWEmNsaWVudEBleGFt
+cGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALcDxJFF30lE
+s/w8KN7ENjhaXosDqOe/IiNTStg+f1CL+/bKdcSu8wTyQsltv/+fi/jiw4ls1chP
+Eni7r+HtkPdMVG5mvuaGzPFyVCl1YkOihS0v0+YQkm83LcC7jU2+dvrDQYMFWH9d
+ehfFur9Cwmur5EH5Xl2nKehYifMYmljh/jPMPdCj6xWGUN6p/k459hz1JGvfWlqa
+1o/35j9uakjBtsFeOKT5SEZsg2S9DudYsHfC/ncXl1LrJCFzQBY1ifhDr3FHrEsM
+ieoAi4+qNq1ZZxwzppB81MAyggaJmqHUo/IpvJxWF8AhK202skiDYURk7k1kyT7g
+ZWRwl72Wz/kCAwEAATANBgkqhkiG9w0BAQsFAAOBgQAPiq0yRWbFD+17cz5TrRsG
+kapRrVmwqpX4nrv+pvBgzT6aatV5SZDXq+jqw1L2n2B/DEUwDXJ0R8vV0J2hE/KE
++7YRWgM0LyT/iYp5CC1n3GKpirxarz5hwXHVmNsMnYjLRc/4NVGkyDOqTZIPN106
+C8hyhUIMHGLBqWMxCG7myQ==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAtwPEkUXfSUSz/Dwo3sQ2OFpeiwOo578iI1NK2D5/UIv79sp1
+xK7zBPJCyW2//5+L+OLDiWzVyE8SeLuv4e2Q90xUbma+5obM8XJUKXViQ6KFLS/T
+5hCSbzctwLuNTb52+sNBgwVYf116F8W6v0LCa6vkQfleXacp6FiJ8xiaWOH+M8w9
+0KPrFYZQ3qn+Tjn2HPUka99aWprWj/fmP25qSMG2wV44pPlIRmyDZL0O51iwd8L+
+dxeXUuskIXNAFjWJ+EOvcUesSwyJ6gCLj6o2rVlnHDOmkHzUwDKCBomaodSj8im8
+nFYXwCErbTaySINhRGTuTWTJPuBlZHCXvZbP+QIDAQABAoIBAQC2hfJ39BiRiQx8
+Jj+YlFWC9FXQDNFad1wDoSFG82WkHkgnRJoZk2XZbAfBvkw7E5LUoMvk9f9sK7g/
+Yugxye3HRX/7L0t6u7wPnTdktaZPz/lELKwHikWQ15Yw3pw5ihg9VZizpBQzyjVn
+GhN6holCOweF6L79Zic8i3jhUos00lciPtKgH2fMXDL/CMMsHsd+Nr52sWmsXTpG
+Rv5p64O2RnDRP555HTzlgkgrsFUuyrR7/BAGa6j9XyXN+9HjybOpwcMLDlvrXrZH
+pxUeneJZIGRUIrF3c3iSVXbPHfySp/WWPD+zobXGnw1uyeWW7YPjFUu7ABATt84j
+KNS5Uz5RAoGBANnw1TboXUoFKcMp8fUidZT5n1AbqqFj2KgMuMN0lUha2Fnd40a1
+yFZbO8P7RDTlQT++krH6jSV1VHfPaN4CQrfC7XQDkGjEc95Eyi0fNSuHpZirX5Ci
+/fsoryls6Kkd62SPA8jDRvbv+EYRxKT8uIQsy871UDcIaHs8+IBnti+tAoGBANb5
+i+HK9Y65DuA/6W26oBW2yGLyRaIoZDWinE7LA1EiZBWwHmXyw602egjUsKRGPCKI
+DCjFpLts13ZvEprTIev0enhmk/tulZ/p0+lcuY0Dd6nfTZVhejJjaLE8o5SgxXGr
+U3UEemW78T9DEA3tZjt8hu8YzYWRCvLPa+8kPrr9AoGAeM+I0cQjGoocKWSSDKoK
+dged6YE8p/Q6QIW00hxJOG+raL2YZDUWldBDJBOgLpY7AkP4+5IBNheBOF0QK6kj
+JMx4ZownO/xSoo6NaE/ZYIT0JdoxwnKnydc2qgcGPeEpAHhKx7qAFxjVDrqAwFib
+TCGs5M+VpLwTduVId52GH40CgYEAoFVIdeP41zTAmpIwWC2b3fYQaHPHaZT0gGhC
+aiXR2H5s5RwQ3/p65MI/rDxtbmgPy7VqVDJslXktDeDzoFOd9izF9uySrDEjGTy9
+V0xX+4s9gY3RgHtONyybVa0jV+O8vvWH7jujyiKtYIB1Bd4spGtQ/ByklFzELKp1
+FswSmUUCgYA9lZ4bEbfFUVCTYJyLlNCFBvDhD+FaWHZ3fQOM/w0jRQVz1B1Y7BO+
+r9Uih1rcUYHUBKE61GiJh3uFFD2IwCkhICvdof0B0WsnoEuSvoTwe6pAGZbKdonY
+ATM1joBOoLbgDIrE2aESBXztMErJ2Lx+q1kPbULF6cEfvYnDdQTM1Q==
+-----END RSA PRIVATE KEY-----
diff --git a/tls/tests/files/client2-key.pem b/tls/tests/files/client2-key.pem
new file mode 100644
index 0000000..26964c6
--- /dev/null
+++ b/tls/tests/files/client2-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAtwPEkUXfSUSz/Dwo3sQ2OFpeiwOo578iI1NK2D5/UIv79sp1
+xK7zBPJCyW2//5+L+OLDiWzVyE8SeLuv4e2Q90xUbma+5obM8XJUKXViQ6KFLS/T
+5hCSbzctwLuNTb52+sNBgwVYf116F8W6v0LCa6vkQfleXacp6FiJ8xiaWOH+M8w9
+0KPrFYZQ3qn+Tjn2HPUka99aWprWj/fmP25qSMG2wV44pPlIRmyDZL0O51iwd8L+
+dxeXUuskIXNAFjWJ+EOvcUesSwyJ6gCLj6o2rVlnHDOmkHzUwDKCBomaodSj8im8
+nFYXwCErbTaySINhRGTuTWTJPuBlZHCXvZbP+QIDAQABAoIBAQC2hfJ39BiRiQx8
+Jj+YlFWC9FXQDNFad1wDoSFG82WkHkgnRJoZk2XZbAfBvkw7E5LUoMvk9f9sK7g/
+Yugxye3HRX/7L0t6u7wPnTdktaZPz/lELKwHikWQ15Yw3pw5ihg9VZizpBQzyjVn
+GhN6holCOweF6L79Zic8i3jhUos00lciPtKgH2fMXDL/CMMsHsd+Nr52sWmsXTpG
+Rv5p64O2RnDRP555HTzlgkgrsFUuyrR7/BAGa6j9XyXN+9HjybOpwcMLDlvrXrZH
+pxUeneJZIGRUIrF3c3iSVXbPHfySp/WWPD+zobXGnw1uyeWW7YPjFUu7ABATt84j
+KNS5Uz5RAoGBANnw1TboXUoFKcMp8fUidZT5n1AbqqFj2KgMuMN0lUha2Fnd40a1
+yFZbO8P7RDTlQT++krH6jSV1VHfPaN4CQrfC7XQDkGjEc95Eyi0fNSuHpZirX5Ci
+/fsoryls6Kkd62SPA8jDRvbv+EYRxKT8uIQsy871UDcIaHs8+IBnti+tAoGBANb5
+i+HK9Y65DuA/6W26oBW2yGLyRaIoZDWinE7LA1EiZBWwHmXyw602egjUsKRGPCKI
+DCjFpLts13ZvEprTIev0enhmk/tulZ/p0+lcuY0Dd6nfTZVhejJjaLE8o5SgxXGr
+U3UEemW78T9DEA3tZjt8hu8YzYWRCvLPa+8kPrr9AoGAeM+I0cQjGoocKWSSDKoK
+dged6YE8p/Q6QIW00hxJOG+raL2YZDUWldBDJBOgLpY7AkP4+5IBNheBOF0QK6kj
+JMx4ZownO/xSoo6NaE/ZYIT0JdoxwnKnydc2qgcGPeEpAHhKx7qAFxjVDrqAwFib
+TCGs5M+VpLwTduVId52GH40CgYEAoFVIdeP41zTAmpIwWC2b3fYQaHPHaZT0gGhC
+aiXR2H5s5RwQ3/p65MI/rDxtbmgPy7VqVDJslXktDeDzoFOd9izF9uySrDEjGTy9
+V0xX+4s9gY3RgHtONyybVa0jV+O8vvWH7jujyiKtYIB1Bd4spGtQ/ByklFzELKp1
+FswSmUUCgYA9lZ4bEbfFUVCTYJyLlNCFBvDhD+FaWHZ3fQOM/w0jRQVz1B1Y7BO+
+r9Uih1rcUYHUBKE61GiJh3uFFD2IwCkhICvdof0B0WsnoEuSvoTwe6pAGZbKdonY
+ATM1joBOoLbgDIrE2aESBXztMErJ2Lx+q1kPbULF6cEfvYnDdQTM1Q==
+-----END RSA PRIVATE KEY-----
diff --git a/tls/tests/files/client2.pem b/tls/tests/files/client2.pem
new file mode 100644
index 0000000..f5696e2
--- /dev/null
+++ b/tls/tests/files/client2.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC3DCCAkUCAQEwDQYJKoZIhvcNAQELBQAwgYYxEzARBgoJkiaJk/IsZAEZFgND
+T00xFzAVBgoJkiaJk/IsZAEZFgdFWEFNUExFMR4wHAYDVQQLDBVDZXJ0aWZpY2F0
+ZSBBdXRob3JpdHkxFzAVBgNVBAMMDmNhLmV4YW1wbGUuY29tMR0wGwYJKoZIhvcN
+AQkBFg5jYUBleGFtcGxlLmNvbTAeFw0xNzA0MjEwODUwMjdaFw00MjA0MTUwODUw
+MjdaMGIxEzARBgoJkiaJk/IsZAEZFgNDT00xFzAVBgoJkiaJk/IsZAEZFgdFWEFN
+UExFMQ8wDQYDVQQDDAZDbGllbnQxITAfBgkqhkiG9w0BCQEWEmNsaWVudEBleGFt
+cGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALcDxJFF30lE
+s/w8KN7ENjhaXosDqOe/IiNTStg+f1CL+/bKdcSu8wTyQsltv/+fi/jiw4ls1chP
+Eni7r+HtkPdMVG5mvuaGzPFyVCl1YkOihS0v0+YQkm83LcC7jU2+dvrDQYMFWH9d
+ehfFur9Cwmur5EH5Xl2nKehYifMYmljh/jPMPdCj6xWGUN6p/k459hz1JGvfWlqa
+1o/35j9uakjBtsFeOKT5SEZsg2S9DudYsHfC/ncXl1LrJCFzQBY1ifhDr3FHrEsM
+ieoAi4+qNq1ZZxwzppB81MAyggaJmqHUo/IpvJxWF8AhK202skiDYURk7k1kyT7g
+ZWRwl72Wz/kCAwEAATANBgkqhkiG9w0BAQsFAAOBgQAPiq0yRWbFD+17cz5TrRsG
+kapRrVmwqpX4nrv+pvBgzT6aatV5SZDXq+jqw1L2n2B/DEUwDXJ0R8vV0J2hE/KE
++7YRWgM0LyT/iYp5CC1n3GKpirxarz5hwXHVmNsMnYjLRc/4NVGkyDOqTZIPN106
+C8hyhUIMHGLBqWMxCG7myQ==
+-----END CERTIFICATE-----
diff --git a/tls/tests/files/create-files.sh b/tls/tests/files/create-files.sh
index 0a7140f..a887562 100755
--- a/tls/tests/files/create-files.sh
+++ b/tls/tests/files/create-files.sh
@@ -124,6 +124,14 @@ openssl x509 -req -in client-csr.pem -days 365 -startdate -enddate -CA ca.pem -C
sudo hwclock -s
touch client-future.pem
+msg "Creating second client key pair"
+openssl genrsa -out client2-key.pem 2048
+openssl req -config ssl/client.conf -key client2-key.pem -new -out client2-csr.pem
+openssl x509 -req -in client2-csr.pem -days 9125 -CA ca.pem -CAkey ca-key.pem -CAserial serial -out
client2.pem
+
+msg "Concatenating second client certificate and private key into a single file"
+cat client2.pem client2-key.pem > client2-and-key.pem
+
#######################################################################
### Concatenate all non-CA certificates
#######################################################################
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]