[glib-networking/mcatanzaro/tls-thread] progress?



commit 6f11c0aa76a1c4ac7b6a6c2901e2771c211f0cf8
Author: Michael Catanzaro <mcatanzaro gnome org>
Date:   Wed Jan 1 08:42:39 2020 -0600

    progress?

 tls/base/gtlsoperationsthread-base.h       |   1 -
 tls/openssl/gtlsbio.c                      |  10 +-
 tls/openssl/gtlsclientconnection-openssl.c | 298 ++---------------------
 tls/openssl/gtlsconnection-openssl.c       |  23 +-
 tls/openssl/gtlsoperationsthread-openssl.c | 372 ++++++++++++++++++++++++++++-
 tls/openssl/gtlsoperationsthread-openssl.h |   4 +-
 tls/openssl/gtlsserverconnection-openssl.c | 171 +------------
 7 files changed, 418 insertions(+), 461 deletions(-)
---
diff --git a/tls/base/gtlsoperationsthread-base.h b/tls/base/gtlsoperationsthread-base.h
index b167759..71f9662 100644
--- a/tls/base/gtlsoperationsthread-base.h
+++ b/tls/base/gtlsoperationsthread-base.h
@@ -213,5 +213,4 @@ GDatagramBased      *g_tls_operations_thread_base_get_base_socket           (GTl
 gboolean             g_tls_operations_thread_base_check                     (GTlsOperationsThreadBase   
*self,
                                                                              GIOCondition                
condition);
 
-
 G_END_DECLS
diff --git a/tls/openssl/gtlsbio.c b/tls/openssl/gtlsbio.c
index e19edd2..710cb57 100644
--- a/tls/openssl/gtlsbio.c
+++ b/tls/openssl/gtlsbio.c
@@ -221,16 +221,16 @@ gtls_bio_read (BIO  *bio,
 }
 
 static int
-gtls_bio_puts(BIO        *bio,
-              const char *str)
+gtls_bio_puts (BIO        *bio,
+               const char *str)
 {
   return gtls_bio_write (bio, str, (int)strlen (str));
 }
 
 static int
-gtls_bio_gets(BIO  *bio,
-              char *buf,
-              int   len)
+gtls_bio_gets (BIO  *bio,
+               char *buf,
+               int   len)
 {
   return -1;
 }
diff --git a/tls/openssl/gtlsclientconnection-openssl.c b/tls/openssl/gtlsclientconnection-openssl.c
index 420f70c..5b31590 100644
--- a/tls/openssl/gtlsclientconnection-openssl.c
+++ b/tls/openssl/gtlsclientconnection-openssl.c
@@ -26,20 +26,19 @@
  */
 
 #include "config.h"
-#include "glib.h"
-
-#include <errno.h>
-#include <string.h>
+#include "gtlsclientconnection-openssl.h"
 
 #include "openssl-include.h"
 #include "gtlsconnection-base.h"
-#include "gtlsclientconnection-openssl.h"
 #include "gtlsbackend-openssl.h"
 #include "gtlscertificate-openssl.h"
 #include "gtlsdatabase-openssl.h"
-#include <glib/gi18n-lib.h>
+#include "gtlsoperationsthread-base.h"
 
-#define DEFAULT_CIPHER_LIST "HIGH:!DSS:!aNULL@STRENGTH"
+#include <errno.h>
+#include <glib.h>
+#include <string.h>
+#include <glib/gi18n-lib.h>
 
 struct _GTlsClientConnectionOpenssl
 {
@@ -55,10 +54,6 @@ struct _GTlsClientConnectionOpenssl
 
   STACK_OF (X509_NAME) *ca_list;
   gboolean ca_list_changed;
-
-  SSL_SESSION *session;
-  SSL *ssl;
-  SSL_CTX *ssl_ctx;
 };
 
 enum
@@ -91,10 +86,6 @@ g_tls_client_connection_openssl_finalize (GObject *object)
   g_clear_pointer (&openssl->session_id, g_bytes_unref);
   g_clear_pointer (&openssl->session_data, g_bytes_unref);
 
-  SSL_free (openssl->ssl);
-  SSL_CTX_free (openssl->ssl_ctx);
-  SSL_SESSION_free (openssl->session);
-
   G_OBJECT_CLASS (g_tls_client_connection_openssl_parent_class)->finalize (object);
 }
 
