[glib-networking/mcatanzaro/tls-info: 8/8] 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: 8/8] tls: Implement protocol version and ciphersuite name accessors
- Date: Tue, 25 May 2021 21:36:53 +0000 (UTC)
commit 0250e50e320a5fd53681c881221739c5794a3f51
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.
meson.build | 4 +-
tls/base/gtlsconnection-base.c | 46 +++++++++++++++++----
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 +++++++++++++++
8 files changed, 197 insertions(+), 31 deletions(-)
---
diff --git a/meson.build b/meson.build
index 6d15970..2c51bf1 100644
--- a/meson.build
+++ b/meson.build
@@ -29,7 +29,7 @@ common_flags = [
'-DG_LOG_USE_STRUCTURED',
'-DLOCALE_DIR="@0@"'.format(localedir),
'-DG_DISABLE_DEPRECATED',
- '-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_56'
+ '-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_70'
]
add_project_arguments(common_flags, language: 'c')
@@ -48,7 +48,7 @@ if host_system.contains('linux')
endif
# *** Check GLib GIO ***
-glib_dep = dependency('glib-2.0', version: '>= 2.67.0',
+glib_dep = dependency('glib-2.0', version: '>= 2.69.0',
fallback: ['glib', 'libglib_dep'])
gio_dep = dependency('gio-2.0',
fallback: ['glib', 'libgio_dep'])
diff --git a/tls/base/gtlsconnection-base.c b/tls/base/gtlsconnection-base.c
index dd87b1b..b13f08e 100644
--- a/tls/base/gtlsconnection-base.c
+++ b/tls/base/gtlsconnection-base.c
@@ -99,7 +99,9 @@ typedef struct
gboolean peer_certificate_examined;
gboolean require_close_notify;
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
GTlsRehandshakeMode rehandshake_mode;
+G_GNUC_END_IGNORE_DEPRECATIONS
/* need_handshake means the next claim_op() will get diverted into
* an implicit handshake (unless it's an OP_HANDSHAKE or OP_CLOSE*).
@@ -158,6 +160,9 @@ typedef struct
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);
@@ -209,6 +214,8 @@ enum
PROP_PEER_CERTIFICATE_ERRORS,
PROP_ADVERTISED_PROTOCOLS,
PROP_NEGOTIATED_PROTOCOL,
+ PROP_PROTOCOL_VERSION,
+ PROP_CIPHERSUITE_NAME
};
gboolean
@@ -279,6 +286,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);
}
@@ -348,6 +357,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);
}
@@ -1593,12 +1610,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)
@@ -1636,16 +1657,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);
@@ -2738,6 +2768,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 7312683..d837da4 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 bc3f9c8..c6d6c40 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -901,23 +901,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 95428c6..8cf32bd 100644
--- a/tls/openssl/gtlsclientconnection-openssl.c
+++ b/tls/openssl/gtlsclientconnection-openssl.c
@@ -183,15 +183,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 98bbb56..57be18e 100644
--- a/tls/openssl/gtlsconnection-openssl.c
+++ b/tls/openssl/gtlsconnection-openssl.c
@@ -358,14 +358,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;
@@ -373,7 +401,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);
@@ -383,9 +413,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));
+}
+
#define BEGIN_OPENSSL_IO(openssl, direction, timeout, cancellable) \
do { \
char error_str[256]; \
@@ -855,8 +888,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 036df04..6be8ee1 100644
--- a/tls/tests/connection.c
+++ b/tls/tests/connection.c
@@ -2913,6 +2913,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[])
@@ -3043,6 +3074,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]