[glib-networking/wip/danw/tls-info: 1/2] gnutls: implement GTlsConnection:connection-info



commit 3e4be903728e744e41d44ba62d6e35f1575205d5
Author: Dan Winship <danw gnome org>
Date:   Mon Mar 23 09:56:21 2015 -0400

    gnutls: implement GTlsConnection:connection-info

 tls/gnutls/gtlsconnection-gnutls.c |  110 ++++++++++++++++++++++++++-
 tls/tests/connection.c             |  150 +++++++++++++++++++++++++++++++-----
 2 files changed, 239 insertions(+), 21 deletions(-)
---
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index 7436451..afc5655 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -87,7 +87,8 @@ enum
   PROP_CERTIFICATE,
   PROP_INTERACTION,
   PROP_PEER_CERTIFICATE,
-  PROP_PEER_CERTIFICATE_ERRORS
+  PROP_PEER_CERTIFICATE_ERRORS,
+  PROP_CONNECTION_INFO
 };
 
 struct _GTlsConnectionGnutlsPrivate
@@ -372,6 +373,102 @@ g_tls_connection_gnutls_finalize (GObject *object)
 }
 
 static void
+get_connection_info (GTlsConnectionGnutls *gnutls,
+                    GValue               *value)
+{
+  GVariantBuilder builder;
+  gnutls_protocol_t proto;
+  GTlsVersion version;
+  gnutls_kx_algorithm_t kx, cur_kx;
+  gnutls_cipher_algorithm_t cipher, cur_cipher;
+  gnutls_mac_algorithm_t mac, cur_mac;
+  char *cipher_suite, *p;
+  int dh_prime_size;
+
+  /* Unfortunately GNUTLS doesn't provide any API for this...
+   * If this becomes a problem, we could snoop the version
+   * from g_tls_connection_gnutls_pull_func()...
+   */
+  switch (gnutls_protocol_get_version (gnutls->priv->session))
+    {
+    case GNUTLS_SSL3:
+      version = G_TLS_VERSION_SSL_3_0;
+    case GNUTLS_TLS1_0:
+      version = G_TLS_VERSION_TLS_1_0;
+    case GNUTLS_TLS1_1:
+      version = G_TLS_VERSION_TLS_1_1;
+    case GNUTLS_TLS1_2:
+      version = G_TLS_VERSION_TLS_1_2;
+    case GNUTLS_DTLS1_0:
+      version = G_TLS_VERSION_DTLS_1_0;
+    case GNUTLS_DTLS1_2:
+      version = G_TLS_VERSION_DTLS_1_2;
+    case GNUTLS_VERSION_UNKNOWN:
+      g_value_set_variant (value, NULL);
+      return;
+    default:
+      g_warning ("Unrecognized gnutls_protocol_t value!");
+      version = G_TLS_VERSION_INVALID;
+    }
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+  g_variant_builder_add (&builder, "{sv}",
+                        "version",
+                        g_variant_new_int16 (version));
+
+  cur_kx = gnutls_kx_get (gnutls->priv->session);
+  cur_cipher = gnutls_cipher_get (gnutls->priv->session);
+  cur_mac = gnutls_mac_get (gnutls->priv->session);
+
+  g_variant_builder_add (&builder, "{sv}",
+                        "key-exchange", 
+                        g_variant_new_string (gnutls_kx_get_name (cur_kx)));
+  g_variant_builder_add (&builder, "{sv}",
+                        "cipher", 
+                        g_variant_new_string (gnutls_cipher_get_name (cur_cipher)));
+  g_variant_builder_add (&builder, "{sv}",
+                        "key-size", 
+                        g_variant_new_int32 (gnutls_cipher_get_key_size (cur_cipher)));
+  g_variant_builder_add (&builder, "{sv}",
+                        "mac", 
+                        g_variant_new_string (gnutls_mac_get_name (cur_mac)));
+  g_variant_builder_add (&builder, "{sv}",
+                        "mac-size", 
+                        g_variant_new_int32 (gnutls_mac_get_key_size (cur_mac)));
+
+  /* The names returned by gnutls_cipher_suite_info() aren't in
+   * the form used in the spec.
+   */
+  cipher_suite = g_strdup_printf ("%s_%s_WITH_%s_%s",
+                                 version == G_TLS_VERSION_SSL3 ? "SSL" : "TLS",
+                                 gnutls_kx_get_name (cur_kx),
+                                 gnutls_cipher_get_name (cur_cipher),
+                                 gnutls_mac_get_name (cur_mac));
+  for (p = cipher_suite; *p; p++)
+    {
+      if (*p == '-')
+       *p = '_';
+    }
+  g_variant_builder_add (&builder, "{sv}",
+                        "cipher-suite", 
+                        g_variant_new_take_string (cipher_suite));
+
+  dh_prime_size = gnutls_dh_get_prime_bits (gnutls->priv->session);
+  if (dh_prime_size) 
+    {
+      g_variant_builder_add (&builder, "{sv}",
+                            "dh-prime-size", 
+                            g_variant_new_int32 (dh_prime_size));
+    }
+
+  g_variant_builder_add (&builder, "{sv}",
+                        "ext-renegotiation-info", 
+                        g_variant_new_boolean (gnutls_safe_renegotiation_status (gnutls->priv->session) != 
0));
+
+  g_value_take_variant (value, g_variant_builder_end (&builder));
+}
+
+static void
 g_tls_connection_gnutls_get_property (GObject    *object,
                                      guint       prop_id,
                                      GValue     *value,
@@ -424,6 +521,13 @@ g_tls_connection_gnutls_get_property (GObject    *object,
       g_value_set_flags (value, gnutls->priv->peer_certificate_errors);
       break;
 
+    case PROP_CONNECTION_INFO:
+      if (!gnutls->priv->ever_handshaked)
+       g_value_set_variant (value, NULL);
+      else
+       get_connection_info (gnutls, value);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -1768,6 +1872,10 @@ g_tls_connection_gnutls_class_init (GTlsConnectionGnutlsClass *klass)
   g_object_class_override_property (gobject_class, PROP_INTERACTION, "interaction");
   g_object_class_override_property (gobject_class, PROP_PEER_CERTIFICATE, "peer-certificate");
   g_object_class_override_property (gobject_class, PROP_PEER_CERTIFICATE_ERRORS, "peer-certificate-errors");
+  g_object_class_override_property (gobject_class, PROP_VERSION, "version");
+  g_object_class_override_property (gobject_class, PROP_VERSION_NAME, "version-name");
+  g_object_class_override_property (gobject_class, PROP_CIPHER_SUITE, "cipher-suite");
+  g_object_class_override_property (gobject_class, PROP_CIPHER_SUITE_NAME, "cipher-suite-name");
 }
 
 static void
diff --git a/tls/tests/connection.c b/tls/tests/connection.c
index 6bcb9c2..155ab58 100644
--- a/tls/tests/connection.c
+++ b/tls/tests/connection.c
@@ -1417,25 +1417,28 @@ quit_on_handshake_complete (GObject      *object,
   return;
 }
 
-#define PRIORITY_SSL_FALLBACK "NORMAL:+VERS-SSL3.0"
-#define PRIORITY_TLS_FALLBACK "NORMAL:+VERS-TLS-ALL:-VERS-SSL3.0"
+typedef struct {
+  GTlsVersion version;
+  const char *version_name;
+} TestVersionData;
 
 static void
-test_fallback (gconstpointer data)
+test_priority_string (gconstpointer data)
 {
-  const char *priority_string = (const char *) data;
-  char *test_name;
+  const char *subtest_name = (const char *) data;
 
-  test_name = g_strdup_printf ("/tls/connection/fallback/subprocess/%s", priority_string);
-  g_test_trap_subprocess (test_name, 0, 0);
+  g_test_trap_subprocess (subtest_name, 0, 0);
   g_test_trap_assert_passed ();
-  g_free (test_name);
 }
 
+#define PRIORITY_SSL_FALLBACK "NORMAL:+VERS-SSL3.0"
+#define PRIORITY_TLS_FALLBACK "NORMAL:+VERS-TLS-ALL:-VERS-SSL3.0"
+
 static void
 test_fallback_subprocess (TestConnection *test,
-                         gconstpointer   data)
+                         gconstpointer   test_data)
 {
+  const TestVersionData *data = (const TestVersionData *) test_data;
   GIOStream *connection;
   GTlsConnection *tlsconn;
   GError *error = NULL;
@@ -1446,6 +1449,9 @@ test_fallback_subprocess (TestConnection *test,
   tlsconn = G_TLS_CONNECTION (test->client_connection);
   g_object_unref (connection);
 
+  g_assert_cmpint (g_tls_connection_get_version (tlsconn), ==, G_TLS_VERSION_INVALID);
+  g_assert_cmpstr (g_tls_connection_get_version_name (tlsconn), ==, NULL);
+
   g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (test->client_connection),
                                                 0);
   g_tls_client_connection_set_use_ssl3 (G_TLS_CLIENT_CONNECTION (test->client_connection),
@@ -1454,9 +1460,79 @@ test_fallback_subprocess (TestConnection *test,
                                    quit_on_handshake_complete, test);
   g_main_loop_run (test->loop);
 
-  /* In 2.42 we don't have the API to test that the correct version was negotiated,
-   * so we merely test that the connection succeeded at all.
-   */
+  g_assert_cmpint (g_tls_connection_get_version (tlsconn), ==, data->version);
+  g_assert_cmpstr (g_tls_connection_get_version_name (tlsconn), ==, data->version_name);
+
+  g_io_stream_close (test->client_connection, NULL, &error);
+  g_assert_no_error (error);
+}
+
+#define PRIORITY_TLS_1_0_ONLY "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.0"
+#define PRIORITY_TLS_1_1_ONLY "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.1"
+#define PRIORITY_RSA_ONLY "NONE:+VERS-TLS-ALL:+RSA:+AES-256-CBC:+SHA256:+SIGN-ALL:+COMP-NULL"
+
+static void
+test_version (TestConnection *test,
+             gconstpointer   test_data)
+{
+  const TestVersionData *data = (const TestVersionData *) test_data;
+  GIOStream *connection;
+  GTlsConnection *tlsconn;
+  GError *error = NULL;
+
+  connection = start_echo_server_and_connect_to_it (test);
+  test->client_connection = g_tls_client_connection_new (connection, NULL, &error);
+  g_assert_no_error (error);
+  tlsconn = G_TLS_CONNECTION (test->client_connection);
+  g_object_unref (connection);
+
+  g_assert_cmpint (g_tls_connection_get_version (tlsconn), ==, G_TLS_VERSION_INVALID);
+  g_assert_cmpstr (g_tls_connection_get_version_name (tlsconn), ==, NULL);
+
+  g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (test->client_connection),
+                                                0);
+  g_tls_connection_handshake_async (tlsconn, G_PRIORITY_DEFAULT, NULL,
+                                   quit_on_handshake_complete, test);
+  g_main_loop_run (test->loop);
+
+  g_assert_cmpint (g_tls_connection_get_version (tlsconn), ==, data->version);
+  g_assert_cmpstr (g_tls_connection_get_version_name (tlsconn), ==, data->version_name);
+
+  g_io_stream_close (test->client_connection, NULL, &error);
+  g_assert_no_error (error);
+}
+
+typedef struct {
+  guint cipher_suite;
+  const char *cipher_suite_name;
+} TestCipherSuiteData;
+
+static void
+test_cipher_suite (TestConnection *test,
+                  gconstpointer   test_data)
+{
+  const TestCipherSuiteData *data = (const TestCipherSuiteData *) test_data;
+  GIOStream *connection;
+  GTlsConnection *tlsconn;
+  GError *error = NULL;
+
+  connection = start_echo_server_and_connect_to_it (test);
+  test->client_connection = g_tls_client_connection_new (connection, NULL, &error);
+  g_assert_no_error (error);
+  tlsconn = G_TLS_CONNECTION (test->client_connection);
+  g_object_unref (connection);
+
+  g_assert_cmpint (g_tls_connection_get_cipher_suite (tlsconn), ==, 0x0000);
+  g_assert_cmpstr (g_tls_connection_get_cipher_suite_name (tlsconn), ==, "TLS_NULL_WITH_NULL_NULL");
+
+  g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (test->client_connection),
+                                                0);
+  g_tls_connection_handshake_async (tlsconn, G_PRIORITY_DEFAULT, NULL,
+                                   quit_on_handshake_complete, test);
+  g_main_loop_run (test->loop);
+
+  g_assert_cmpint (g_tls_connection_get_cipher_suite (tlsconn), ==, data->cipher_suite);
+  g_assert_cmpstr (g_tls_connection_get_cipher_suite_name (tlsconn), ==, data->cipher_suite_name);
 
   g_io_stream_close (test->client_connection, NULL, &error);
   g_assert_no_error (error);
