[glib-networking] gnutls: Add support for copying session data



commit fb3f6b8017ca2e5272b4fc5ec9625b14b0ed9f51
Author: Ross Lagerwall <rosslagerwall gmail com>
Date:   Thu Feb 26 22:12:21 2015 +0000

    gnutls: Add support for copying session data
    
    Add support for copying session data between client connections.
    This is needed for implementing FTP over TLS. Most servers use a separate
    session for each control connection and enforce sharing of each control
    connection's session between the related data connection.
    
    Copying session data between two connections is needed for two reasons:
    1) The data connection runs on a separate port and so has a different
    server_identity which means it would not normally share the session with
    the control connection using the session caching currently implemented.
    2) It is typical to have multiple control connections, each of which
    uses a different session with the same server_identity, so only one of
    these sessions gets stored in the cache. If a data connection is opened,
    (ignoring the port issue) it may try and reuse the wrong control
    connection's session, and fail.
    
    This operation is conceptually the same as OpenSSL's SSL_copy_session_id
    operation.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=745255

 tls/gnutls/gtlsclientconnection-gnutls.c |   88 ++++++++++++++++++++----------
 1 files changed, 60 insertions(+), 28 deletions(-)
---
diff --git a/tls/gnutls/gtlsclientconnection-gnutls.c b/tls/gnutls/gtlsclientconnection-gnutls.c
index 7ca4220..060a2f3 100644
--- a/tls/gnutls/gtlsclientconnection-gnutls.c
+++ b/tls/gnutls/gtlsclientconnection-gnutls.c
@@ -57,8 +57,10 @@ struct _GTlsClientConnectionGnutlsPrivate
   GTlsCertificateFlags validation_flags;
   GSocketConnectable *server_identity;
   gboolean use_ssl3;
+  gboolean session_data_override;
 
   GBytes *session_id;
+  GBytes *session_data;
 
   gboolean cert_requested;
   GError *cert_error;
@@ -141,6 +143,7 @@ g_tls_client_connection_gnutls_finalize (GObject *object)
   g_clear_object (&gnutls->priv->server_identity);
   g_clear_pointer (&gnutls->priv->accepted_cas, g_ptr_array_unref);
   g_clear_pointer (&gnutls->priv->session_id, g_bytes_unref);
+  g_clear_pointer (&gnutls->priv->session_data, g_bytes_unref);
   g_clear_error (&gnutls->priv->cert_error);
 
   G_OBJECT_CLASS (g_tls_client_connection_gnutls_parent_class)->finalize (object);
@@ -274,6 +277,8 @@ g_tls_client_connection_gnutls_failed (GTlsConnectionGnutls *conn)
 {
   GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (conn);
 
+  gnutls->priv->session_data_override = FALSE;
+  g_clear_pointer (&gnutls->priv->session_data, g_bytes_unref);
   if (gnutls->priv->session_id)
     g_tls_backend_gnutls_remove_session (GNUTLS_CLIENT, gnutls->priv->session_id);
 }
@@ -284,7 +289,13 @@ g_tls_client_connection_gnutls_begin_handshake (GTlsConnectionGnutls *conn)
   GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (conn);
 
   /* Try to get a cached session */
-  if (gnutls->priv->session_id)
+  if (gnutls->priv->session_data_override)
+    {
+      gnutls_session_set_data (g_tls_connection_gnutls_get_session (conn),
+                               g_bytes_get_data (gnutls->priv->session_data, NULL),
+                               g_bytes_get_size (gnutls->priv->session_data));
+    }
+  else if (gnutls->priv->session_id)
     {
       GBytes *session_data;
 
@@ -294,7 +305,8 @@ g_tls_client_connection_gnutls_begin_handshake (GTlsConnectionGnutls *conn)
          gnutls_session_set_data (g_tls_connection_gnutls_get_session (conn),
                                   g_bytes_get_data (session_data, NULL),
                                   g_bytes_get_size (session_data));
-         g_bytes_unref (session_data);
+          g_clear_pointer (&gnutls->priv->session_data, g_bytes_unref);
+          gnutls->priv->session_data = session_data;
        }
     }
 