@@ -172,6 +163,7 @@ g_tls_client_connection_openssl_set_property (GObject      *object,
                                              GParamSpec   *pspec)
 {
   GTlsClientConnectionOpenssl *openssl = G_TLS_CLIENT_CONNECTION_OPENSSL (object);
+  const gchar *hostname;
 
   switch (prop_id)
     {
@@ -183,6 +175,17 @@ g_tls_client_connection_openssl_set_property (GObject      *object,
       if (openssl->server_identity)
         g_object_unref (openssl->server_identity);
       openssl->server_identity = g_value_dup_object (value);
+
+      // FIXME: should allow unsetting server identity on op thread, and for GnuTLS too
+      hostname = get_server_identity (openssl);
+      if (hostname)
+        {
+          GTlsOperationsThreadBase *thread;
+
+          thread = g_tls_connection_base_get_op_thread (G_TLS_CONNECTION_BASE (openssl));
+          if (thread)
+            g_tls_operations_thread_base_set_server_identity (thread, hostname);
+        }
       break;
 
     case PROP_USE_SSL3:
@@ -194,54 +197,6 @@ g_tls_client_connection_openssl_set_property (GObject      *object,
     }
 }
 
-static void
-g_tls_client_connection_openssl_constructed (GObject *object)
-{
-  GTlsClientConnectionOpenssl *openssl = G_TLS_CLIENT_CONNECTION_OPENSSL (object);
-  GSocketConnection *base_conn;
-  GSocketAddress *remote_addr;
-  GInetAddress *iaddr;
-  guint port;
-
-  /* Create a TLS session ID. We base it on the IP address since
-   * different hosts serving the same hostname/service will probably
-   * not share the same session cache. We base it on the
-   * server-identity because at least some servers will fail (rather
-   * than just failing to resume the session) if we don't.
-   * (https://bugs.launchpad.net/bugs/823325)
-   *
-   * FIXME: this logic is broken because it doesn't consider the client
-   * certificate when computing the session ID. The GnuTLS version of this
-   * code has this problem fixed. Eliminate this code duplication.
-   */
-  g_object_get (G_OBJECT (openssl), "base-io-stream", &base_conn, NULL);
-  if (G_IS_SOCKET_CONNECTION (base_conn))
-    {
-      remote_addr = g_socket_connection_get_remote_address (base_conn, NULL);
-      if (G_IS_INET_SOCKET_ADDRESS (remote_addr))
-        {
-          GInetSocketAddress *isaddr = G_INET_SOCKET_ADDRESS (remote_addr);
-          const gchar *server_hostname;
-          gchar *addrstr, *session_id;
-
-          iaddr = g_inet_socket_address_get_address (isaddr);
-          port = g_inet_socket_address_get_port (isaddr);
-
-          addrstr = g_inet_address_to_string (iaddr);
-          server_hostname = get_server_identity (openssl);
-          session_id = g_strdup_printf ("%s/%s/%d", addrstr,
-                                        server_hostname ? server_hostname : "",
-                                        port);
-          openssl->session_id = g_bytes_new_take (session_id, strlen (session_id));
-          g_free (addrstr);
-        }
-      g_object_unref (remote_addr);
-    }
-  g_object_unref (base_conn);
-
-  G_OBJECT_CLASS (g_tls_client_connection_openssl_parent_class)->constructed (object);
-}
-
 static GTlsCertificateFlags
 verify_ocsp_response (GTlsClientConnectionOpenssl *openssl,
                       GTlsCertificate             *peer_certificate)
@@ -279,6 +234,7 @@ verify_ocsp_response (GTlsClientConnectionOpenssl *openssl,
 #endif
 }
 
+// FIXME FIXME: looks important
 static GTlsCertificateFlags
 g_tls_client_connection_openssl_verify_peer_certificate (GTlsConnectionBase   *tls,
                                                          GTlsCertificate      *certificate,
@@ -292,12 +248,6 @@ g_tls_client_connection_openssl_verify_peer_certificate (GTlsConnectionBase   *t
   return flags;
 }
 
-static SSL *
-g_tls_client_connection_openssl_get_ssl (GTlsConnectionOpenssl *connection)
-{
-  return G_TLS_CLIENT_CONNECTION_OPENSSL (connection)->ssl;
-}
-
 static void
 g_tls_client_connection_openssl_class_init (GTlsClientConnectionOpensslClass *klass)
 {
@@ -308,12 +258,9 @@ g_tls_client_connection_openssl_class_init (GTlsClientConnectionOpensslClass *kl
   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;
 
-  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");
   g_object_class_override_property (gobject_class, PROP_USE_SSL3, "use-ssl3");
@@ -338,219 +285,24 @@ g_tls_client_connection_openssl_client_connection_interface_init (GTlsClientConn
   iface->copy_session_state = g_tls_client_connection_openssl_copy_session_state;
 }
 
-static int data_index = -1;
-
-static int
-handshake_thread_retrieve_certificate (SSL       *ssl,
-                                       X509     **x509,
-                                       EVP_PKEY **pkey)
-{
-  GTlsClientConnectionOpenssl *client;
-  GTlsConnectionBase *tls;
-  GTlsCertificate *cert;
-  gboolean had_ca_list;
-
-  client = SSL_get_ex_data (ssl, data_index);
-  tls = G_TLS_CONNECTION_BASE (client);
-
-  had_ca_list = client->ca_list != NULL;
-  client->ca_list = SSL_get_client_CA_list (client->ssl);
-  client->ca_list_changed = client->ca_list || had_ca_list;
-
-  cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (client));
-  if (!cert)
-    {
-      if (g_tls_connection_base_handshake_thread_request_certificate (tls))
-        cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (client));
-    }
-
-  if (cert)
-    {
-      EVP_PKEY *key;
-
-      key = g_tls_certificate_openssl_get_key (G_TLS_CERTIFICATE_OPENSSL (cert));
-      /* increase ref count */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
-      CRYPTO_add (&key->references, 1, CRYPTO_LOCK_EVP_PKEY);
-#else
-      EVP_PKEY_up_ref (key);
-#endif
-      *pkey = key;
-
-      *x509 = X509_dup (g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (cert)));
-
-      return 1;
-    }
-
-  g_tls_connection_base_handshake_thread_set_missing_requested_client_certificate (tls);
-
-  return 0;
-}
-
-static int
-generate_session_id (SSL           *ssl,
-                     unsigned char *id,
-                     unsigned int  *id_len)
-{
-  GTlsClientConnectionOpenssl *client;
-  int len;
-
-  client = SSL_get_ex_data (ssl, data_index);
-
-  len = MIN (*id_len, g_bytes_get_size (client->session_id));
-  memcpy (id, g_bytes_get_data (client->session_id, NULL), len);
-
-  return 1;
-}
-
-static gboolean
-set_cipher_list (GTlsClientConnectionOpenssl  *client,
-                 GError                      **error)
-{
-  const gchar *cipher_list;
-
-  cipher_list = g_getenv ("G_TLS_OPENSSL_CIPHER_LIST");
-  if (!cipher_list)
-    cipher_list = DEFAULT_CIPHER_LIST;
-
-  if (!SSL_CTX_set_cipher_list (client->ssl_ctx, cipher_list))
-    {
-      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
-                   _("Could not create TLS context: %s"),
-                   ERR_error_string (ERR_get_error (), NULL));
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-#ifdef SSL_CTX_set1_sigalgs_list
-static void
-set_signature_algorithm_list (GTlsClientConnectionOpenssl *client)
-{
-  const gchar *signature_algorithm_list;
-
-  signature_algorithm_list = g_getenv ("G_TLS_OPENSSL_SIGNATURE_ALGORITHM_LIST");
-  if (!signature_algorithm_list)
-    return;
-
-  SSL_CTX_set1_sigalgs_list (client->ssl_ctx, signature_algorithm_list);
-}
-#endif
-
-#ifdef SSL_CTX_set1_curves_list
-static void
-set_curve_list (GTlsClientConnectionOpenssl *client)
-{
-  const gchar *curve_list;
-
-  curve_list = g_getenv ("G_TLS_OPENSSL_CURVE_LIST");
-  if (!curve_list)
-    return;
-
-  SSL_CTX_set1_curves_list (client->ssl_ctx, curve_list);
-}
-#endif
-
-static gboolean
-use_ocsp (void)
-{
-  return g_getenv ("G_TLS_OPENSSL_OCSP_ENABLED") != NULL;
-}
-
 static gboolean
 g_tls_client_connection_openssl_initable_init (GInitable       *initable,
                                                GCancellable    *cancellable,
                                                GError         **error)
 {
-  GTlsClientConnectionOpenssl *client = G_TLS_CLIENT_CONNECTION_OPENSSL (initable);
-  long options;
-  const char *hostname;
-
-  client->session = SSL_SESSION_new ();
-
-  client->ssl_ctx = SSL_CTX_new (SSLv23_client_method ());
-  if (!client->ssl_ctx)
-    {
-      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
-                   _("Could not create TLS context: %s"),
-                   ERR_error_string (ERR_get_error (), NULL));
-      return FALSE;
-    }
+  GTlsClientConnectionOpenssl *client;
+  GTlsOperationsThreadBase *thread;
+  const gchar *hostname;
 
-  if (!set_cipher_list (client, error))
+  if (!g_tls_client_connection_openssl_parent_initable_iface->init (initable, cancellable, error))
     return FALSE;
 
-  /* Only TLS 1.2 or higher */
-  options = SSL_OP_NO_TICKET |
-            SSL_OP_NO_COMPRESSION |
-#ifdef SSL_OP_NO_TLSv1_1
-            SSL_OP_NO_TLSv1_1 |
-#endif
-            SSL_OP_NO_SSLv2 |
-            SSL_OP_NO_SSLv3 |
-            SSL_OP_NO_TLSv1;
-  SSL_CTX_set_options (client->ssl_ctx, options);
-
-  SSL_CTX_clear_options (client->ssl_ctx, SSL_OP_LEGACY_SERVER_CONNECT);
-
   hostname = get_server_identity (client);
-
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined (LIBRESSL_VERSION_NUMBER)
   if (hostname)
     {
-      X509_VERIFY_PARAM *param;
-
-      param = X509_VERIFY_PARAM_new ();
-      X509_VERIFY_PARAM_set1_host (param, hostname, 0);
-      SSL_CTX_set1_param (client->ssl_ctx, param);
-      X509_VERIFY_PARAM_free (param);
+      thread = g_tls_connection_base_get_op_thread (G_TLS_CONNECTION_BASE (client));
+      g_tls_operations_thread_base_set_server_identity (thread, hostname);
     }
-#endif
-
-  SSL_CTX_set_generate_session_id (client->ssl_ctx, (GEN_SESSION_CB)generate_session_id);
-
-  SSL_CTX_add_session (client->ssl_ctx, client->session);
-
-  SSL_CTX_set_client_cert_cb (client->ssl_ctx, handshake_thread_retrieve_certificate);
-
-#ifdef SSL_CTX_set1_sigalgs_list
-  set_signature_algorithm_list (client);
-#endif
-
-#ifdef SSL_CTX_set1_curves_list
-  set_curve_list (client);
-#endif
-
-  client->ssl = SSL_new (client->ssl_ctx);
-  if (!client->ssl)
-    {
-      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
-                   _("Could not create TLS connection: %s"),
-                   ERR_error_string (ERR_get_error (), NULL));
-      return FALSE;
-    }
-
-  if (data_index == -1) {
-      data_index = SSL_get_ex_new_index (0, (void *)"gtlsclientconnection", NULL, NULL, NULL);
-  }
-  SSL_set_ex_data (client->ssl, data_index, client);
-
-#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
-  if (hostname)
-    SSL_set_tlsext_host_name (client->ssl, hostname);
-#endif
-
-  SSL_set_connect_state (client->ssl);
-
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
-    !defined(OPENSSL_NO_OCSP)
-  if (use_ocsp())
-    SSL_set_tlsext_status_type (client->ssl, TLSEXT_STATUSTYPE_ocsp);
-#endif
-
-  if (!g_tls_client_connection_openssl_parent_initable_iface->init (initable, cancellable, error))
-    return FALSE;
 
   return TRUE;
 }
diff --git a/tls/openssl/gtlsconnection-openssl.c b/tls/openssl/gtlsconnection-openssl.c
index 9833612..8260232 100644
--- a/tls/openssl/gtlsconnection-openssl.c
+++ b/tls/openssl/gtlsconnection-openssl.c
@@ -58,7 +58,24 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GTlsConnectionOpenssl, g_tls_connection_openss
 static GTlsOperationsThreadBase *
 g_tls_connection_openssl_create_op_thread (GTlsConnectionBase *tls)
 {
-  return g_tls_operations_thread_openssl_new (G_TLS_CONNECTION_OPENSSL (tls));
+  GTlsOperationsThreadBase *thread;
+  GTlsOperationsThreadType thread_type;
+  GIOStream *base_iostream = NULL;
+
+  g_object_get (tls,
+                "base-io-stream", &base_iostream,
+                NULL);
+
+  if (G_IS_TLS_CLIENT_CONNECTION (tls))
+    thread_type = G_TLS_OPERATIONS_THREAD_CLIENT;
+  else
+    thread_type = G_TLS_OPERATIONS_THREAD_SERVER;
+
+  thread = g_tls_operations_thread_openssl_new (base_iostream,
+                                                thread_type);
+  g_object_unref (base_iostream);
+
+  return thread;
 }
 
 static GTlsCertificate *
@@ -191,6 +208,8 @@ g_tls_connection_openssl_initable_init (GInitable     *initable,
 
   SSL_set_bio (ssl, priv->bio, priv->bio);
 
+  g_object_unref (base_io_stream);
+
   return g_tls_connection_openssl_parent_initable_iface->init (initable, cancellable, error);
 }
 
@@ -207,6 +226,7 @@ g_tls_connection_openssl_init (GTlsConnectionOpenssl *openssl)
 {
 }
 
+// FIXME: remove
 SSL *
 g_tls_connection_openssl_get_ssl (GTlsConnectionOpenssl *openssl)
 {
@@ -215,6 +235,7 @@ g_tls_connection_openssl_get_ssl (GTlsConnectionOpenssl *openssl)
   return G_TLS_CONNECTION_OPENSSL_GET_CLASS (openssl)->get_ssl (openssl);
 }
 
+// FIXME: remove
 GTlsConnectionOpenssl *
 g_tls_connection_openssl_get_connection_from_ssl (SSL *ssl)
 {
diff --git a/tls/openssl/gtlsoperationsthread-openssl.c b/tls/openssl/gtlsoperationsthread-openssl.c
index e67bbee..41414bb 100644
--- a/tls/openssl/gtlsoperationsthread-openssl.c
+++ b/tls/openssl/gtlsoperationsthread-openssl.c
@@ -31,10 +31,18 @@
 
 #include <glib/gi18n-lib.h>
 
+#define DEFAULT_CIPHER_LIST "HIGH:!DSS:!aNULL@STRENGTH"
+
+static int data_index = -1;
+
 struct _GTlsOperationsThreadOpenssl {
   GTlsOperationsThreadBase parent_instance;
 
+  GTlsOperationsThreadType thread_type;
+
+  SSL_SESSION *session;
   SSL *ssl;
+  SSL_CTX *ssl_ctx;
 
   gboolean shutting_down;
 };
@@ -48,6 +56,43 @@ G_DEFINE_TYPE_WITH_CODE (GTlsOperationsThreadOpenssl, g_tls_operations_thread_op
                                                 g_tls_operations_thread_openssl_initable_iface_init);
                          )
 
+static inline gboolean
+is_client (GTlsOperationsThreadOpenssl *self)
+{
+  return self->thread_type == G_TLS_OPERATIONS_THREAD_CLIENT;
+}
+
+static inline gboolean
+is_server (GTlsOperationsThreadOpenssl *self)
+{
+  return self->thread_type == G_TLS_OPERATIONS_THREAD_SERVER;
+}
+
+static void
+g_tls_operations_thread_openssl_set_server_identity (GTlsOperationsThreadBase *base,
+                                                     const gchar              *server_identity)
+{
+  GTlsOperationsThreadOpenssl *self = G_TLS_OPERATIONS_THREAD_OPENSSL (base);
+
+  g_assert (is_client (self));
+
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined (LIBRESSL_VERSION_NUMBER)
+  if (server_identity)
+    {
+      X509_VERIFY_PARAM *param;
+
+      param = X509_VERIFY_PARAM_new ();
+      X509_VERIFY_PARAM_set1_host (param, server_identity, 0);
+      SSL_CTX_set1_param (self->ssl_ctx, param);
+      X509_VERIFY_PARAM_free (param);
+
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+      SSL_set_tlsext_host_name (self->ssl, server_identity);
+#endif
+    }
+#endif
+}
+
 static GTlsOperationStatus
 end_openssl_io (GTlsOperationsThreadOpenssl  *self,
                 GIOCondition                  direction,
@@ -273,19 +318,322 @@ g_tls_operations_thread_openssl_close (GTlsOperationsThreadBase  *base,
   return status;
 }
 
+static gboolean
+set_cipher_list (GTlsOperationsThreadOpenssl  *self,
+                 GError                      **error)
+{
+  const gchar *cipher_list;
+
+  cipher_list = g_getenv ("G_TLS_OPENSSL_CIPHER_LIST");
+  if (!cipher_list)
+    cipher_list = DEFAULT_CIPHER_LIST;
+
+  if (!SSL_CTX_set_cipher_list (self->ssl_ctx, cipher_list))
+    {
+      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+                   _("Could not create TLS context: %s"),
+                   ERR_error_string (ERR_get_error (), NULL));
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+#ifdef SSL_CTX_set1_sigalgs_list
+static void
+set_signature_algorithm_list (GTlsOperationsThreadOpenssl *self)
+{
+  const gchar *signature_algorithm_list;
+
+  signature_algorithm_list = g_getenv ("G_TLS_OPENSSL_SIGNATURE_ALGORITHM_LIST");
+  if (!signature_algorithm_list)
+    return;
+
+  SSL_CTX_set1_sigalgs_list (self->ssl_ctx, signature_algorithm_list);
+}
+#endif
+
+#ifdef SSL_CTX_set1_curves_list
+static void
+set_curve_list (GTlsOperationsThreadOpenssl *self)
+{
+  const gchar *curve_list;
+
+  curve_list = g_getenv ("G_TLS_OPENSSL_CURVE_LIST");
+  if (!curve_list)
+    return;
+
+  SSL_CTX_set1_curves_list (self->ssl_ctx, curve_list);
+}
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+static void
+ssl_info_callback (const SSL *ssl,
+                   int        type,
+                   int        val)
+{
+  g_assert (is_server (self));
+
+  if ((type & SSL_CB_HANDSHAKE_DONE) != 0)
+    {
+      /* Disable renegotiation (CVE-2009-3555) */
+      ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
+    }
+}
+#endif
+
+static void
+compute_session_id (GTlsOperationsThreadOpenssl *self)
+{
+  GSocketConnection *base_conn;
+  GSocketAddress *remote_addr;
+  GInetAddress *iaddr;
+  guint port;
+
+  /* FIXME: this logic is broken because it doesn't consider the client
+   * certificate when computing the session ID. The GnuTLS version of this
+   * code has this problem fixed. Eliminate this code duplication.
+   */
+  g_object_get (G_OBJECT (openssl), "base-io-stream", &base_conn, NULL);
+  if (G_IS_SOCKET_CONNECTION (base_conn))
+    {
+      remote_addr = g_socket_connection_get_remote_address (base_conn, NULL);
+      if (G_IS_INET_SOCKET_ADDRESS (remote_addr))
+        {
+          GInetSocketAddress *isaddr = G_INET_SOCKET_ADDRESS (remote_addr);
+          const gchar *server_hostname;
+          gchar *addrstr, *session_id;
+
+          iaddr = g_inet_socket_address_get_address (isaddr);
+          port = g_inet_socket_address_get_port (isaddr);
+
+          addrstr = g_inet_address_to_string (iaddr);
+          server_hostname = get_server_identity (openssl); /* FIXME: server identity won't be available 
until after init... */
+          session_id = g_strdup_printf ("%s/%s/%d", addrstr,
+                                        server_hostname ? server_hostname : "",
+                                        port);
+          self->session_id = g_bytes_new_take (session_id, strlen (session_id));
+          g_free (addrstr);
+        }
+      g_object_unref (remote_addr);
+    }
+  g_object_unref (base_conn);
+}
+
+static int
+generate_session_id_cb (SSL           *ssl,
+                        unsigned char *id,
+                        unsigned int  *id_len)
+{
+  GTlsOperationsThreadOpenssl *self;
+  int len;
+
+  self = SSL_get_ex_data (ssl, data_index);
+
+  len = MIN (*id_len, g_bytes_get_size (self->session_id));
+  memcpy (id, g_bytes_get_data (self->session_id, NULL), len);
+
+  return 1;
+}
+
+static int
+retrieve_certificate_cb (SSL       *ssl,
+                         X509     **x509,
+                         EVP_PKEY **pkey)
+{
+  GTlsOperationsThreadOpenssl *self;
+  GTlsConnectionBase *tls;
+  GTlsCertificate *cert;
+  gboolean had_ca_list;
+
+  self = SSL_get_ex_data (ssl, data_index);
+  tls = G_TLS_CONNECTION_BASE (client);
+
+  had_ca_list = self->ca_list != NULL;
+  self->ca_list = SSL_get_client_CA_list (client->ssl);
+  self->ca_list_changed = self->ca_list || had_ca_list;
+
+  cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (client));
+  if (!cert)
+    {
+      if (g_tls_connection_base_handshake_thread_request_certificate (tls))
+        cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (client));
+    }
+
+  if (cert)
+    {
+      EVP_PKEY *key;
+
+      key = g_tls_certificate_openssl_get_key (G_TLS_CERTIFICATE_OPENSSL (cert));
+      /* increase ref count */
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+      CRYPTO_add (&key->references, 1, CRYPTO_LOCK_EVP_PKEY);
+#else
+      EVP_PKEY_up_ref (key);
+#endif
+      *pkey = key;
+
+      *x509 = X509_dup (g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (cert)));
+
+      return 1;
+    }
+
+  g_tls_connection_base_handshake_thread_set_missing_requested_client_certificate (tls);
+
+  return 0;
+}
+
+static gboolean
+use_ocsp (void)
+{
+  return g_getenv ("G_TLS_OPENSSL_OCSP_ENABLED") != NULL;
+}
+
+static void
+g_tls_operations_thread_openssl_finalize (GObject *object)
+{
+  GTlsOperationsThreadOpenssl *self = G_TLS_OPERATIONS_THREAD_OPENSSL (object);
+
+  SSL_free (self->ssl);
+  SSL_CTX_free (self->ssl_ctx);
+  SSL_SESSION_free (self->session);
+
+  G_OBJECT_CLASS (g_tls_operations_thread_openssl_parent_class)->finalize (object);
+}
+
 static gboolean
 g_tls_operations_thread_openssl_initable_init (GInitable     *initable,
                                                GCancellable  *cancellable,
                                                GError       **error)
 {
   GTlsOperationsThreadOpenssl *self = G_TLS_OPERATIONS_THREAD_OPENSSL (initable);
-  GTlsConnectionBase *openssl;
+  long options;
+  const char *hostname;
+  GTlsCertificate *cert; /* FIXME: remove, become part of handshake op? */
 
   if (!g_tls_operations_thread_openssl_parent_initable_iface->init (initable, cancellable, error))
     return FALSE;
 
-  openssl = g_tls_operations_thread_base_get_connection (G_TLS_OPERATIONS_THREAD_BASE (self));
-  self->ssl = g_tls_connection_openssl_get_ssl (G_TLS_CONNECTION_OPENSSL (openssl));
+  g_object_get (self,
+                "thread-type", &self->thread_type,
+                NULL);
+
+  if (is_client (self)) /* FIXME: broken */
+    compute_session_id (self);
+
+  self->session = SSL_SESSION_new ();
+  self->ssl_ctx = SSL_CTX_new (is_client (self) ? SSLv23_client_method () : SSLv23_server_method ());
+  if (!self->ssl_ctx)
+    {
+      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+                   _("Could not create TLS context: %s"),
+                   ERR_error_string (ERR_get_error (), NULL));
+      return FALSE;
+    }
+
+    if (!set_cipher_list (self, error))
+      return FALSE;
+
+  /* Only TLS 1.2 or higher */
+  options = SSL_OP_NO_TICKET |
+            SSL_OP_NO_COMPRESSION |
+#ifdef SSL_OP_NO_TLSv1_1
+            SSL_OP_NO_TLSv1_1 |
+#endif
+            SSL_OP_NO_SSLv2 |
+            SSL_OP_NO_SSLv3 |
+            SSL_OP_NO_TLSv1;
+
+  if (is_server (self))
+    {
+      SSL_CTX_set_options (self->ssl_ctx, options);
+    }
+  else
+    {
+      options |= SSL_OP_CIPHER_SERVER_PREFERENCE |
+                 SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
+                 SSL_OP_SINGLE_ECDH_USE;
+#ifdef SSL_OP_NO_RENEGOTIATION
+      options |= SSL_OP_NO_RENEGOTIATION;
+#endif
+      SSL_CTX_set_options (self->ssl_ctx, options);
+      SSL_CTX_clear_options (self->ssl_ctx, SSL_OP_LEGACY_SERVER_CONNECT);
+
+      SSL_CTX_set_generate_session_id (self->ssl_ctx, (GEN_SESSION_CB)generate_session_id_cb);
+
+      SSL_CTX_set_client_cert_cb (self->ssl_ctx, retrieve_certificate_cb);
+    }
+
+  SSL_CTX_add_session (self->ssl_ctx, self->session);
+
+#ifdef SSL_CTX_set1_sigalgs_list
+  set_signature_algorithm_list (server);
+#endif
+
+#ifdef SSL_CTX_set1_curves_list
+  set_curve_list (server);
+#endif
+
+  if (is_server (self))
+    {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
+# ifdef SSL_CTX_set_ecdh_auto
+      SSL_CTX_set_ecdh_auto (self->ssl_ctx, 1);
+# else
+      {
+        EC_KEY *ecdh;
+
+        ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1);
+        if (ecdh)
+          {
+            SSL_CTX_set_tmp_ecdh (self->ssl_ctx, ecdh);
+            EC_KEY_free (ecdh);
+          }
+      }
+# endif
+
+      SSL_CTX_set_info_callback (self->ssl_ctx, ssl_info_callback);
+#endif
+
+      cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (initable));
+
+#if OPENSSL_VERSION_NUMBER < 0x10002000L
+      if (cert && !ssl_ctx_set_certificate (server->ssl_ctx, cert, error))
+        return FALSE;
+#endif
+    }
+
+  self->ssl = SSL_new (self->ssl_ctx);
+  if (!self->ssl)
+    {
+      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
+                   _("Could not create TLS connection: %s"),
+                   ERR_error_string (ERR_get_error (), NULL));
+      return FALSE;
+    }
+
+  if (data_index == -1)
+    data_index = SSL_get_ex_new_index (0, (void *)"gtlsoperationsthread", NULL, NULL, NULL);
+  SSL_set_ex_data (self->ssl, data_index, self);
+
+  if (is_client (self))
+    {
+      SSL_set_connect_state (client->ssl);
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_OCSP)
+      if (use_ocsp())
+        SSL_set_tlsext_status_type (client->ssl, TLSEXT_STATUSTYPE_ocsp);
+#endif
+    }
+  else
+    {
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L || defined (LIBRESSL_VERSION_NUMBER)
+      if (cert && !ssl_set_certificate (server->ssl, cert, error))
+        return FALSE;
+#endif
+      SSL_set_accept_state (server->ssl);
+    }
 
   return TRUE;
 }
