[glib-networking/mcatanzaro/tls-info: 42/42] tls: Implement protocol version and ciphersuite name accessors
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking/mcatanzaro/tls-info: 42/42] tls: Implement protocol version and ciphersuite name accessors
- Date: Wed, 23 Jun 2021 19:23:54 +0000 (UTC)
commit 000e32b565ea79578504b78cd64c9ecad65cae39
Author: Michael Catanzaro <mcatanzaro gnome org>
Date: Thu Apr 29 16:19:48 2021 -0500
tls: Implement protocol version and ciphersuite name accessors
This allows the application to display protocol version and ciphersuite
name. This implements the APIs added in glib!2077.
tls/base/gtlsconnection-base.c | 44 ++++++++++++++++----
tls/base/gtlsconnection-base.h | 2 +
tls/gnutls/gtlsclientconnection-gnutls.c | 17 +++++---
tls/gnutls/gtlsconnection-gnutls.c | 64 +++++++++++++++++++++++++++---
tls/openssl/gtlsclientconnection-openssl.c | 17 +++++---
tls/openssl/gtlsconnection-openssl.c | 45 ++++++++++++++++++---
tls/tests/connection.c | 33 +++++++++++++++
7 files changed, 193 insertions(+), 29 deletions(-)
---
diff --git a/tls/base/gtlsconnection-base.c b/tls/base/gtlsconnection-base.c
index b68a940..dd23c46 100644
--- a/tls/base/gtlsconnection-base.c
+++ b/tls/base/gtlsconnection-base.c
@@ -161,6 +161,9 @@ G_GNUC_END_IGNORE_DEPRECATIONS
gchar **advertised_protocols;
gchar *negotiated_protocol;
+
+ GTlsProtocolVersion protocol_version;
+ gchar *ciphersuite_name;
} GTlsConnectionBasePrivate;
static void g_tls_connection_base_dtls_connection_iface_init (GDtlsConnectionInterface *iface);
@@ -212,6 +215,8 @@ enum
PROP_PEER_CERTIFICATE_ERRORS,
PROP_ADVERTISED_PROTOCOLS,
PROP_NEGOTIATED_PROTOCOL,
+ PROP_PROTOCOL_VERSION,
+ PROP_CIPHERSUITE_NAME
};
gboolean
@@ -282,6 +287,8 @@ g_tls_connection_base_finalize (GObject *object)
g_clear_pointer (&priv->advertised_protocols, g_strfreev);
g_clear_pointer (&priv->negotiated_protocol, g_free);
+ g_clear_pointer (&priv->ciphersuite_name, g_free);
+
G_OBJECT_CLASS (g_tls_connection_base_parent_class)->finalize (object);
}
@@ -351,6 +358,14 @@ g_tls_connection_base_get_property (GObject *object,
g_value_set_string (value, priv->negotiated_protocol);
break;
+ case PROP_PROTOCOL_VERSION:
+ g_value_set_enum (value, priv->protocol_version);
+ break;
+
+ case PROP_CIPHERSUITE_NAME:
+ g_value_set_string (value, priv->ciphersuite_name);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -1616,12 +1631,16 @@ finish_handshake (GTlsConnectionBase *tls,
GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
GTlsConnectionBaseClass *tls_class = G_TLS_CONNECTION_BASE_GET_CLASS (tls);
gchar *original_negotiated_protocol;
+ gchar *original_ciphersuite_name;
+ GTlsProtocolVersion original_protocol_version;
gboolean success;
GError *my_error = NULL;
g_tls_log_debug (tls, "finishing TLS handshake");
original_negotiated_protocol = g_steal_pointer (&priv->negotiated_protocol);
+ original_ciphersuite_name = g_steal_pointer (&priv->ciphersuite_name);
+ original_protocol_version = priv->protocol_version;
success = g_task_propagate_boolean (task, &my_error);
if (success)
@@ -1659,16 +1678,25 @@ finish_handshake (GTlsConnectionBase *tls,
}
}
- if (tls_class->complete_handshake)
- {
- /* If we already have an error, ignore further errors. */
- tls_class->complete_handshake (tls, success, &priv->negotiated_protocol, my_error ? NULL : &my_error);
+ tls_class->complete_handshake (tls,
+ success,
+ &priv->negotiated_protocol,
+ &priv->protocol_version,
+ &priv->ciphersuite_name,
+ /* If we already have an error, ignore further errors. */
+ my_error ? NULL : &my_error);
- if (g_strcmp0 (original_negotiated_protocol, priv->negotiated_protocol) != 0)
- g_object_notify (G_OBJECT (tls), "negotiated-protocol");
- }
+ if (g_strcmp0 (original_negotiated_protocol, priv->negotiated_protocol) != 0)
+ g_object_notify (G_OBJECT (tls), "negotiated-protocol");
g_free (original_negotiated_protocol);
+ if (original_protocol_version != priv->protocol_version)
+ g_object_notify (G_OBJECT (tls), "protocol-version");
+
+ if (g_strcmp0 (original_ciphersuite_name, priv->ciphersuite_name) != 0)
+ g_object_notify (G_OBJECT (tls), "ciphersuite-name");
+ g_free (original_ciphersuite_name);
+
if (my_error && priv->started_handshake)
priv->handshake_error = g_error_copy (my_error);
@@ -2777,6 +2805,8 @@ g_tls_connection_base_class_init (GTlsConnectionBaseClass *klass)
g_object_class_override_property (gobject_class, PROP_PEER_CERTIFICATE_ERRORS, "peer-certificate-errors");
g_object_class_override_property (gobject_class, PROP_ADVERTISED_PROTOCOLS, "advertised-protocols");
g_object_class_override_property (gobject_class, PROP_NEGOTIATED_PROTOCOL, "negotiated-protocol");
+ g_object_class_override_property (gobject_class, PROP_PROTOCOL_VERSION, "protocol-version");
+ g_object_class_override_property (gobject_class, PROP_CIPHERSUITE_NAME, "ciphersuite-name");
}
static void
diff --git a/tls/base/gtlsconnection-base.h b/tls/base/gtlsconnection-base.h
index a89122e..4541f54 100644
--- a/tls/base/gtlsconnection-base.h
+++ b/tls/base/gtlsconnection-base.h
@@ -75,6 +75,8 @@ struct _GTlsConnectionBaseClass
void (*complete_handshake) (GTlsConnectionBase *tls,
gboolean handshake_succeeded,
gchar **negotiated_protocol,
+ GTlsProtocolVersion *protocol_version,
+ gchar **ciphersuite_name,
GError **error);
gboolean (*is_session_resumed) (GTlsConnectionBase *tls);
diff --git a/tls/gnutls/gtlsclientconnection-gnutls.c b/tls/gnutls/gtlsclientconnection-gnutls.c
index 6f4cd23..7df0488 100644
--- a/tls/gnutls/gtlsclientconnection-gnutls.c
+++ b/tls/gnutls/gtlsclientconnection-gnutls.c
@@ -493,16 +493,23 @@ g_tls_client_connection_gnutls_prepare_handshake (GTlsConnectionBase *tls,
}
static void
-g_tls_client_connection_gnutls_complete_handshake (GTlsConnectionBase *tls,
- gboolean handshake_succeeded,
- gchar **negotiated_protocol,
- GError **error)
+g_tls_client_connection_gnutls_complete_handshake (GTlsConnectionBase *tls,
+ gboolean handshake_succeeded,
+ gchar **negotiated_protocol,
+ GTlsProtocolVersion *protocol_version,
+ gchar **ciphersuite_name,
+ GError **error)
{
GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (tls);
gnutls_session_t session;
gnutls_protocol_t version;
- G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_gnutls_parent_class)->complete_handshake (tls,
handshake_succeeded, negotiated_protocol, error);
+ G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_gnutls_parent_class)->complete_handshake (tls,
+
handshake_succeeded,
+
negotiated_protocol,
+
protocol_version,
+
ciphersuite_name,
+ error);
/* It may have changed during the handshake, but we have to wait until here
* because we can't emit notifies on the handshake thread.
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index 1b7fd85..cc07c1f 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -907,23 +907,75 @@ g_tls_connection_gnutls_handshake_thread_handshake (GTlsConnectionBase *tls,
return status;
}
+static GTlsProtocolVersion
+glib_protocol_version_from_gnutls (gnutls_protocol_t protocol_version)
+{
+ switch (protocol_version)
+ {
+ case GNUTLS_SSL3:
+ return G_TLS_PROTOCOL_VERSION_SSL_3_0;
+ case GNUTLS_TLS1_0:
+ return G_TLS_PROTOCOL_VERSION_TLS_1_0;
+ case GNUTLS_TLS1_1:
+ return G_TLS_PROTOCOL_VERSION_TLS_1_1;
+ case GNUTLS_TLS1_2:
+ return G_TLS_PROTOCOL_VERSION_TLS_1_2;
+ case GNUTLS_TLS1_3:
+ return G_TLS_PROTOCOL_VERSION_TLS_1_3;
+ case GNUTLS_DTLS0_9:
+ return G_TLS_PROTOCOL_VERSION_UNKNOWN;
+ case GNUTLS_DTLS1_0:
+ return G_TLS_PROTOCOL_VERSION_DTLS_1_0;
+ case GNUTLS_DTLS1_2:
+ return G_TLS_PROTOCOL_VERSION_DTLS_1_2;
+ default:
+ return G_TLS_PROTOCOL_VERSION_UNKNOWN;
+ }
+}
+
+static gchar *
+get_ciphersuite_name (gnutls_session_t session)
+{
+ gnutls_protocol_t protocol_version = gnutls_protocol_get_version (session);
+
+ if (protocol_version <= GNUTLS_TLS1_2 ||
+ (protocol_version >= GNUTLS_DTLS0_9 && protocol_version <= GNUTLS_DTLS1_2))
+ {
+ return g_strdup (gnutls_cipher_suite_get_name (gnutls_kx_get (session),
+ gnutls_cipher_get (session),
+ gnutls_mac_get (session)));
+ }
+
+ return g_strdup_printf ("TLS_%s_%s",
+ gnutls_cipher_get_name (gnutls_cipher_get (session)),
+ gnutls_digest_get_name (gnutls_prf_hash_get (session)));
+
+}
+
static void
-g_tls_connection_gnutls_complete_handshake (GTlsConnectionBase *tls,
- gboolean handshake_succeeded,
- gchar **negotiated_protocol,
- GError **error)
+g_tls_connection_gnutls_complete_handshake (GTlsConnectionBase *tls,
+ gboolean handshake_succeeded,
+ gchar **negotiated_protocol,
+ GTlsProtocolVersion *protocol_version,
+ gchar **ciphersuite_name,
+ GError **error)
{
GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (tls);
GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
gnutls_datum_t protocol;
- if (handshake_succeeded &&
- gnutls_alpn_get_selected_protocol (priv->session, &protocol) == 0 &&
+ if (!handshake_succeeded)
+ return;
+
+ if (gnutls_alpn_get_selected_protocol (priv->session, &protocol) == 0 &&
protocol.size > 0)
{
g_assert (!*negotiated_protocol);
*negotiated_protocol = g_strndup ((gchar *)protocol.data, protocol.size);
}
+
+ *protocol_version = glib_protocol_version_from_gnutls (gnutls_protocol_get_version (priv->session));
+ *ciphersuite_name = get_ciphersuite_name (priv->session);
}
static gboolean
diff --git a/tls/openssl/gtlsclientconnection-openssl.c b/tls/openssl/gtlsclientconnection-openssl.c
index 0e83b03..1adb9fe 100644
--- a/tls/openssl/gtlsclientconnection-openssl.c
+++ b/tls/openssl/gtlsclientconnection-openssl.c
@@ -185,15 +185,22 @@ g_tls_client_connection_openssl_set_property (GObject *object,
}
static void
-g_tls_client_connection_openssl_complete_handshake (GTlsConnectionBase *tls,
- gboolean handshake_succeeded,
- gchar **negotiated_protocol,
- GError **error)
+g_tls_client_connection_openssl_complete_handshake (GTlsConnectionBase *tls,
+ gboolean handshake_succeeded,
+ gchar **negotiated_protocol,
+ GTlsProtocolVersion *protocol_version,
+ gchar **ciphersuite_name,
+ GError **error)
{
GTlsClientConnectionOpenssl *client = G_TLS_CLIENT_CONNECTION_OPENSSL (tls);
if (G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_openssl_parent_class)->complete_handshake)
- G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_openssl_parent_class)->complete_handshake (tls,
handshake_succeeded, negotiated_protocol, error);
+ G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_openssl_parent_class)->complete_handshake (tls,
+
handshake_succeeded,
+
negotiated_protocol,
+
protocol_version,
+
ciphersuite_name,
+ error);
/* It may have changed during the handshake, but we have to wait until here
* because we can't emit notifies on the handshake thread.
diff --git a/tls/openssl/gtlsconnection-openssl.c b/tls/openssl/gtlsconnection-openssl.c
index e756fa7..648645c 100644
--- a/tls/openssl/gtlsconnection-openssl.c
+++ b/tls/openssl/gtlsconnection-openssl.c
@@ -482,14 +482,42 @@ g_tls_connection_openssl_prepare_handshake (GTlsConnectionBase *tls,
g_byte_array_unref (protocols);
}
}
+#endif
+
+static GTlsProtocolVersion
+glib_protocol_version_from_openssl (int protocol_version)
+{
+ switch (protocol_version)
+ {
+ case SSL3_VERSION:
+ return G_TLS_PROTOCOL_VERSION_SSL_3_0;
+ case TLS1_VERSION:
+ return G_TLS_PROTOCOL_VERSION_TLS_1_0;
+ case TLS1_1_VERSION:
+ return G_TLS_PROTOCOL_VERSION_TLS_1_1;
+ case TLS1_2_VERSION:
+ return G_TLS_PROTOCOL_VERSION_TLS_1_2;
+ case TLS1_3_VERSION:
+ return G_TLS_PROTOCOL_VERSION_TLS_1_3;
+ case DTLS1_VERSION:
+ return G_TLS_PROTOCOL_VERSION_DTLS_1_0;
+ case DTLS1_2_VERSION:
+ return G_TLS_PROTOCOL_VERSION_DTLS_1_2;
+ default:
+ return G_TLS_PROTOCOL_VERSION_UNKNOWN;
+ }
+}
static void
-g_tls_connection_openssl_complete_handshake (GTlsConnectionBase *tls,
- gboolean handshake_succeeded,
- gchar **negotiated_protocol,
- GError **error)
+g_tls_connection_openssl_complete_handshake (GTlsConnectionBase *tls,
+ gboolean handshake_succeeded,
+ gchar **negotiated_protocol,
+ GTlsProtocolVersion *protocol_version,
+ gchar **ciphersuite_name,
+ GError **error)
{
SSL *ssl;
+ SSL_SESSION *session;
unsigned int len = 0;
const unsigned char *data = NULL;
@@ -497,7 +525,9 @@ g_tls_connection_openssl_complete_handshake (GTlsConnectionBase *tls,
return;
ssl = g_tls_connection_openssl_get_ssl (G_TLS_CONNECTION_OPENSSL (tls));
+ session = SSL_get_session (ssl);
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L || defined (LIBRESSL_VERSION_NUMBER)
SSL_get0_alpn_selected (ssl, &data, &len);
g_tls_log_debug (tls, "negotiated ALPN protocols: [%d]%p", len, data);
@@ -507,9 +537,12 @@ g_tls_connection_openssl_complete_handshake (GTlsConnectionBase *tls,
g_assert (!*negotiated_protocol);
*negotiated_protocol = g_strndup ((gchar *)data, len);
}
-}
#endif
+ *protocol_version = glib_protocol_version_from_openssl (SSL_SESSION_get_protocol_version (session));
+ *ciphersuite_name = g_strdup (SSL_get_cipher_name (ssl));
+}
+
static int
perform_rehandshake (SSL *ssl,
gpointer user_data)
@@ -1005,8 +1038,8 @@ g_tls_connection_openssl_class_init (GTlsConnectionOpensslClass *klass)
#if OPENSSL_VERSION_NUMBER >= 0x10002000L || defined (LIBRESSL_VERSION_NUMBER)
base_class->prepare_handshake = g_tls_connection_openssl_prepare_handshake;
- base_class->complete_handshake = g_tls_connection_openssl_complete_handshake;
#endif
+ base_class->complete_handshake = g_tls_connection_openssl_complete_handshake;
base_class->handshake_thread_safe_renegotiation_status =
g_tls_connection_openssl_handshake_thread_safe_renegotiation_status;
base_class->handshake_thread_request_rehandshake =
g_tls_connection_openssl_handshake_thread_request_rehandshake;
base_class->handshake_thread_handshake =
g_tls_connection_openssl_handshake_thread_handshake;
diff --git a/tls/tests/connection.c b/tls/tests/connection.c
index b0dd9d8..e5ed014 100644
--- a/tls/tests/connection.c
+++ b/tls/tests/connection.c
@@ -2937,6 +2937,37 @@ test_peer_certificate_notify (TestConnection *test,
#endif
}
+static void
+test_tls_info (TestConnection *test,
+ gconstpointer data)
+{
+ GIOStream *connection;
+ GError *error = NULL;
+
+ connection = start_async_server_and_connect_to_it (test, G_TLS_AUTHENTICATION_NONE);
+ test->client_connection = g_tls_client_connection_new (connection, test->identity, &error);
+ g_assert_no_error (error);
+ g_object_unref (connection);
+
+ g_assert_cmpint (g_tls_connection_get_protocol_version (G_TLS_CONNECTION (test->client_connection)), ==,
G_TLS_PROTOCOL_VERSION_UNKNOWN);
+ g_assert_null (g_tls_connection_get_ciphersuite_name (G_TLS_CONNECTION (test->client_connection)));
+
+ /* No validation at all in this test */
+ g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (test->client_connection),
+ 0);
+
+
+ read_test_data_async (test);
+ g_main_loop_run (test->loop);
+ wait_until_server_finished (test);
+
+ g_assert_no_error (test->read_error);
+ g_assert_no_error (test->server_error);
+
+ g_assert_cmpint (g_tls_connection_get_protocol_version (G_TLS_CONNECTION (test->client_connection)), !=,
G_TLS_PROTOCOL_VERSION_UNKNOWN);
+ g_assert_nonnull (g_tls_connection_get_ciphersuite_name (G_TLS_CONNECTION (test->client_connection)));
+}
+
int
main (int argc,
char *argv[])
@@ -3067,6 +3098,8 @@ main (int argc,
setup_connection, test_connection_binding_match_tls_server_end_point, teardown_connection);
g_test_add ("/tls/" BACKEND "/connection/binding/match-tls-exporter", TestConnection, NULL,
setup_connection, test_connection_binding_match_tls_exporter, teardown_connection);
+ g_test_add ("/tls/" BACKEND "/connection/tls-info", TestConnection, NULL,
+ setup_connection, test_tls_info, teardown_connection);
ret = g_test_run ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]