@@ -306,6 +318,7 @@ g_tls_client_connection_gnutls_finish_handshake (GTlsConnectionGnutls  *conn,
                                                 GError               **inout_error)
 {
   GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (conn);
+  int resumed;
 
   g_assert (inout_error != NULL);
 
@@ -325,33 +338,51 @@ g_tls_client_connection_gnutls_finish_handshake (GTlsConnectionGnutls  *conn,
        }
     }
 
-  if (gnutls->priv->session_id)
+  resumed = gnutls_session_is_resumed (g_tls_connection_gnutls_get_session (conn));
+  if (*inout_error || !resumed)
     {
-      if (!*inout_error)
-       {
-          if (!gnutls_session_is_resumed (g_tls_connection_gnutls_get_session (conn)))
-            {
-              gnutls_datum_t session_datum;
-
-              if (gnutls_session_get_data2 (g_tls_connection_gnutls_get_session (conn),
-                                            &session_datum) == 0)
-                {
-                  GBytes *session_data = g_bytes_new_with_free_func (session_datum.data,
-                                                                     session_datum.size,
-                                                                     (GDestroyNotify)gnutls_free,
-                                                                     session_datum.data);
-
-                  g_tls_backend_gnutls_store_session (GNUTLS_CLIENT,
-                                                      gnutls->priv->session_id,
-                                                      session_data);
-                  g_bytes_unref (session_data);
-                }
-              else
-                g_tls_backend_gnutls_remove_session (GNUTLS_CLIENT, gnutls->priv->session_id);
-            }
-       }
-      else
-       g_tls_backend_gnutls_remove_session (GNUTLS_CLIENT, gnutls->priv->session_id);
+      /* Clear session data since the server did not accept what we provided. */
+      gnutls->priv->session_data_override = FALSE;
+      g_clear_pointer (&gnutls->priv->session_data, g_bytes_unref);
+      if (gnutls->priv->session_id)
+        g_tls_backend_gnutls_remove_session (GNUTLS_CLIENT, gnutls->priv->session_id);
+    }
+
+  if (!*inout_error && !resumed)
+    {
+      gnutls_datum_t session_datum;
+
+      if (gnutls_session_get_data2 (g_tls_connection_gnutls_get_session (conn),
+                                    &session_datum) == 0)
+        {
+          gnutls->priv->session_data = g_bytes_new_with_free_func (session_datum.data,
+                                                                   session_datum.size,
+                                                                   (GDestroyNotify)gnutls_free,
+                                                                   session_datum.data);
+
+          g_tls_backend_gnutls_store_session (GNUTLS_CLIENT,
+                                              gnutls->priv->session_id,
+                                              gnutls->priv->session_data);
+        }
+    }
+}
+
+static void
+g_tls_client_connection_gnutls_copy_session_state (GTlsClientConnection *conn,
+                                                   GTlsClientConnection *source)
+{
+  GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (conn);
+  GTlsClientConnectionGnutls *gnutls_source = G_TLS_CLIENT_CONNECTION_GNUTLS (source);
+
+  if (gnutls_source->priv->session_data)
+    {
+      gnutls->priv->session_data_override = TRUE;
+      gnutls->priv->session_data = g_bytes_ref (gnutls_source->priv->session_data);
+
+      if (gnutls->priv->session_id)
+        g_tls_backend_gnutls_store_session (GNUTLS_CLIENT,
+                                            gnutls->priv->session_id,
+                                            gnutls->priv->session_data);
     }
 }
 
@@ -381,4 +412,5 @@ g_tls_client_connection_gnutls_class_init (GTlsClientConnectionGnutlsClass *klas
 static void
 g_tls_client_connection_gnutls_client_connection_interface_init (GTlsClientConnectionInterface *iface)
 {
+  iface->copy_session_state = g_tls_client_connection_gnutls_copy_session_state;
 }


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