@@ -301,10 +649,14 @@ g_tls_operations_thread_openssl_class_init (GTlsOperationsThreadOpensslClass *kl
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   GTlsOperationsThreadBaseClass *base_class = G_TLS_OPERATIONS_THREAD_BASE_CLASS (klass);
 
-  base_class->handshake_fn   = g_tls_operations_thread_openssl_handshake;
-  base_class->read_fn        = g_tls_operations_thread_openssl_read;
-  base_class->write_fn       = g_tls_operations_thread_openssl_write;
-  base_class->close_fn       = g_tls_operations_thread_openssl_close;
+  gobject_class->finalize         = g_tls_operations_thread_openssl_finalize;
+
+  base_class->copy_certificate    = g_tls_operations_thread_openssl_copy_certificate;
+  base_class->set_server_identity = g_tls_operations_thread_openssl_set_server_identity;
+  base_class->handshake_fn        = g_tls_operations_thread_openssl_handshake;
+  base_class->read_fn             = g_tls_operations_thread_openssl_read;
+  base_class->write_fn            = g_tls_operations_thread_openssl_write;
+  base_class->close_fn            = g_tls_operations_thread_openssl_close;
 }
 
 static void
@@ -316,12 +668,12 @@ g_tls_operations_thread_openssl_initable_iface_init (GInitableIface *iface)
 }
 
 GTlsOperationsThreadBase *
