[glib-networking/mcatanzaro/base-rebase] Progress



commit 63ad9580c0e4d08ea791e71c555f6c06701d8caf
Author: Michael Catanzaro <mcatanzaro igalia com>
Date:   Sun Apr 28 22:47:24 2019 -0500

    Progress

 tls/base/gtlsconnection-base.c             | 174 +++++++++++++++++--
 tls/base/gtlsconnection-base.h             | 270 ++++++++++++++---------------
 tls/gnutls/gtlsconnection-gnutls.c         | 166 +-----------------
 tls/gnutls/meson.build                     |   2 -
 tls/openssl/gtlsclientconnection-openssl.c |  64 ++++++-
 tls/openssl/gtlsconnection-openssl.c       | 161 ++---------------
 tls/openssl/gtlsserverconnection-openssl.c |   9 +-
 7 files changed, 372 insertions(+), 474 deletions(-)
---
diff --git a/tls/base/gtlsconnection-base.c b/tls/base/gtlsconnection-base.c
index 8602265..91fef0a 100644
--- a/tls/base/gtlsconnection-base.c
+++ b/tls/base/gtlsconnection-base.c
@@ -1123,12 +1123,81 @@ g_tls_connection_base_condition_wait (GDatagramBased  *datagram_based,
   return !g_cancellable_set_error_if_cancelled (cancellable, error);
 }
 