@@ -1535,14 +1611,48 @@ main (int   argc,
   g_test_add ("/tls/connection/async-implicit-handshake", TestConnection, NULL,
               setup_connection, test_async_implicit_handshake, teardown_connection);
 
-  g_test_add_data_func ("/tls/connection/fallback/SSL", PRIORITY_SSL_FALLBACK, test_fallback);
-  g_test_add ("/tls/connection/fallback/subprocess/" PRIORITY_SSL_FALLBACK,
-             TestConnection, NULL,
-              setup_connection, test_fallback_subprocess, teardown_connection);
-  g_test_add_data_func ("/tls/connection/fallback/TLS", PRIORITY_TLS_FALLBACK, test_fallback);
-  g_test_add ("/tls/connection/fallback/subprocess/" PRIORITY_TLS_FALLBACK,
-             TestConnection, NULL,
-              setup_connection, test_fallback_subprocess, teardown_connection);
+  {
+    TestVersionData ssl3 = { G_TLS_VERSION_SSL_3_0, "SSL3.0" };
+    TestVersionData tls10 = { G_TLS_VERSION_TLS_1_0, "TLS1.0" };
+    TestVersionData tls11 = { G_TLS_VERSION_TLS_1_1, "TLS1.1" };
+
+    g_test_add_data_func ("/tls/connection/fallback/SSL",
+                         "/tls/connection/fallback/subprocess/" PRIORITY_SSL_FALLBACK,
+                         test_priority_string);
+    g_test_add ("/tls/connection/fallback/subprocess/" PRIORITY_SSL_FALLBACK,
+               TestConnection, &ssl3,
+               setup_connection, test_fallback_subprocess, teardown_connection);
+    g_test_add_data_func ("/tls/connection/fallback/TLS",
+                         "/tls/connection/fallback/subprocess/" PRIORITY_TLS_FALLBACK,
+                         test_priority_string);
+    g_test_add ("/tls/connection/fallback/subprocess/" PRIORITY_TLS_FALLBACK,
+               TestConnection, &tls10,
+               setup_connection, test_fallback_subprocess, teardown_connection);
+
+    g_test_add_data_func ("/tls/connection/version/TLS1.0",
+                         "/tls/connection/version/TLS1.0/subprocess/" PRIORITY_TLS_1_0_ONLY,
+                         test_priority_string);
+    g_test_add ("/tls/connection/version/TLS1.0/subprocess/" PRIORITY_TLS_1_0_ONLY,
+               TestConnection, &tls10,
+               setup_connection, test_version, teardown_connection);
+    g_test_add_data_func ("/tls/connection/version/TLS1.1",
+                         "/tls/connection/version/TLS1.1/subprocess/" PRIORITY_TLS_1_1_ONLY,
+                         test_priority_string);
+    g_test_add ("/tls/connection/version/TLS1.1/subprocess/" PRIORITY_TLS_1_1_ONLY,
+               TestConnection, &tls11,
+               setup_connection, test_version, teardown_connection);
+  }
+
+  {
+    TestCipherSuiteData rsa = { 0x003D, "TLS_RSA_WITH_AES_256_CBC_SHA256" };
+
+    g_test_add_data_func ("/tls/connection/cipher-suite/RSA",
+                         "/tls/connection/cipher-suite/RSA/subprocess/" PRIORITY_RSA_ONLY,
+                         test_priority_string);
+    g_test_add ("/tls/connection/cipher-suite/RSA/subprocess/" PRIORITY_RSA_ONLY,
+               TestConnection, &rsa,
+               setup_connection, test_cipher_suite, teardown_connection);
+  }
 
   ret = g_test_run();
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]