-g_tls_operations_thread_openssl_new (GTlsConnectionOpenssl *tls,
-                                     GIOStream             *base_iostream)
+g_tls_operations_thread_openssl_new (GIOStream                *base_iostream,
+                                     GTlsOperationsThreadType  type)
 {
   return g_initable_new (G_TYPE_TLS_OPERATIONS_THREAD_OPENSSL,
                          NULL, NULL,
                          "base-iostream", base_iostream,
-                         "tls-connection", tls,
+                         "thread-type", type,
                          NULL);
 }
diff --git a/tls/openssl/gtlsoperationsthread-openssl.h b/tls/openssl/gtlsoperationsthread-openssl.h
index 7441f3c..9a3ecc0 100644
--- a/tls/openssl/gtlsoperationsthread-openssl.h
+++ b/tls/openssl/gtlsoperationsthread-openssl.h
@@ -36,7 +36,7 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (GTlsOperationsThreadOpenssl, g_tls_operations_thread_openssl, G, 
TLS_OPERATIONS_THREAD_OPENSSL, GTlsOperationsThreadBase)
 
-GTlsOperationsThreadBase *g_tls_operations_thread_openssl_new (GTlsConnectionOpenssl *tls,
-                                                               GIOStream             *base_iostream);
+GTlsOperationsThreadBase *g_tls_operations_thread_openssl_new (GIOStream                *base_iostream,
+                                                               GTlsOperationsThreadType  type);
 
 G_END_DECLS
