[glib-networking] Revert "Perform certificate verification during, not after, TLS handshake"
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking] Revert "Perform certificate verification during, not after, TLS handshake"
- Date: Mon, 13 Aug 2018 19:32:29 +0000 (UTC)
commit 22c1879b773e4f9df5a1c3761b0845986b504caf
Author: Michael Catanzaro <mcatanzaro igalia com>
Date: Mon Aug 13 14:28:23 2018 -0500
Revert "Perform certificate verification during, not after, TLS handshake"
This reverts commit 45c5f335312680c12f7b7b41a9b323d1122bf0e9.
Hopefully fixes #43. Something is wrong, and this needs to be reverted
until I've figured out what.
meson.build | 2 +-
tls/gnutls/gtlsconnection-gnutls.c | 283 ++++++++++---------------------------
2 files changed, 72 insertions(+), 213 deletions(-)
---
diff --git a/meson.build b/meson.build
index 30fb613..a09ee95 100644
--- a/meson.build
+++ b/meson.build
@@ -75,7 +75,7 @@ if enable_gnome_proxy_support
endif
# *** Checks for GnuTLS ***
-gnutls_dep = dependency('gnutls', version: '>= 3.4.6', required: true)
+gnutls_dep = dependency('gnutls', version: '>= 3.4.4', required: true)
# *** Checks for p11-kit ***
enable_pkcs11_support = get_option('pkcs11_support')
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index 44adcf8..959fa68 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -117,14 +117,12 @@ static P11KitPin* on_pin_prompt_callback (const char *pinfile,
static void g_tls_connection_gnutls_init_priorities (void);
-static int verify_certificate_cb (gnutls_session_t session);
-
static gboolean do_implicit_handshake (GTlsConnectionGnutls *gnutls,
gint64 timeout,
GCancellable *cancellable,
GError **error);
static gboolean finish_handshake (GTlsConnectionGnutls *gnutls,
- GTask *task,
+ GTask *thread_task,
GError **error);
enum
@@ -178,11 +176,8 @@ typedef struct
GTlsCertificate *certificate, *peer_certificate;
GTlsCertificateFlags peer_certificate_errors;
-
- GMutex verify_certificate_mutex;
- GCond verify_certificate_condition;
- gboolean peer_certificate_accepted;
- gboolean peer_certificate_examined;
+ GTlsCertificate *peer_certificate_tmp;
+ GTlsCertificateFlags peer_certificate_errors_tmp;
gboolean require_close_notify;
GTlsRehandshakeMode rehandshake_mode;
@@ -213,7 +208,6 @@ typedef struct
*/
gboolean need_handshake, need_finish_handshake;
gboolean started_handshake, handshaking, ever_handshaked;
- GMainContext *handshake_context;
GTask *implicit_handshake;
GError *handshake_error;
GByteArray *app_data_buf;
@@ -261,9 +255,6 @@ g_tls_connection_gnutls_init (GTlsConnectionGnutls *gnutls)
gnutls_certificate_allocate_credentials (&priv->creds);
- g_mutex_init (&priv->verify_certificate_mutex);
- g_cond_init (&priv->verify_certificate_condition);
-
priv->need_handshake = TRUE;
priv->database_is_unset = TRUE;
@@ -398,9 +389,6 @@ g_tls_connection_gnutls_initable_init (GInitable *initable,
gnutls_init (&priv->session, flags);
- gnutls_session_set_ptr (priv->session, gnutls);
- gnutls_session_set_verify_function (priv->session, verify_certificate_cb);
-
status = gnutls_credentials_set (priv->session,
GNUTLS_CRD_CERTIFICATE,
priv->creds);
@@ -461,9 +449,7 @@ g_tls_connection_gnutls_finalize (GObject *object)
g_clear_object (&priv->database);
g_clear_object (&priv->certificate);
g_clear_object (&priv->peer_certificate);
-
- g_mutex_clear (&priv->verify_certificate_mutex);
- g_cond_clear (&priv->verify_certificate_condition);
+ g_clear_object (&priv->peer_certificate_tmp);
g_clear_pointer (&priv->app_data_buf, g_byte_array_unref);
@@ -478,8 +464,6 @@ g_tls_connection_gnutls_finalize (GObject *object)
g_clear_error (&priv->read_error);
g_clear_error (&priv->write_error);
- g_clear_pointer (&priv->handshake_context, g_main_context_unref);
-
/* This must always be NULL here, as it holds a reference to @gnutls as
* its source object. However, we clear it anyway just in case this changes
* in future. */
@@ -767,7 +751,6 @@ claim_op (GTlsConnectionGnutls *gnutls,
g_mutex_unlock (&priv->op_mutex);
success = finish_handshake (gnutls, priv->implicit_handshake, &my_error);
g_clear_object (&priv->implicit_handshake);
- g_clear_pointer (&priv->handshake_context, g_main_context_unref);
g_mutex_lock (&priv->op_mutex);
if (op != G_TLS_CONNECTION_GNUTLS_OP_CLOSE_BOTH &&
@@ -1039,12 +1022,6 @@ end_gnutls_io (GTlsConnectionGnutls *gnutls,
_("TLS connection peer did not send a certificate"));
return status;
}
- else if (status == GNUTLS_E_CERTIFICATE_ERROR)
- {
- g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
- _("Unacceptable TLS certificate"));
- return status;
- }
else if (status == GNUTLS_E_FATAL_ALERT_RECEIVED)
{
g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
@@ -1805,102 +1782,6 @@ verify_peer_certificate (GTlsConnectionGnutls *gnutls,
return errors;
}
-static gboolean
-accept_peer_certificate (GTlsConnectionGnutls *gnutls,
- GTlsCertificate *peer_certificate,
- GTlsCertificateFlags peer_certificate_errors)
-{
- gboolean accepted = FALSE;
-
- if (G_IS_TLS_CLIENT_CONNECTION (gnutls))
- {
- GTlsCertificateFlags validation_flags;
-
- if (!g_tls_connection_gnutls_is_dtls (gnutls))
- validation_flags =
- g_tls_client_connection_get_validation_flags (G_TLS_CLIENT_CONNECTION (gnutls));
- else
- validation_flags =
- g_dtls_client_connection_get_validation_flags (G_DTLS_CLIENT_CONNECTION (gnutls));
-
- if ((peer_certificate_errors & validation_flags) == 0)
- accepted = TRUE;
- }
-
- if (!accepted)
- {
- accepted = g_tls_connection_emit_accept_certificate (G_TLS_CONNECTION (gnutls),
- peer_certificate,
- peer_certificate_errors);
- }
-
- return accepted;
-}
-
-static gboolean
-accept_certificate_cb (gpointer user_data)
-{
- GTlsConnectionGnutls *gnutls = user_data;
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
-
- g_assert (g_main_context_is_owner (priv->handshake_context));
-
- g_mutex_lock (&priv->verify_certificate_mutex);
-
- if (gnutls_certificate_type_get (priv->session) == GNUTLS_CRT_X509)
- {
- priv->peer_certificate = get_peer_certificate_from_session (gnutls);
- if (priv->peer_certificate)
- priv->peer_certificate_errors = verify_peer_certificate (gnutls, priv->peer_certificate);
- }
-
- priv->peer_certificate_accepted = accept_peer_certificate (gnutls,
- priv->peer_certificate,
- priv->peer_certificate_errors);
-
- priv->peer_certificate_examined = TRUE;
-
- g_cond_signal (&priv->verify_certificate_condition);
- g_mutex_unlock (&priv->verify_certificate_mutex);
-
- g_object_notify (G_OBJECT (gnutls), "peer-certificate");
- g_object_notify (G_OBJECT (gnutls), "peer-certificate-errors");
-
- return G_SOURCE_REMOVE;
-}
-
-static int
-verify_certificate_cb (gnutls_session_t session)
-{
- GTlsConnectionGnutls *gnutls = gnutls_session_get_ptr (session);
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
- gboolean accepted;
-
- g_mutex_lock (&priv->verify_certificate_mutex);
- priv->peer_certificate_examined = FALSE;
- priv->peer_certificate_accepted = FALSE;
- g_mutex_unlock (&priv->verify_certificate_mutex);
-
- /* Invoke the callback on the handshake context's thread. This is
- * necessary because we need to ensure the accept-certificate signal
- * is emitted on the original thread.
- */
- g_assert (priv->handshake_context);
- g_main_context_invoke (priv->handshake_context, accept_certificate_cb, gnutls);
-
- /* We'll block the handshake thread until the original thread has
- * decided whether to accept the certificate.
- */
- g_mutex_lock (&priv->verify_certificate_mutex);
- while (!priv->peer_certificate_examined)
- g_cond_wait (&priv->verify_certificate_condition, &priv->verify_certificate_mutex);
- accepted = priv->peer_certificate_accepted;
- g_mutex_unlock (&priv->verify_certificate_mutex);
-
- /* Return 0 for the handshake to continue, non-zero to terminate. */
- return !accepted;
-}
-
static void
handshake_thread (GTask *task,
gpointer object,
@@ -2017,10 +1898,16 @@ handshake_thread (GTask *task,
END_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, ret,
_("Error performing TLS handshake"), &error);
- if (G_IS_TLS_CLIENT_CONNECTION (gnutls) && !priv->peer_certificate && !error)
+ if (ret == 0 && gnutls_certificate_type_get (priv->session) == GNUTLS_CRT_X509)
{
- g_set_error_literal (&error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
- _("Server did not return a valid TLS certificate"));
+ priv->peer_certificate_tmp = get_peer_certificate_from_session (gnutls);
+ if (priv->peer_certificate_tmp)
+ priv->peer_certificate_errors_tmp = verify_peer_certificate (gnutls, priv->peer_certificate_tmp);
+ else if (G_IS_TLS_CLIENT_CONNECTION (gnutls))
+ {
+ g_set_error_literal (&error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+ _("Server did not return a valid TLS certificate"));
+ }
}
/* This calls the finish_handshake code of GTlsClientConnectionGnutls
@@ -2041,6 +1928,38 @@ handshake_thread (GTask *task,
}
}
+static gboolean
+accept_peer_certificate (GTlsConnectionGnutls *gnutls,
+ GTlsCertificate *peer_certificate,
+ GTlsCertificateFlags peer_certificate_errors)
+{
+ gboolean accepted = FALSE;
+
+ if (G_IS_TLS_CLIENT_CONNECTION (gnutls))
+ {
+ GTlsCertificateFlags validation_flags;
+
+ if (!g_tls_connection_gnutls_is_dtls (gnutls))
+ validation_flags =
+ g_tls_client_connection_get_validation_flags (G_TLS_CLIENT_CONNECTION (gnutls));
+ else
+ validation_flags =
+ g_dtls_client_connection_get_validation_flags (G_DTLS_CLIENT_CONNECTION (gnutls));
+
+ if ((peer_certificate_errors & validation_flags) == 0)
+ accepted = TRUE;
+ }
+
+ if (!accepted)
+ {
+ accepted = g_tls_connection_emit_accept_certificate (G_TLS_CONNECTION (gnutls),
+ peer_certificate,
+ peer_certificate_errors);
+ }
+
+ return accepted;
+}
+
static void
begin_handshake (GTlsConnectionGnutls *gnutls)
{
@@ -2053,13 +1972,29 @@ finish_handshake (GTlsConnectionGnutls *gnutls,
GError **error)
{
GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
+ GTlsCertificate *peer_certificate;
+ GTlsCertificateFlags peer_certificate_errors;
+
g_assert (error != NULL);
- if (g_task_propagate_boolean (task, error) &&
- priv->peer_certificate && !priv->peer_certificate_accepted)
+ peer_certificate = priv->peer_certificate_tmp;
+ priv->peer_certificate_tmp = NULL;
+ peer_certificate_errors = priv->peer_certificate_errors_tmp;
+ priv->peer_certificate_errors_tmp = 0;
+
+ if (g_task_propagate_boolean (task, error) && peer_certificate)
{
- g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
- _("Unacceptable TLS certificate"));
+ if (!accept_peer_certificate (gnutls, peer_certificate,
+ peer_certificate_errors))
+ {
+ g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+ _("Unacceptable TLS certificate"));
+ }
+
+ priv->peer_certificate = peer_certificate;
+ priv->peer_certificate_errors = peer_certificate_errors;
+ g_object_notify (G_OBJECT (gnutls), "peer-certificate");
+ g_object_notify (G_OBJECT (gnutls), "peer-certificate-errors");
}
if (*error && priv->started_handshake)
@@ -2068,77 +2003,26 @@ finish_handshake (GTlsConnectionGnutls *gnutls,
return (*error == NULL);
}
-static void
-sync_handshake_thread_completed (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (object);
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
-
- g_assert (g_main_context_is_owner (priv->handshake_context));
-
- g_mutex_lock (&priv->op_mutex);
- priv->need_finish_handshake = TRUE;
- g_mutex_unlock (&priv->op_mutex);
-
- g_main_context_wakeup (priv->handshake_context);
-}
-
-static void
-crank_sync_handshake_context (GTlsConnectionGnutls *gnutls,
- GCancellable *cancellable)
-{
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
-
- /* need_finish_handshake will be set inside sync_handshake_thread_completed(),
- * which should only ever be invoked while iterating the handshake context
- * here. So need_finish_handshake should only change on this thread.
- */
- g_mutex_lock (&priv->op_mutex);
- priv->need_finish_handshake = FALSE;
- while (!priv->need_finish_handshake && !g_cancellable_is_cancelled (cancellable))
- {
- g_mutex_unlock (&priv->op_mutex);
- g_main_context_iteration (priv->handshake_context, TRUE);
- g_mutex_lock (&priv->op_mutex);
- }
- g_mutex_unlock (&priv->op_mutex);
-}
-
static gboolean
g_tls_connection_gnutls_handshake (GTlsConnection *conn,
GCancellable *cancellable,
GError **error)
{
GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (conn);
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
GTask *task;
gboolean success;
gint64 *timeout = NULL;
GError *my_error = NULL;
- g_assert (priv->handshake_context == NULL);
- priv->handshake_context = g_main_context_new ();
-
- g_main_context_push_thread_default (priv->handshake_context);
-
- begin_handshake (gnutls);
-
- task = g_task_new (conn, cancellable, sync_handshake_thread_completed, NULL);
+ task = g_task_new (conn, cancellable, NULL, NULL);
g_task_set_source_tag (task, g_tls_connection_gnutls_handshake);
- g_task_set_return_on_cancel (task, TRUE);
timeout = g_new0 (gint64, 1);
*timeout = -1; /* blocking */
g_task_set_task_data (task, timeout, g_free);
- g_task_run_in_thread (task, handshake_thread);
- crank_sync_handshake_context (gnutls, cancellable);
-
- g_main_context_pop_thread_default (priv->handshake_context);
-
- g_clear_pointer (&priv->handshake_context, g_main_context_unref);
+ begin_handshake (gnutls);
+ g_task_run_in_thread_sync (task, handshake_thread);
success = finish_handshake (gnutls, task, &my_error);
g_object_unref (task);
@@ -2174,8 +2058,6 @@ handshake_thread_completed (GObject *object,
GError *error = NULL;
gboolean need_finish_handshake, success;
- g_clear_pointer (&priv->handshake_context, g_main_context_unref);
-
g_mutex_lock (&priv->op_mutex);
if (priv->need_finish_handshake)
{
@@ -2232,13 +2114,9 @@ g_tls_connection_gnutls_handshake_async (GTlsConnection *conn,
GAsyncReadyCallback callback,
gpointer user_data)
{
- GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (G_TLS_CONNECTION_GNUTLS
(conn));
GTask *thread_task, *caller_task;
gint64 *timeout = NULL;
- g_assert (!priv->handshake_context);
- priv->handshake_context = g_main_context_ref_thread_default ();
-
caller_task = g_task_new (conn, cancellable, callback, user_data);
g_task_set_source_tag (caller_task, g_tls_connection_gnutls_handshake_async);
g_task_set_priority (caller_task, io_priority);
@@ -2299,21 +2177,8 @@ do_implicit_handshake (GTlsConnectionGnutls *gnutls,
/* We have op_mutex */
- g_assert (priv->handshake_context == NULL);
- if (timeout != 0)
- {
- priv->handshake_context = g_main_context_new ();
- g_main_context_push_thread_default (priv->handshake_context);
- }
- else
- {
- priv->handshake_context = g_main_context_ref_thread_default ();
- }
-
g_assert (priv->implicit_handshake == NULL);
- priv->implicit_handshake = g_task_new (gnutls, cancellable,
- timeout ? sync_handshake_thread_completed : NULL,
- NULL);
+ priv->implicit_handshake = g_task_new (gnutls, cancellable, NULL, NULL);
g_task_set_source_tag (priv->implicit_handshake,
do_implicit_handshake);
@@ -2337,14 +2202,8 @@ do_implicit_handshake (GTlsConnectionGnutls *gnutls,
g_mutex_unlock (&priv->op_mutex);
- g_task_set_return_on_cancel (priv->implicit_handshake, TRUE);
- g_task_run_in_thread (priv->implicit_handshake, handshake_thread);
- crank_sync_handshake_context (gnutls, cancellable);
-
- g_main_context_pop_thread_default (priv->handshake_context);
-
- g_clear_pointer (&priv->handshake_context, g_main_context_unref);
-
+ g_task_run_in_thread_sync (priv->implicit_handshake,
+ handshake_thread);
success = finish_handshake (gnutls,
priv->implicit_handshake,
&my_error);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]