From 1b8db6c27f2f3909b55fc2902d2fd0431b066058 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sun, 26 Oct 2014 12:25:15 -0400 Subject: [PATCH 1/2] gnutls: loosen the semantics of "use-ssl3" If SSL 3.0 is disabled, then make "use-ssl3" mean "use the lowest available TLS version" instead, so that, eg, TLS 1.2 -> TLS 1.0 fallback is still possible. https://bugzilla.gnome.org/show_bug.cgi?id=738633 --- tls/gnutls/gtlsconnection-gnutls.c | 55 +++++++++++++++++------- tls/tests/connection.c | 88 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 16 deletions(-) diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c index 7e63412..444ca36 100644 --- a/tls/gnutls/gtlsconnection-gnutls.c +++ b/tls/gnutls/gtlsconnection-gnutls.c @@ -194,15 +194,16 @@ g_tls_connection_gnutls_init (GTlsConnectionGnutls *gnutls) g_mutex_init (&gnutls->priv->op_mutex); } -/* First field is "ssl3 only", second is "allow unsafe rehandshaking" */ +/* First field is "fallback", second is "allow unsafe rehandshaking" */ static gnutls_priority_t priorities[2][2]; static void g_tls_connection_gnutls_init_priorities (void) { const gchar *base_priority; - gchar *ssl3_priority, *unsafe_rehandshake_priority, *ssl3_unsafe_rehandshake_priority; - int ret; + gchar *fallback_priority, *unsafe_rehandshake_priority, *fallback_unsafe_rehandshake_priority; + const guint *protos; + int ret, i, nprotos, fallback_proto; base_priority = g_getenv ("G_TLS_GNUTLS_PRIORITY"); if (!base_priority) @@ -215,31 +216,53 @@ g_tls_connection_gnutls_init_priorities (void) gnutls_priority_init (&priorities[FALSE][FALSE], base_priority, NULL); } - ssl3_priority = g_strdup_printf ("%s:!VERS-TLS1.2:!VERS-TLS1.1:!VERS-TLS1.0", base_priority); unsafe_rehandshake_priority = g_strdup_printf ("%s:%%UNSAFE_RENEGOTIATION", base_priority); - ssl3_unsafe_rehandshake_priority = g_strdup_printf ("%s:!VERS-TLS1.2:!VERS-TLS1.1:!VERS-TLS1.0:%%UNSAFE_RENEGOTIATION", base_priority); - - gnutls_priority_init (&priorities[TRUE][FALSE], ssl3_priority, NULL); - gnutls_priority_init (&priorities[FALSE][TRUE], unsafe_rehandshake_priority, NULL); - gnutls_priority_init (&priorities[TRUE][TRUE], ssl3_unsafe_rehandshake_priority, NULL); - - g_free (ssl3_priority); + ret = gnutls_priority_init (&priorities[FALSE][TRUE], unsafe_rehandshake_priority, NULL); + g_warn_if_fail (ret == 0); g_free (unsafe_rehandshake_priority); - g_free (ssl3_unsafe_rehandshake_priority); + + /* Figure out the lowest SSl/TLS version supported by base_priority */ + nprotos = gnutls_priority_protocol_list (priorities[FALSE][FALSE], &protos); + fallback_proto = G_MAXUINT; + for (i = 0; i < nprotos; i++) + { + if (protos[i] < fallback_proto) + fallback_proto = protos[i]; + } + if (fallback_proto == G_MAXUINT) + { + g_warning ("All GNUTLS protocol versions disabled?"); + fallback_priority = g_strdup (base_priority); + } + else + { + fallback_priority = g_strdup_printf ("%s:!VERS-TLS-ALL:+VERS-%s", + base_priority, + gnutls_protocol_get_name (fallback_proto)); + } + fallback_unsafe_rehandshake_priority = g_strdup_printf ("%s:%%UNSAFE_RENEGOTIATION", + fallback_priority); + + ret = gnutls_priority_init (&priorities[TRUE][FALSE], fallback_priority, NULL); + g_warn_if_fail (ret == 0); + ret = gnutls_priority_init (&priorities[TRUE][TRUE], fallback_unsafe_rehandshake_priority, NULL); + g_warn_if_fail (ret == 0); + g_free (fallback_priority); + g_free (fallback_unsafe_rehandshake_priority); } static void g_tls_connection_gnutls_set_handshake_priority (GTlsConnectionGnutls *gnutls) { - gboolean use_ssl3, unsafe_rehandshake; + gboolean fallback, unsafe_rehandshake; if (G_IS_TLS_CLIENT_CONNECTION (gnutls)) - use_ssl3 = g_tls_client_connection_get_use_ssl3 (G_TLS_CLIENT_CONNECTION (gnutls)); + fallback = g_tls_client_connection_get_use_ssl3 (G_TLS_CLIENT_CONNECTION (gnutls)); else - use_ssl3 = FALSE; + fallback = FALSE; unsafe_rehandshake = (gnutls->priv->rehandshake_mode == G_TLS_REHANDSHAKE_UNSAFELY); gnutls_priority_set (gnutls->priv->session, - priorities[use_ssl3][unsafe_rehandshake]); + priorities[fallback][unsafe_rehandshake]); } static gboolean diff --git a/tls/tests/connection.c b/tls/tests/connection.c index 0df8bb1..0e7b706 100644 --- a/tls/tests/connection.c +++ b/tls/tests/connection.c @@ -1377,11 +1377,90 @@ test_async_implicit_handshake (TestConnection *test, gconstpointer data) test->client_connection = NULL; } +static void +quit_on_handshake_complete (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + TestConnection *test = user_data; + GError *error = NULL; + + g_tls_connection_handshake_finish (G_TLS_CONNECTION (object), result, &error); + g_assert_no_error (error); + + g_main_loop_quit (test->loop); + return; +} + +#define PRIORITY_SSL_FALLBACK "NORMAL:+VERS-SSL3.0" +#define PRIORITY_TLS_FALLBACK "NORMAL:+VERS-TLS-ALL:-VERS-SSL3.0" + +static void +test_fallback (gconstpointer data) +{ + const char *priority_string = (const char *) data; + char *test_name; + + test_name = g_strdup_printf ("/tls/connection/fallback/subprocess/%s", priority_string); + g_test_trap_subprocess (test_name, 0, 0); + g_test_trap_assert_passed (); + g_free (test_name); +} + +static void +test_fallback_subprocess (TestConnection *test, + gconstpointer 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_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), + TRUE); + g_tls_connection_handshake_async (tlsconn, G_PRIORITY_DEFAULT, NULL, + 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_io_stream_close (test->client_connection, NULL, &error); + g_assert_no_error (error); +} + int main (int argc, char *argv[]) { int ret; + int i; + + /* Check if this is a subprocess, and set G_TLS_GNUTLS_PRIORITY + * appropriately if so. + */ + for (i = 1; i < argc - 1; i++) + { + if (!strcmp (argv[i], "-p")) + { + const char *priority = argv[i + 1]; + + priority = strrchr (priority, '/'); + if (priority++ && + (g_str_has_prefix (priority, "NORMAL:") || + g_str_has_prefix (priority, "NONE:"))) + g_setenv ("G_TLS_GNUTLS_PRIORITY", priority, TRUE); + break; + } + } g_test_init (&argc, &argv, NULL); g_test_bug_base ("http://bugzilla.gnome.org/"); @@ -1431,6 +1510,15 @@ 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); + ret = g_test_run(); /* for valgrinding */ -- 2.1.0