diff --git a/tls/openssl/gtlsserverconnection-openssl.c b/tls/openssl/gtlsserverconnection-openssl.c
index 2165ccb..ead2b8a 100644
--- a/tls/openssl/gtlsserverconnection-openssl.c
+++ b/tls/openssl/gtlsserverconnection-openssl.c
@@ -33,16 +33,11 @@
 #include "openssl-include.h"
 #include <glib/gi18n-lib.h>
 
-#define DEFAULT_CIPHER_LIST "HIGH:!DSS:!aNULL@STRENGTH"
-
 struct _GTlsServerConnectionOpenssl
 {
   GTlsConnectionOpenssl parent_instance;
 
   GTlsAuthenticationMode authentication_mode;
-  SSL_SESSION *session;
-  SSL *ssl;
-  SSL_CTX *ssl_ctx;
 };
 
 enum
@@ -63,17 +58,6 @@ G_DEFINE_TYPE_WITH_CODE (GTlsServerConnectionOpenssl, g_tls_server_connection_op
                          G_IMPLEMENT_INTERFACE (G_TYPE_TLS_SERVER_CONNECTION,
                                                 
g_tls_server_connection_openssl_server_connection_interface_init))
 
-static void
-g_tls_server_connection_openssl_finalize (GObject *object)
-{
-  GTlsServerConnectionOpenssl *openssl = G_TLS_SERVER_CONNECTION_OPENSSL (object);
-
-  SSL_free (openssl->ssl);
-  SSL_CTX_free (openssl->ssl_ctx);
-  SSL_SESSION_free (openssl->session);
-
-  G_OBJECT_CLASS (g_tls_server_connection_openssl_parent_class)->finalize (object);
-}
 
 static void
 g_tls_server_connection_openssl_get_property (GObject    *object,
@@ -296,7 +280,6 @@ g_tls_server_connection_openssl_class_init (GTlsServerConnectionOpensslClass *kl
   GTlsConnectionBaseClass *base_class = G_TLS_CONNECTION_BASE_CLASS (klass);
   GTlsConnectionOpensslClass *connection_class = G_TLS_CONNECTION_OPENSSL_CLASS (klass);
 
-  gobject_class->finalize = g_tls_server_connection_openssl_finalize;
   gobject_class->get_property = g_tls_server_connection_openssl_get_property;
   gobject_class->set_property = g_tls_server_connection_openssl_set_property;
 
@@ -317,167 +300,17 @@ g_tls_server_connection_openssl_server_connection_interface_init (GTlsServerConn
 {
 }
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
-static void
-ssl_info_callback (const SSL *ssl,
-                   int        type,
-                   int        val)
-{
-  if ((type & SSL_CB_HANDSHAKE_DONE) != 0)
-    {
-      /* Disable renegotiation (CVE-2009-3555) */
-      ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
-    }
-}
-#endif
-
-static gboolean
-set_cipher_list (GTlsServerConnectionOpenssl  *server,
-                 GError                      **error)
-{
-  const gchar *cipher_list;
-
-  cipher_list = g_getenv ("G_TLS_OPENSSL_CIPHER_LIST");
-  if (!cipher_list)
-    cipher_list = DEFAULT_CIPHER_LIST;
-
-  if (!SSL_CTX_set_cipher_list (server->ssl_ctx, cipher_list))
-    {
-      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
-                   _("Could not create TLS context: %s"),
-                   ERR_error_string (ERR_get_error (), NULL));
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-#ifdef SSL_CTX_set1_sigalgs_list
-static void
-set_signature_algorithm_list (GTlsServerConnectionOpenssl *server)
-{
-  const gchar *signature_algorithm_list;
-
-  signature_algorithm_list = g_getenv ("G_TLS_OPENSSL_SIGNATURE_ALGORITHM_LIST");
-  if (!signature_algorithm_list)
-    return;
-
-  SSL_CTX_set1_sigalgs_list (server->ssl_ctx, signature_algorithm_list);
-}
-#endif
-
-#ifdef SSL_CTX_set1_curves_list
-static void
-set_curve_list (GTlsServerConnectionOpenssl *server)
-{
-  const gchar *curve_list;
-
-  curve_list = g_getenv ("G_TLS_OPENSSL_CURVE_LIST");
-  if (!curve_list)
-    return;
-
-  SSL_CTX_set1_curves_list (server->ssl_ctx, curve_list);
-}
-#endif
-
 static gboolean
 g_tls_server_connection_openssl_initable_init (GInitable       *initable,
                                                GCancellable    *cancellable,
                                                GError         **error)
 {
   GTlsServerConnectionOpenssl *server = G_TLS_SERVER_CONNECTION_OPENSSL (initable);
-  GTlsCertificate *cert;
-  long options;
-
-  server->session = SSL_SESSION_new ();
-
-  server->ssl_ctx = SSL_CTX_new (SSLv23_server_method ());
-  if (!server->ssl_ctx)
-    {
-      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
-                   _("Could not create TLS context: %s"),
-                   ERR_error_string (ERR_get_error (), NULL));
-      return FALSE;
-    }
-
-  if (!set_cipher_list (server, error))
-    return FALSE;
-
-  /* Only TLS 1.2 or higher */
-  options = SSL_OP_NO_TICKET |
-            SSL_OP_NO_COMPRESSION |
-            SSL_OP_CIPHER_SERVER_PREFERENCE |
-            SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
-            SSL_OP_SINGLE_ECDH_USE |
-#ifdef SSL_OP_NO_TLSv1_1
-            SSL_OP_NO_TLSv1_1 |
-#endif
-            SSL_OP_NO_SSLv2 |
-            SSL_OP_NO_SSLv3 |
-            SSL_OP_NO_TLSv1;
-
-#ifdef SSL_OP_NO_RENEGOTIATION
-  options |= SSL_OP_NO_RENEGOTIATION;
-#endif
-
-  SSL_CTX_set_options (server->ssl_ctx, options);
-
-  SSL_CTX_add_session (server->ssl_ctx, server->session);
-
-#ifdef SSL_CTX_set1_sigalgs_list
-  set_signature_algorithm_list (server);
-#endif
-
-#ifdef SSL_CTX_set1_curves_list
-  set_curve_list (server);
-#endif
-
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined (LIBRESSL_VERSION_NUMBER)
-# ifdef SSL_CTX_set_ecdh_auto
-  SSL_CTX_set_ecdh_auto (server->ssl_ctx, 1);
-# else
-  {
-    EC_KEY *ecdh;
-
-    ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1);
-    if (ecdh)
-      {
-        SSL_CTX_set_tmp_ecdh (server->ssl_ctx, ecdh);
-        EC_KEY_free (ecdh);
-      }
-  }
-# endif
-
-  SSL_CTX_set_info_callback (server->ssl_ctx, ssl_info_callback);
-#endif
-
-  cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (initable));
-
-#if OPENSSL_VERSION_NUMBER < 0x10002000L
-  if (cert && !ssl_ctx_set_certificate (server->ssl_ctx, cert, error))
-    return FALSE;
-#endif
-
-  server->ssl = SSL_new (server->ssl_ctx);
-  if (!server->ssl)
-    {
-      g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
-                   _("Could not create TLS connection: %s"),
-                   ERR_error_string (ERR_get_error (), NULL));
-      return FALSE;
-    }
-
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L || defined (LIBRESSL_VERSION_NUMBER)
-  if (cert && !ssl_set_certificate (server->ssl, cert, error))
-    return FALSE;
-#endif
-
-  SSL_set_accept_state (server->ssl);
 
-  if (!g_tls_server_connection_openssl_parent_initable_iface->
-      init (initable, cancellable, error))
+  if (!g_tls_server_connection_openssl_parent_initable_iface->init (initable, cancellable, error))
     return FALSE;
 
+// FIXME: remove this
 #if OPENSSL_VERSION_NUMBER >= 0x10002000L || defined (LIBRESSL_VERSION_NUMBER)
   g_signal_connect (server, "notify::certificate", G_CALLBACK (on_certificate_changed), NULL);
 #endif



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