[glib-networking] gnutls: preserve handshake errors
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking] gnutls: preserve handshake errors
- Date: Wed, 18 Jul 2012 21:47:49 +0000 (UTC)
commit e1a341ff46d6a741312a45ada989454f0daea0d0
Author: Dan Winship <danw gnome org>
Date: Sun Feb 12 11:30:22 2012 -0500
gnutls: preserve handshake errors
If an error occurs during handshake, remember it for later, since the
connection is now essentially broken.
tls/gnutls/gtlsconnection-gnutls.c | 39 +++++++++++++++----
tls/tests/connection.c | 72 +++++++++++++++++++++++++++++++----
2 files changed, 94 insertions(+), 17 deletions(-)
---
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index 3f872a9..65658e3 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -98,6 +98,7 @@ struct _GTlsConnectionGnutlsPrivate
GTlsDatabase *database;
gboolean database_is_unset;
gboolean need_handshake, handshaking, ever_handshaked;
+ GError *handshake_error;
gboolean closing;
GInputStream *tls_istream;
@@ -248,6 +249,7 @@ g_tls_connection_gnutls_finalize (GObject *object)
g_clear_object (&gnutls->priv->interaction);
g_clear_error (&gnutls->priv->error);
+ g_clear_error (&gnutls->priv->handshake_error);
G_OBJECT_CLASS (g_tls_connection_gnutls_parent_class)->finalize (object);
}
@@ -523,14 +525,14 @@ end_gnutls_io (GTlsConnectionGnutls *gnutls,
begin_gnutls_io (gnutls, blocking, cancellable); \
do {
-#define END_GNUTLS_IO(gnutls, ret, errmsg, error) \
+#define END_GNUTLS_IO(gnutls, ret, errmsg, err) \
} while ((ret == GNUTLS_E_AGAIN || \
ret == GNUTLS_E_WARNING_ALERT_RECEIVED) && \
!gnutls->priv->error); \
- ret = end_gnutls_io (gnutls, ret, error); \
- if (ret < 0 && ret != GNUTLS_E_REHANDSHAKE && error && !*error) \
+ ret = end_gnutls_io (gnutls, ret, err); \
+ if (ret < 0 && ret != GNUTLS_E_REHANDSHAKE && err && !*err) \
{ \
- g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,\
+ g_set_error (err, G_TLS_ERROR, G_TLS_ERROR_MISC,\
errmsg, gnutls_strerror (ret)); \
} \
;
@@ -777,6 +779,8 @@ handshake_internal (GTlsConnectionGnutls *gnutls,
GTlsCertificateFlags peer_certificate_errors = 0;
int ret;
+ g_clear_error (&gnutls->priv->handshake_error);
+
if (G_IS_TLS_SERVER_CONNECTION_GNUTLS (gnutls) &&
gnutls->priv->ever_handshaked && !gnutls->priv->handshaking &&
!gnutls->priv->need_handshake)
@@ -808,10 +812,15 @@ handshake_internal (GTlsConnectionGnutls *gnutls,
BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
ret = gnutls_handshake (gnutls->priv->session);
- END_GNUTLS_IO (gnutls, ret, _("Error performing TLS handshake: %s"), error);
+ END_GNUTLS_IO (gnutls, ret, _("Error performing TLS handshake: %s"),
+ &gnutls->priv->handshake_error);
if (ret == GNUTLS_E_AGAIN)
- return FALSE;
+ {
+ g_propagate_error (error, gnutls->priv->handshake_error);
+ gnutls->priv->handshake_error = NULL;
+ return FALSE;
+ }
gnutls->priv->handshaking = FALSE;
gnutls->priv->need_handshake = FALSE;
@@ -855,13 +864,20 @@ handshake_internal (GTlsConnectionGnutls *gnutls,
if (!accepted)
{
- g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+ g_set_error_literal (&gnutls->priv->handshake_error,
+ G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
_("Unacceptable TLS certificate"));
+ if (error)
+ *error = g_error_copy (gnutls->priv->handshake_error);
return FALSE;
}
}
- G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->finish_handshake (gnutls, ret == 0, error);
+ G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->
+ finish_handshake (gnutls, ret == 0, &gnutls->priv->handshake_error);
+
+ if (gnutls->priv->handshake_error && error)
+ *error = g_error_copy (gnutls->priv->handshake_error);
return (ret == 0);
}
@@ -871,6 +887,13 @@ handshake_in_progress_or_failed (GTlsConnectionGnutls *gnutls,
GCancellable *cancellable,
GError **error)
{
+ if (gnutls->priv->handshake_error)
+ {
+ if (error)
+ *error = g_error_copy (gnutls->priv->handshake_error);
+ return TRUE;
+ }
+
if (!(gnutls->priv->need_handshake || gnutls->priv->handshaking))
return FALSE;
diff --git a/tls/tests/connection.c b/tls/tests/connection.c
index 7ad66ad..30fdb4e 100644
--- a/tls/tests/connection.c
+++ b/tls/tests/connection.c
@@ -40,6 +40,7 @@ typedef struct {
GTlsAuthenticationMode auth_mode;
gboolean rehandshake;
GTlsCertificateFlags accept_flags;
+ GError *read_error;
} TestConnection;
static void
@@ -107,6 +108,7 @@ teardown_connection (TestConnection *test, gconstpointer data)
g_object_unref (test->address);
g_object_unref (test->identity);
g_main_loop_unref (test->loop);
+ g_clear_error (&test->read_error);
}
static gboolean
@@ -249,19 +251,20 @@ on_input_read_finish (GObject *object,
gpointer user_data)
{
TestConnection *test = user_data;
- GError *error = NULL;
gchar *line, *check;
line = g_data_input_stream_read_line_finish (G_DATA_INPUT_STREAM (object), res,
- NULL, &error);
- g_assert_no_error (error);
- g_assert (line);
+ NULL, &test->read_error);
+ if (!test->read_error)
+ {
+ g_assert (line);
- check = g_strdup (TEST_DATA);
- g_strstrip (check);
- g_assert_cmpstr (line, ==, check);
- g_free (check);
- g_free (line);
+ check = g_strdup (TEST_DATA);
+ g_strstrip (check);
+ g_assert_cmpstr (line, ==, check);
+ g_free (check);
+ g_free (line);
+ }
g_main_loop_quit (test->loop);
}
@@ -297,6 +300,7 @@ test_basic_connection (TestConnection *test,
read_test_data_async (test);
g_main_loop_run (test->loop);
+ g_assert_no_error (test->read_error);
}
static void
@@ -324,6 +328,7 @@ test_verified_connection (TestConnection *test,
read_test_data_async (test);
g_main_loop_run (test->loop);
+ g_assert_no_error (test->read_error);
}
static void
@@ -358,6 +363,7 @@ test_client_auth_connection (TestConnection *test,
read_test_data_async (test);
g_main_loop_run (test->loop);
+ g_assert_no_error (test->read_error);
}
static void
@@ -394,6 +400,52 @@ test_connection_no_database (TestConnection *test,
read_test_data_async (test);
g_main_loop_run (test->loop);
+ g_assert_no_error (test->read_error);
+}
+
+static void
+handshake_failed_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ TestConnection *test = user_data;
+ GError *error = NULL;
+
+ g_tls_connection_handshake_finish (G_TLS_CONNECTION (test->client_connection),
+ result, &error);
+ g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
+ g_clear_error (&error);
+
+ g_main_loop_quit (test->loop);
+}
+
+static void
+test_failed_connection (TestConnection *test,
+ gconstpointer data)
+{
+ GIOStream *connection;
+ GError *error = NULL;
+ GSocketConnectable *bad_addr;
+
+ connection = start_server_and_connect_to_it (test, G_TLS_AUTHENTICATION_NONE);
+
+ bad_addr = g_network_address_new ("wrong.example.com", 80);
+ test->client_connection = g_tls_client_connection_new (connection, bad_addr, &error);
+ g_object_unref (bad_addr);
+ g_assert_no_error (error);
+ g_object_unref (connection);
+
+ g_tls_connection_handshake_async (G_TLS_CONNECTION (test->client_connection),
+ G_PRIORITY_DEFAULT, NULL,
+ handshake_failed_cb, test);
+ g_main_loop_run (test->loop);
+
+ g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (test->client_connection),
+ G_TLS_CERTIFICATE_VALIDATE_ALL);
+
+ read_test_data_async (test);
+ g_main_loop_run (test->loop);
+ g_assert_error (test->read_error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
}
static void
@@ -506,6 +558,8 @@ main (int argc,
setup_connection, test_client_auth_rehandshake, teardown_connection);
g_test_add ("/tls/connection/no-database", TestConnection, NULL,
setup_connection, test_connection_no_database, teardown_connection);
+ g_test_add ("/tls/connection/failed", TestConnection, NULL,
+ setup_connection, test_failed_connection, teardown_connection);
g_test_add ("/tls/connection/socket-client", TestConnection, NULL,
setup_connection, test_connection_socket_client, teardown_connection);
g_test_add ("/tls/connection/socket-client-failed", TestConnection, NULL,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]