GTlsDatabase *database;
gboolean database_is_unset;
gboolean need_handshake, handshaking, ever_handshaked;
+ GError *handshake_error;
gboolean closing;
GInputStream *tls_istream;
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);
}
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)); \
} \
;
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)
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;
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);
}
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;
GTlsAuthenticationMode auth_mode;
gboolean rehandshake;
GTlsCertificateFlags accept_flags;
+ GError *read_error;
} TestConnection;
static void
g_object_unref (test->address);
g_object_unref (test->identity);
g_main_loop_unref (test->loop);
+ g_clear_error (&test->read_error);
}
static gboolean
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);
}
read_test_data_async (test);
g_main_loop_run (test->loop);
+ g_assert_no_error (test->read_error);
}
static void
read_test_data_async (test);
g_main_loop_run (test->loop);
+ g_assert_no_error (test->read_error);
}
static void
read_test_data_async (test);
g_main_loop_run (test->loop);
+ g_assert_no_error (test->read_error);
}
static void
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
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,