-void
-g_tls_connection_base_set_peer_certificate (GTlsConnectionBase   *tls,
-                                            GTlsCertificate      *peer_certificate,
-                                            GTlsCertificateFlags  peer_certificate_errors)
+static GTlsCertificateFlags
+verify_peer_certificate (GTlsConnectionBase *tls,
+                         GTlsCertificate    *peer_certificate)
 {
-  GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
+  GSocketConnectable *peer_identity;
+  GTlsDatabase *database;
+  GTlsCertificateFlags errors;
+  gboolean is_client;
+
+  is_client = G_IS_TLS_CLIENT_CONNECTION (tls);
+
+  if (!is_client)
+    peer_identity = NULL;
+  else if (!g_tls_connection_base_is_dtls (tls))
+    peer_identity = g_tls_client_connection_get_server_identity (G_TLS_CLIENT_CONNECTION (tls));
+  else
+    peer_identity = g_dtls_client_connection_get_server_identity (G_DTLS_CLIENT_CONNECTION (tls));
+
+  errors = 0;
+
+  database = g_tls_connection_get_database (G_TLS_CONNECTION (tls));
+  if (database == NULL)
+    {
+      errors |= G_TLS_CERTIFICATE_UNKNOWN_CA;
+      errors |= g_tls_certificate_verify (peer_certificate, peer_identity, NULL);
+    }
+  else
+    {
+      GError *error = NULL;
+
+      errors |= g_tls_database_verify_chain (database, peer_certificate,
+                                             is_client ?
+                                             G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER :
+                                             G_TLS_DATABASE_PURPOSE_AUTHENTICATE_CLIENT,
+                                             peer_identity,
+                                             g_tls_connection_get_interaction (G_TLS_CONNECTION (tls)),
+                                             G_TLS_DATABASE_VERIFY_NONE,
+                                             NULL, &error);
+      if (error)
+        {
+          g_warning ("failure verifying certificate chain: %s",
+                     error->message);
+          g_assert (errors != 0);
+          g_clear_error (&error);
+        }
+    }
+
+  if (tls_class->verify_peer_certificate)
+    errors |= tls_class->verify_peer_certificate (tls, peer_certificate, errors);
+
+  return errors;
+}
+
+static void
+update_peer_certificate_and_compute_errors (GTlsConnectionBase *tls)
+{
+  GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (gnutls);
+  GTlsCertificate *peer_certificate = NULL;
+  GTlsCertificateFlags peer_certificate_errors = 0;
+
+  /* This function must be called from the handshake context thread
+   * (probably the main thread, NOT the handshake thread) because
+   * it emits notifies that are application-visible.
+   *
+   * verify_certificate_mutex should be locked.
+   */
+  g_assert (priv->handshake_context);
+  g_assert (g_main_context_is_owner (priv->handshake_context));
+
+  if (gnutls_certificate_type_get (priv->session) == GNUTLS_CRT_X509)
+    {
+      peer_certificate = get_peer_certificate_from_session (tls);
+      if (peer_certificate)
+        peer_certificate_errors = verify_peer_certificate (tls, peer_certificate);
+    }
 
   g_set_object (&priv->peer_certificate, peer_certificate);
 
@@ -1138,6 +1207,89 @@ g_tls_connection_base_set_peer_certificate (GTlsConnectionBase   *tls,
   g_object_notify (G_OBJECT (tls), "peer-certificate-errors");
 }
 
+static gboolean
+accept_or_reject_peer_certificate (gpointer user_data)
+{
+  GTlsConnectionBase *tls = user_data;
+  GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
+  gboolean accepted = FALSE;
+
+  g_assert (g_main_context_is_owner (priv->handshake_context));
+
+  g_mutex_lock (&priv->verify_certificate_mutex);
+
+  update_peer_certificate_and_compute_errors (tls);
+
+  if (G_IS_TLS_CLIENT_CONNECTION (tls) && priv->peer_certificate != NULL)
+    {
+      GTlsCertificateFlags validation_flags;
+
+      if (!g_tls_connection_base_is_dtls (tls))
+        validation_flags =
+          g_tls_client_connection_get_validation_flags (G_TLS_CLIENT_CONNECTION (tls));
+      else
+        validation_flags =
+          g_dtls_client_connection_get_validation_flags (G_DTLS_CLIENT_CONNECTION (tls));
+
+      if ((priv->peer_certificate_errors & validation_flags) == 0)
+        accepted = TRUE;
+    }
+
+  if (!accepted)
+    {
+      g_main_context_pop_thread_default (priv->handshake_context);
+      accepted = g_tls_connection_emit_accept_certificate (G_TLS_CONNECTION (tls),
+                                                           priv->peer_certificate,
+                                                           priv->peer_certificate_errors);
+      g_main_context_push_thread_default (priv->handshake_context);
+    }
+
+  priv->peer_certificate_accepted = accepted;
+
+  /* This has to be the very last statement before signaling the
+   * condition variable because otherwise the code could spuriously
+   * wakeup and continue before we are done here.
+   */
+  priv->peer_certificate_examined = TRUE;
+
+  g_cond_signal (&priv->verify_certificate_condition);
+  g_mutex_unlock (&priv->verify_certificate_mutex);
+
+  g_object_notify (G_OBJECT (tls), "peer-certificate");
+  g_object_notify (G_OBJECT (tls), "peer-certificate-errors");
+
+  return G_SOURCE_REMOVE;
+}
+
+gboolean
+g_tls_connection_base_handshake_thread_verify_certificate (GTlsConnectionBase *tls)
+{
+  GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
+
+  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_or_reject_peer_certificate, 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 accepted;
+}
+
 static void
 handshake_thread (GTask        *task,
                   gpointer      object,
@@ -2327,14 +2479,14 @@ g_tls_connection_base_datagram_based_iface_init (GDatagramBasedInterface *iface)
 }
 
 void
-GTLS_DEBUG (gpointer    gnutls,
+GTLS_DEBUG (gpointer    connection,
             const char *message,
             ...)
 {
   char *result = NULL;
   int ret;
 
-  g_assert (G_IS_TLS_CONNECTION (gnutls));
+  g_assert (G_IS_TLS_CONNECTION (connection));
 
   va_list args;
   va_start (args, message);
@@ -2342,10 +2494,10 @@ GTLS_DEBUG (gpointer    gnutls,
   ret = g_vasprintf (&result, message, args);
   g_assert (ret > 0);
 
-  if (G_IS_TLS_CLIENT_CONNECTION (gnutls))
-    g_printf ("CLIENT %p: ", gnutls);
-  else if (G_IS_TLS_SERVER_CONNECTION (gnutls))
-    g_printf ("SERVER %p: ", gnutls);
+  if (G_IS_TLS_CLIENT_CONNECTION (connection))
+    g_printf ("CLIENT %p: ", connection;
+  else if (G_IS_TLS_SERVER_CONNECTION (connection))
+    g_printf ("SERVER %p: ", connection);
   else
     g_assert_not_reached ();
 
diff --git a/tls/base/gtlsconnection-base.h b/tls/base/gtlsconnection-base.h
index 66e2048..e7febf6 100644
--- a/tls/base/gtlsconnection-base.h
+++ b/tls/base/gtlsconnection-base.h
@@ -43,9 +43,9 @@ typedef enum {
 } GTlsConnectionBaseStatus;
 
 typedef enum {
-        G_TLS_DIRECTION_NONE = 0,
-        G_TLS_DIRECTION_READ = 1 << 0,
-        G_TLS_DIRECTION_WRITE = 1 << 1,
+  G_TLS_DIRECTION_NONE = 0,
+  G_TLS_DIRECTION_READ = 1 << 0,
+  G_TLS_DIRECTION_WRITE = 1 << 1,
 } GTlsDirection;
 
 #define G_TLS_DIRECTION_BOTH (G_TLS_DIRECTION_READ | G_TLS_DIRECTION_WRITE)
@@ -54,141 +54,139 @@ struct _GTlsConnectionBaseClass
 {
   GTlsConnectionClass parent_class;                                      
 
-  GTlsConnectionBaseStatus (*request_rehandshake)  (GTlsConnectionBase  *tls,
-                                                    gint64               timeout,
-                                                    GCancellable        *cancellable,
-                                                    GError             **error);
-  void                     (*prepare_handshake)    (GTlsConnectionBase  *tls,
-                                                    gchar              **advertised_protocols);            
-  GTlsConnectionBaseStatus (*handshake_thread_handshake)
-                                                   (GTlsConnectionBase  *tls,
-                                                    gint64               timeout,
-                                                    GCancellable        *cancellable,
-                                                    GError             **error);
-  void                     (*complete_handshake)   (GTlsConnectionBase  *tls,
-                                                    gchar              **negotiated_protocol,
-                                                    GError             **error);
-
-  void                     (*push_io)              (GTlsConnectionBase  *tls,
-                                                    GIOCondition         direction,
-                                                    gint64               timeout,
-                                                    GCancellable        *cancellable);
-  GTlsConnectionBaseStatus (*pop_io)               (GTlsConnectionBase  *tls,
-                                                    GIOCondition         direction,
-                                                    gboolean             success,
-                                                    GError             **error);
-
-  GTlsConnectionBaseStatus (*read_fn)              (GTlsConnectionBase  *tls,
-                                                    void                *buffer,
-                                                    gsize                count,
-                                                    gint64               timeout,
-                                                    gssize              *nread,
-                                                    GCancellable        *cancellable,
-                                                    GError             **error);
-  GTlsConnectionBaseStatus (*read_message_fn)      (GTlsConnectionBase  *tls,
-                                                    GInputVector        *vectors,
-                                                    guint                num_vectors,
-                                                    gint64               timeout,
-                                                    gssize              *nread,
-                                                    GCancellable        *cancellable,
-                                                    GError             **error);
-
-  GTlsConnectionBaseStatus (*write_fn)             (GTlsConnectionBase  *tls,
-                                                    const void          *buffer,
-                                                    gsize                count,
-                                                    gint64               timeout,
-                                                    gssize              *nwrote,
-                                                    GCancellable        *cancellable,
-                                                    GError             **error);
-  GTlsConnectionBaseStatus (*write_message_fn)     (GTlsConnectionBase  *tls,
-                                                    GOutputVector       *vectors,
-                                                    guint                num_vectors,
-                                                    gint64               timeout,
-                                                    gssize              *nwrote,
-                                                    GCancellable        *cancellable,
-                                                    GError             **error);
-
-  GTlsConnectionBaseStatus (*close_fn)             (GTlsConnectionBase  *tls,
-                                                    gint64               timeout,
-                                                    GCancellable        *cancellable,
-                                                    GError             **error);
+  GTlsConnectionBaseStatus (*request_rehandshake)        (GTlsConnectionBase   *tls,
+                                                          gint64                timeout,
+                                                          GCancellable         *cancellable,
+                                                          GError              **error);
+  void                     (*prepare_handshake)          (GTlsConnectionBase   *tls,
+                                                          gchar               **advertised_protocols);
+  GTlsConnectionBaseStatus (*handshake_thread_handshake) (GTlsConnectionBase   *tls,
+                                                          gint64                timeout,
+                                                          GCancellable         *cancellable,
+                                                          GError              **error);
+  GTlsCertificateFlags     (*verify_peer_certificate)    (GTlsConnenctionBase  *tls,
+                                                          GTlsCertificate      *certificate,
+                                                          GTlsCertificateFlags  flags);
+  void                     (*complete_handshake)         (GTlsConnectionBase   *tls,
+                                                          gchar               **negotiated_protocol,
+                                                          GError              **error);
+
+  void                     (*push_io)                    (GTlsConnectionBase   *tls,
+                                                          GIOCondition          direction,
+                                                          gint64                timeout,
+                                                          GCancellable         *cancellable);
+  GTlsConnectionBaseStatus (*pop_io)                     (GTlsConnectionBase   *tls,
+                                                          GIOCondition          direction,
+                                                          gboolean              success,
+                                                          GError              **error);
+
+  GTlsConnectionBaseStatus (*read_fn)                    (GTlsConnectionBase   *tls,
+                                                          void                 *buffer,
+                                                          gsize                 count,
+                                                          gint64                timeout,
+                                                          gssize               *nread,
+                                                          GCancellable         *cancellable,
+                                                          GError              **error);
+  GTlsConnectionBaseStatus (*read_message_fn)            (GTlsConnectionBase   *tls,
+                                                          GInputVector         *vectors,
+                                                          guint                 num_vectors,
+                                                          gint64                timeout,
+                                                          gssize               *nread,
+                                                          GCancellable         *cancellable,
+                                                          GError              **error);
+
+  GTlsConnectionBaseStatus (*write_fn)                   (GTlsConnectionBase   *tls,
+                                                          const void           *buffer,
+                                                          gsize                 count,
+                                                          gint64                timeout,
+                                                          gssize               *nwrote,
+                                                          GCancellable         *cancellable,
+                                                          GError              **error);
+  GTlsConnectionBaseStatus (*write_message_fn)           (GTlsConnectionBase   *tls,
+                                                          GOutputVector        *vectors,
+                                                          guint                 num_vectors,
+                                                          gint64                timeout,
+                                                          gssize               *nwrote,
+                                                          GCancellable         *cancellable,
+                                                          GError              **error);
+
+  GTlsConnectionBaseStatus (*close_fn)                   (GTlsConnectionBase   *tls,
+                                                          gint64                timeout,
+                                                          GCancellable         *cancellable,
+                                                          GError              **error);
 };
 
-void g_tls_connection_base_set_peer_certificate (GTlsConnectionBase   *tls,
-                                                 GTlsCertificate      *peer_certificate,
-                                                 GTlsCertificateFlags  peer_certificate_errors);
-
-void     g_tls_connection_base_push_io       (GTlsConnectionBase *tls,
-                                              GIOCondition        direction,
-                                              gint64              timeout,
-                                              GCancellable       *cancellable);
-GTlsConnectionBaseStatus
-         g_tls_connection_base_pop_io        (GTlsConnectionBase  *tls,
-                                              GIOCondition         direction,
-                                              gboolean             success,
-                                              GError             **error);
-
-gssize   g_tls_connection_base_read          (GTlsConnectionBase  *tls,
-                                              void                *buffer,
-                                              gsize                size,
-                                              gint64               timeout,
-                                              GCancellable        *cancellable,
-                                              GError             **error);
-gssize   g_tls_connection_base_write         (GTlsConnectionBase  *tls,
-                                              const void          *buffer,
-                                              gsize                size,
-                                              gint64               timeout,
-                                              GCancellable        *cancellable,
-                                              GError             **error);
-
-gboolean g_tls_connection_base_check         (GTlsConnectionBase  *tls,
-                                              GIOCondition         condition);
-gboolean g_tls_connection_base_base_check    (GTlsConnectionBase  *tls,
-                                              GIOCondition         condition);
-GSource *g_tls_connection_base_create_source (GTlsConnectionBase  *tls,
-                                              GIOCondition         condition,
-                                              GCancellable        *cancellable);
-
-gboolean g_tls_connection_base_close_internal (GIOStream      *stream,
-                                               GTlsDirection   direction,
-                                               gint64          timeout,
-                                               GCancellable   *cancellable,
-                                               GError        **error);
-
-gboolean        g_tls_connection_base_is_dtls            (GTlsConnectionBase *tls);
-
-GDatagramBased *g_tls_connection_base_get_base_socket    (GTlsConnectionBase *tls);
-
-GIOStream              *g_tls_connection_base_get_base_iostream  (GTlsConnectionBase *tls);
-GPollableInputStream   *g_tls_connection_base_get_base_istream   (GTlsConnectionBase *tls);
-GPollableOutputStream  *g_tls_connection_base_get_base_ostream   (GTlsConnectionBase *tls);
-
-void            g_tls_connection_base_set_missing_requested_client_certificate
-                                                                 (GTlsConnectionBase *tls);
-
-GError        **g_tls_connection_base_get_certificate_error      (GTlsConnectionBase *tls);
-GError        **g_tls_connection_base_get_read_error             (GTlsConnectionBase *tls);
-GError        **g_tls_connection_base_get_write_error            (GTlsConnectionBase *tls);
-
-gint64          g_tls_connection_base_get_read_timeout           (GTlsConnectionBase *tls);
-gint64          g_tls_connection_base_get_write_timeout          (GTlsConnectionBase *tls);
-
-gboolean        g_tls_connection_base_is_handshaking             (GTlsConnectionBase *tls);
-
-gboolean        g_tls_connection_base_ever_handshaked            (GTlsConnectionBase *tls);
-
-gboolean        g_tls_connection_base_request_certificate (GTlsConnectionBase  *tls,
-                                                           GError             **error);
-
-void            g_tls_connection_base_buffer_application_data (GTlsConnectionBase *tls,
-                                                               guint8             *data,
-                                                               gsize               length);
-
-void            g_tls_connection_base_set_advertised_protocols
-
-void GTLS_DEBUG (gpointer    gnutls,
-                 const char *message,
-                 ...);
+gboolean                  g_tls_connection_base_handshake_thread_verify_certificate
+                                                                        (GTlsConnectionBase *tls);
+
+void                      g_tls_connection_base_push_io                 (GTlsConnectionBase *tls,
+                                                                         GIOCondition        direction,
+                                                                         gint64              timeout,
+                                                                         GCancellable       *cancellable);
+GTlsConnectionBaseStatus  g_tls_connection_base_pop_io                  (GTlsConnectionBase  *tls,
+                                                                         GIOCondition         direction,
+                                                                         gboolean             success,
+                                                                         GError             **error);
+
+gssize                    g_tls_connection_base_read                    (GTlsConnectionBase  *tls,
+                                                                         void                *buffer,
+                                                                         gsize                size,
+                                                                         gint64               timeout,
+                                                                         GCancellable        *cancellable,
+                                                                         GError             **error);
+gssize                    g_tls_connection_base_write                   (GTlsConnectionBase  *tls,
+                                                                         const void          *buffer,
+                                                                         gsize                size,
+                                                                         gint64               timeout,
+                                                                         GCancellable        *cancellable,
+                                                                         GError             **error);
+
+gboolean                  g_tls_connection_base_check                   (GTlsConnectionBase  *tls,
+                                                                         GIOCondition         condition);
+gboolean                  g_tls_connection_base_base_check              (GTlsConnectionBase  *tls,
+                                                                         GIOCondition         condition);
+GSource                  *g_tls_connection_base_create_source           (GTlsConnectionBase  *tls,
+                                                                         GIOCondition         condition,
+                                                                         GCancellable        *cancellable);
+
+gboolean                  g_tls_connection_base_close_internal          (GIOStream      *stream,
+                                                                         GTlsDirection   direction,
+                                                                         gint64          timeout,
+                                                                         GCancellable   *cancellable,
+                                                                         GError        **error);
+
+gboolean                  g_tls_connection_base_is_dtls                 (GTlsConnectionBase *tls);
+
+GDatagramBased           *g_tls_connection_base_get_base_socket         (GTlsConnectionBase *tls);
+
+GIOStream                *g_tls_connection_base_get_base_iostream       (GTlsConnectionBase *tls);
+GPollableInputStream     *g_tls_connection_base_get_base_istream        (GTlsConnectionBase *tls);
+GPollableOutputStream    *g_tls_connection_base_get_base_ostream        (GTlsConnectionBase *tls);
+
+void                      g_tls_connection_base_set_missing_requested_client_certificate
+                                                                        (GTlsConnectionBase *tls);
+
+GError                  **g_tls_connection_base_get_certificate_error   (GTlsConnectionBase *tls);
+GError                  **g_tls_connection_base_get_read_error          (GTlsConnectionBase *tls);
+GError                  **g_tls_connection_base_get_write_error         (GTlsConnectionBase *tls);
+
+gint64                    g_tls_connection_base_get_read_timeout        (GTlsConnectionBase *tls);
+gint64                    g_tls_connection_base_get_write_timeout       (GTlsConnectionBase *tls);
+
+gboolean                  g_tls_connection_base_is_handshaking          (GTlsConnectionBase *tls);
+
+gboolean                  g_tls_connection_base_ever_handshaked         (GTlsConnectionBase *tls);
+
+gboolean                  g_tls_connection_base_request_certificate     (GTlsConnectionBase  *tls,
+                                                                         GError             **error);
+
+void                      g_tls_connection_base_buffer_application_data (GTlsConnectionBase *tls,
+                                                                         guint8             *data,
+                                                                         gsize               length);
+
+void                      GTLS_DEBUG                                    (gpointer    connection,
+                                                                         const char *message,
+                                                                         ...);
 
 G_END_DECLS
 
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index 537d465..937cc30 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -801,173 +801,15 @@ get_peer_certificate_from_session (GTlsConnectionGnutls *gnutls)
   return G_TLS_CERTIFICATE (chain);
 }
 
-//MOVE
-#if 0
-static GTlsCertificateFlags
-verify_peer_certificate (GTlsConnectionGnutls *gnutls,
-                         GTlsCertificate      *peer_certificate)
-{
-  GTlsConnection *conn = G_TLS_CONNECTION (gnutls);
-  GSocketConnectable *peer_identity;
-  GTlsDatabase *database;
-  GTlsCertificateFlags errors;
-  gboolean is_client;
-
-  is_client = G_IS_TLS_CLIENT_CONNECTION (gnutls);
-
-  if (!is_client)
-    peer_identity = NULL;
-  else if (!g_tls_connection_gnutls_is_dtls (gnutls))
-    peer_identity = g_tls_client_connection_get_server_identity (G_TLS_CLIENT_CONNECTION (gnutls));
-  else
-    peer_identity = g_dtls_client_connection_get_server_identity (G_DTLS_CLIENT_CONNECTION (gnutls));
-
-  errors = 0;
-
-  database = g_tls_connection_get_database (conn);
-  if (database == NULL)
-    {
-      errors |= G_TLS_CERTIFICATE_UNKNOWN_CA;
-      errors |= g_tls_certificate_verify (peer_certificate, peer_identity, NULL);
-    }
-  else
-    {
-      GError *error = NULL;
-
-      errors |= g_tls_database_verify_chain (database, peer_certificate,
-                                             is_client ?
-                                             G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER :
-                                             G_TLS_DATABASE_PURPOSE_AUTHENTICATE_CLIENT,
-                                             peer_identity,
-                                             g_tls_connection_get_interaction (conn),
-                                             G_TLS_DATABASE_VERIFY_NONE,
-                                             NULL, &error);
-      if (error)
-        {
-          g_warning ("failure verifying certificate chain: %s",
-                     error->message);
-          g_assert (errors != 0);
-          g_clear_error (&error);
-        }
-    }
-
-  return errors;
-}
-
-static void
-update_peer_certificate_and_compute_errors (GTlsConnectionGnutls *gnutls)
-{
-  GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
-  GTlsCertificate *peer_certificate = NULL;
-  GTlsCertificateFlags peer_certificate_errors = 0;
-
-  /* This function must be called from the handshake context thread
-   * (probably the main thread, NOT the handshake thread) because
-   * g_tls_connection_base_set_peer_certificate() emits notifies
-   * that are application-visible.
-   *
-   * verify_certificate_mutex should be locked.
-   */
-  g_assert (priv->handshake_context);
-  g_assert (g_main_context_is_owner (priv->handshake_context));
-
-  if (gnutls_certificate_type_get (priv->session) == GNUTLS_CRT_X509)
-    {
-      peer_certificate = get_peer_certificate_from_session (gnutls);
-      if (peer_certificate)
-        peer_certificate_errors = verify_peer_certificate (gnutls, peer_certificate);
-    }
-
-  g_tls_connection_base_set_peer_certificate (G_TLS_CONNECTION_BASE (gnutls),
-                                              peer_certificate, peer_certificate_errors);
-}
-
-static gboolean
-accept_or_reject_peer_certificate (gpointer user_data)
-{
-  GTlsConnectionGnutls *gnutls = user_data;
-  GTlsConnectionGnutlsPrivate *priv = g_tls_connection_gnutls_get_instance_private (gnutls);
-  gboolean accepted = FALSE;
-
-  g_assert (g_main_context_is_owner (priv->handshake_context));
-
-  g_mutex_lock (&priv->verify_certificate_mutex);
-
-  update_peer_certificate_and_compute_errors (gnutls);
-
-  if (G_IS_TLS_CLIENT_CONNECTION (gnutls) && priv->peer_certificate != NULL)
-    {
-      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 ((priv->peer_certificate_errors & validation_flags) == 0)
-        accepted = TRUE;
-    }
-
-  if (!accepted)
-    {
-      g_main_context_pop_thread_default (priv->handshake_context);
-      accepted = g_tls_connection_emit_accept_certificate (G_TLS_CONNECTION (gnutls),
-                                                           priv->peer_certificate,
-                                                           priv->peer_certificate_errors);
-      g_main_context_push_thread_default (priv->handshake_context);
-    }
-
-  priv->peer_certificate_accepted = accepted;
-
-  /* This has to be the very last statement before signaling the
-   * condition variable because otherwise the code could spuriously
-   * wakeup and continue before we are done here.
-   */
-  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_or_reject_peer_certificate, gnutls);
+  GTlsConnectionBase *tls = gnutls_session_get_ptr (session);
 
-  /* 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;
+  /* Return 0 for the handshake to continue, non-zero to terminate.
+   * Complete opposite of what OpenSSL does. */
+  return !g_tls_connection_base_handshake_thread_verify_certificate (tls);
 }
-#endif
 
 static void
 g_tls_connection_gnutls_prepare_handshake (GTlsConnectionBase  *tls,
diff --git a/tls/gnutls/meson.build b/tls/gnutls/meson.build
index 4ff127e..af2b937 100644
--- a/tls/gnutls/meson.build
+++ b/tls/gnutls/meson.build
@@ -6,8 +6,6 @@ sources = files(
   'gtlsconnection-gnutls.c',
   'gtlsdatabase-gnutls.c',
   'gtlsfiledatabase-gnutls.c',
-  'gtlsinputstream-gnutls.c',
-  'gtlsoutputstream-gnutls.c',
   'gtlsserverconnection-gnutls.c'
 )
 
diff --git a/tls/openssl/gtlsclientconnection-openssl.c b/tls/openssl/gtlsclientconnection-openssl.c
index 7d7be05..762b812 100644
--- a/tls/openssl/gtlsclientconnection-openssl.c
+++ b/tls/openssl/gtlsclientconnection-openssl.c
@@ -234,6 +234,56 @@ g_tls_client_connection_openssl_constructed (GObject *object)
   G_OBJECT_CLASS (g_tls_client_connection_openssl_parent_class)->constructed (object);
 }
 
+static GTlsCertificateFlags
+verify_ocsp_response (GTlsClientConnectionOpenssl *openssl,
+                      GTlsCertificate             *peer_certificate)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_OCSP)
+  SSL *ssl = NULL;
+  OCSP_RESPONSE *resp = NULL;
+  GTlsDatabase *database;
+  long len = 0;
+  unsigned char *p = NULL;
+
+  ssl = g_tls_connection_openssl_get_ssl (G_TLS_CONNECTION_OPENSSL (openssl));
+  len = SSL_get_tlsext_status_ocsp_resp (ssl, &p);
+  /* Soft fail in case of no response is the best we can do
+   * FIXME: this makes it security theater, why bother with OCSP at all? */
+  if (p == NULL)
+    return 0;
+
+  resp = d2i_OCSP_RESPONSE (NULL, (const unsigned char **)&p, len);
+  if (resp == NULL)
+    return G_TLS_CERTIFICATE_GENERIC_ERROR;
+
+  database = g_tls_connection_get_database (G_TLS_CONNECTION (openssl));
+
+  /* If there's no database, then G_TLS_CERTIFICATE_UNKNOWN_CA must be flagged,
+   * and this function is only called if there are no flags.
+   */
+  g_assert (database);
+
+  return g_tls_file_database_openssl_verify_ocsp_response (database,
+                                                           peer_certificate,
+                                                           resp);
+#else
+  return 0;
+#endif
+}
+
+static GTlsCertificateFlags
+g_tls_client_connection_openssl_verify_peer_certificate (GTlsConnectionBase   *tls,
+                                                         GTlsCertificate      *certificate,
+                                                         GTlsCertificateFlags  flags)
+{
+  GTlsClientConnectionOpenssl *openssl = G_TLS_CLIENT_CONNECTION_OPENSSL (tls);
+
+  if (flags == 0)
+    flags = verify_ocsp_response (openssl, certificate);
+
+  return flags;
+}
+
 static SSL *
 g_tls_client_connection_openssl_get_ssl (GTlsConnectionOpenssl *connection)
 {
@@ -245,14 +295,16 @@ g_tls_client_connection_openssl_class_init (GTlsClientConnectionOpensslClass *kl
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   GTlsConnectionBaseClass *base_class = G_TLS_CONNECTION_BASE_CLASS (klass);
-  GTlsConnectionOpensslClass *connection_class = G_TLS_CONNECTION_OPENSSL_CLASS (klass);
+  GTlsConnectionOpensslClass *openssl_class = G_TLS_CONNECTION_OPENSSL_CLASS (klass);
+
+  gobject_class->finalize             = g_tls_client_connection_openssl_finalize;
+  gobject_class->get_property         = g_tls_client_connection_openssl_get_property;
+  gobject_class->set_property         = g_tls_client_connection_openssl_set_property;
+  gobject_class->constructed          = g_tls_client_connection_openssl_constructed;
 
-  gobject_class->finalize     = g_tls_client_connection_openssl_finalize;
-  gobject_class->get_property = g_tls_client_connection_openssl_get_property;
-  gobject_class->set_property = g_tls_client_connection_openssl_set_property;
-  gobject_class->constructed  = g_tls_client_connection_openssl_constructed;
+  base_class->verify_peer_certificate = g_tls_client_connection_openssl_verify_peer_certificate;
 
-  connection_class->get_ssl = g_tls_client_connection_openssl_get_ssl;
+  openssl_class->get_ssl              = g_tls_client_connection_openssl_get_ssl;
 
   g_object_class_override_property (gobject_class, PROP_VALIDATION_FLAGS, "validation-flags");
   g_object_class_override_property (gobject_class, PROP_SERVER_IDENTITY, "server-identity");
diff --git a/tls/openssl/gtlsconnection-openssl.c b/tls/openssl/gtlsconnection-openssl.c
index cbd193b..95ecb20 100644
--- a/tls/openssl/gtlsconnection-openssl.c
+++ b/tls/openssl/gtlsconnection-openssl.c
@@ -290,120 +290,18 @@ get_peer_certificate (GTlsConnectionOpenssl *openssl)
   return G_TLS_CERTIFICATE (chain);
 }
 
-static GTlsCertificateFlags
-verify_ocsp_response (GTlsConnectionOpenssl *openssl,
-                      GTlsDatabase          *database,
-                      GTlsCertificate       *peer_certificate)
+static int
+handshake_thread_verify_certificate_cb (int             preverify_ok,
+                                        X509_STORE_CTX *x509_ctx)
 {
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
-  !defined(OPENSSL_NO_OCSP)
-  SSL *ssl = NULL;
-  OCSP_RESPONSE *resp = NULL;
-  long len = 0;
-  unsigned char *p = NULL;
-
-  ssl = g_tls_connection_openssl_get_ssl (openssl);
-  len = SSL_get_tlsext_status_ocsp_resp (ssl, &p);
-  /* Soft fail in case of no response is the best we can do */
-  if (p == NULL)
-    return 0;
-
-  resp = d2i_OCSP_RESPONSE (NULL, (const unsigned char **)&p, len);
-  if (resp == NULL)
-    return G_TLS_CERTIFICATE_GENERIC_ERROR;
-
-  return g_tls_file_database_openssl_verify_ocsp_response (database,
-                                                           peer_certificate,
-                                                           resp);
-#else
+  // FIXME: Get the GTlsConnectionOpenssl out of the X509_STORE_CTX using
+  //        x509_STORE_CTX_get_ex_data... somehow. We probably have to pass
+  //        the GTlsConnectionOpenssl to the GTlsFileDatabaseOpenssl...
+  //        somehow.
+  // return !g_tls_connection_base_handshake_thread_verify_certificate (
+  /* Return 1 for the handshake to continue, 0 to terminate.
+   * Complete opposite of what GnuTLS does. */
   return 0;
-#endif
-}
-
-/* FIXME: Share with GnuTLS */
-static GTlsCertificateFlags
-verify_peer_certificate (GTlsConnectionOpenssl *openssl,
-                         GTlsCertificate       *peer_certificate)
-{
-  GTlsConnection *conn = G_TLS_CONNECTION (openssl);
-  GSocketConnectable *peer_identity;
-  GTlsDatabase *database;
-  GTlsCertificateFlags errors;
-  gboolean is_client;
-
-  is_client = G_IS_TLS_CLIENT_CONNECTION (openssl);
-  if (is_client)
-    peer_identity = g_tls_client_connection_get_server_identity (G_TLS_CLIENT_CONNECTION (openssl));
-  else
-    peer_identity = NULL;
-
-  errors = 0;
-
-  database = g_tls_connection_get_database (conn);
-  if (database == NULL)
-    {
-      errors |= G_TLS_CERTIFICATE_UNKNOWN_CA;
-      errors |= g_tls_certificate_verify (peer_certificate, peer_identity, NULL);
-    }
-  else
-    {
-      GError *error = NULL;
-
-      errors |= g_tls_database_verify_chain (database, peer_certificate,
-                                             is_client ?
-                                             G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER :
-                                             G_TLS_DATABASE_PURPOSE_AUTHENTICATE_CLIENT,
-                                             peer_identity,
-                                             g_tls_connection_get_interaction (conn),
-                                             G_TLS_DATABASE_VERIFY_NONE,
-                                             NULL, &error);
-      if (error)
-        {
-          g_warning ("failure verifying certificate chain: %s",
-                     error->message);
-          g_assert (errors != 0);
-          g_clear_error (&error);
-        }
-    }
-
-  if (is_client && (errors == 0))
-    errors = verify_ocsp_response (openssl, database, peer_certificate);
-
-  return errors;
-}
-
-/* FIXME: Share with GnuTLS */
-static gboolean
-accept_peer_certificate (GTlsConnectionBase   *tls,
-                         GTlsCertificate      *peer_certificate,
-                         GTlsCertificateFlags  peer_certificate_errors)
-{
-  GTlsConnectionBasePrivate *priv = g_tls_connection_base_get_instance_private (tls);
-  gboolean accepted = FALSE;
-
-  if (G_IS_TLS_CLIENT_CONNECTION (tls) && priv->peer_certificate)
-    {
-      GTlsCertificateFlags validation_flags;
-
-      if (!g_tls_connection_base_is_dtls (tls))
-        validation_flags =
-          g_tls_client_connection_get_validation_flags (G_TLS_CLIENT_CONNECTION (tls));
-      else
-        validation_flags =
-          g_dtls_client_connection_get_validation_flags (G_DTLS_CLIENT_CONNECTION (tls));
-
-      if ((peer_certificate_errors & validation_flags) == 0)
-        accepted = TRUE;
-    }
-
-  if (!accepted)
-    {
-      accepted = g_tls_connection_emit_accept_certificate (G_TLS_CONNECTION (tls),
-                                                           peer_certificate,
-                                                           peer_certificate_errors);
-    }
-
-  return accepted;
 }
 
 static GTlsConnectionBaseStatus
@@ -442,43 +340,6 @@ g_tls_connection_openssl_handshake_thread_handshake (GTlsConnectionBase  *tls,
   return status;
 }
 
-// FIXME all this needs to move up to base class
-#if 0
-static void
-g_tls_connection_openssl_complete_handshake (GTlsConnectionBase  *tls,
-                                             gchar              **negotiated_protocol,
-                                             GError             **error)
-{
-  GTlsConnectionOpenssl *openssl = G_TLS_CONNECTION_OPENSSL (tls);
-  GTlsConnectionOpensslPrivate *priv;
-  GTlsCertificate *peer_certificate;
-  GTlsCertificateFlags peer_certificate_errors = 0;
-
-  priv = g_tls_connection_openssl_get_instance_private (openssl);
-
-  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 (peer_certificate)
-    {
-      /* FIXME: This is too late. Verification should occur during the handshake. */
-      if (!accept_peer_certificate (tls, peer_certificate, peer_certificate_errors))
-        {
-          g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
-                               _("Unacceptable TLS certificate"));
-          status = G_TLS_CONNECTION_BASE_ERROR;
-        }
-
-      g_tls_connection_base_set_peer_certificate (G_TLS_CONNECTION_BASE (openssl),
-                                                  peer_certificate,
-                                                  peer_certificate_errors);
-      g_clear_object (&peer_certificate);
-    }
-}
-#endif
-
 static void
 g_tls_connection_openssl_push_io (GTlsConnectionBase *tls,
                                   GIOCondition        direction,
@@ -652,6 +513,8 @@ g_tls_connection_openssl_initable_init (GInitable     *initable,
   ssl = g_tls_connection_openssl_get_ssl (openssl);
   g_assert (ssl != NULL);
 
+  SSL_set_verify (ssl, SSL_VERIFY_PEER, handshake_thread_verify_certificate_cb);
+
   priv->bio = g_tls_bio_new (base_io_stream);
 
   SSL_set_bio (ssl, priv->bio, priv->bio);
diff --git a/tls/openssl/gtlsserverconnection-openssl.c b/tls/openssl/gtlsserverconnection-openssl.c
index 73e86f9..86a51ab 100644
--- a/tls/openssl/gtlsserverconnection-openssl.c
+++ b/tls/openssl/gtlsserverconnection-openssl.c
@@ -172,13 +172,6 @@ g_tls_server_connection_openssl_set_property (GObject      *object,
     }
 }
 
-static int
-verify_callback (int             preverify_ok,
-                 X509_STORE_CTX *ctx)
-{
-  return 1;
-}
-
 static void
 g_tls_server_connection_openssl_prepare_handshake (GTlsConnectionBase  *tls,
                                                    gchar              **advertised_protocols)
@@ -200,7 +193,7 @@ g_tls_server_connection_openssl_prepare_handshake (GTlsConnectionBase  *tls,
       break;
     }
 
-  SSL_set_verify (openssl->ssl, req_mode, verify_callback);
+  SSL_set_verify (openssl->ssl, req_mode, NULL);
   /* FIXME: is this ok? */
   SSL_set_verify_depth (openssl->ssl, 0);
 



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