[glib-networking] gnutls: add server-side session cache support
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking] gnutls: add server-side session cache support
- Date: Sat, 3 Dec 2011 18:35:26 +0000 (UTC)
commit 16c9fe1bd6030016730f83c50d747b6ff6fffda9
Author: Dan Winship <danw gnome org>
Date: Sat Dec 3 19:32:01 2011 +0100
gnutls: add server-side session cache support
https://bugzilla.gnome.org/show_bug.cgi?id=636574
configure.ac | 2 +-
tls/gnutls/gtlsbackend-gnutls.c | 99 +++++++++++++++++------------
tls/gnutls/gtlsbackend-gnutls.h | 12 ++--
tls/gnutls/gtlsclientconnection-gnutls.c | 49 +++++++++------
tls/gnutls/gtlsconnection-gnutls.c | 3 +
tls/gnutls/gtlsconnection-gnutls.h | 2 +
tls/gnutls/gtlsserverconnection-gnutls.c | 80 ++++++++++++++++++++++++
7 files changed, 182 insertions(+), 65 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index a408a54..0964b60 100644
--- a/configure.ac
+++ b/configure.ac
@@ -226,7 +226,7 @@ if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then
-Wall -Wstrict-prototypes -Werror=missing-prototypes \
-Werror=implicit-function-declaration \
-Werror=pointer-arith -Werror=init-self -Werror=format=2 \
- -Werror=missing-include-dirs -Werror=aggregate-return \
+ -Werror=missing-include-dirs \
-Werror=declaration-after-statement"
fi
diff --git a/tls/gnutls/gtlsbackend-gnutls.c b/tls/gnutls/gtlsbackend-gnutls.c
index 6db3fec..3597753 100644
--- a/tls/gnutls/gtlsbackend-gnutls.c
+++ b/tls/gnutls/gtlsbackend-gnutls.c
@@ -166,26 +166,26 @@ g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface)
*/
G_LOCK_DEFINE_STATIC (session_cache_lock);
-GHashTable *session_cache;
+GHashTable *client_session_cache, *server_session_cache;
#define SESSION_CACHE_MAX_SIZE 50
#define SESSION_CACHE_MAX_AGE (60 * 60) /* one hour */
typedef struct {
- gchar *session_id;
- GByteArray *session_data;
- time_t last_used;
+ GBytes *session_id;
+ GBytes *session_data;
+ time_t last_used;
} GTlsBackendGnutlsCacheData;
static void
-session_cache_cleanup (void)
+session_cache_cleanup (GHashTable *cache)
{
GHashTableIter iter;
gpointer key, value;
GTlsBackendGnutlsCacheData *cache_data;
time_t expired = time (NULL) - SESSION_CACHE_MAX_AGE;
- g_hash_table_iter_init (&iter, session_cache);
+ g_hash_table_iter_init (&iter, cache);
while (g_hash_table_iter_next (&iter, &key, &value))
{
cache_data = value;
@@ -199,81 +199,98 @@ cache_data_free (gpointer data)
{
GTlsBackendGnutlsCacheData *cache_data = data;
- g_free (cache_data->session_id);
- g_byte_array_unref (cache_data->session_data);
+ g_bytes_unref (cache_data->session_id);
+ g_bytes_unref (cache_data->session_data);
g_slice_free (GTlsBackendGnutlsCacheData, cache_data);
}
+static GHashTable *
+get_session_cache (gnutls_connection_end_t type,
+ gboolean create)
+{
+ GHashTable **cache_p;
+
+ cache_p = (type == GNUTLS_CLIENT) ? &client_session_cache : &server_session_cache;
+ if (!*cache_p && create)
+ {
+ *cache_p = g_hash_table_new_full (g_bytes_hash, g_bytes_equal,
+ NULL, cache_data_free);
+ }
+ return *cache_p;
+}
+
void
-g_tls_backend_gnutls_cache_session_data (const gchar *session_id,
- guchar *session_data,
- gsize session_data_length)
+g_tls_backend_gnutls_store_session (gnutls_connection_end_t type,
+ GBytes *session_id,
+ GBytes *session_data)
{
GTlsBackendGnutlsCacheData *cache_data;
+ GHashTable *cache;
G_LOCK (session_cache_lock);
- if (!session_cache)
- session_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
- NULL, cache_data_free);
-
- cache_data = g_hash_table_lookup (session_cache, session_id);
+ cache = get_session_cache (type, TRUE);
+ cache_data = g_hash_table_lookup (cache, session_id);
if (cache_data)
{
- if (cache_data->session_data->len == session_data_length &&
- memcmp (cache_data->session_data->data,
- session_data, session_data_length) == 0)
+ if (!g_bytes_equal (cache_data->session_data, session_data))
{
- cache_data->last_used = time (NULL);
- G_UNLOCK (session_cache_lock);
- return;
+ g_bytes_unref (cache_data->session_data);
+ cache_data->session_data = g_bytes_ref (session_data);
}
-
- g_byte_array_set_size (cache_data->session_data, 0);
}
else
{
- if (g_hash_table_size (session_cache) >= SESSION_CACHE_MAX_SIZE)
- session_cache_cleanup ();
+ if (g_hash_table_size (cache) >= SESSION_CACHE_MAX_SIZE)
+ session_cache_cleanup (cache);
cache_data = g_slice_new (GTlsBackendGnutlsCacheData);
- cache_data->session_id = g_strdup (session_id);
- cache_data->session_data = g_byte_array_sized_new (session_data_length);
+ cache_data->session_id = g_bytes_ref (session_id);
+ cache_data->session_data = g_bytes_ref (session_data);
- g_hash_table_insert (session_cache, cache_data->session_id, cache_data);
+ g_hash_table_insert (cache, cache_data->session_id, cache_data);
}
-
- g_byte_array_append (cache_data->session_data,
- session_data, session_data_length);
cache_data->last_used = time (NULL);
+
G_UNLOCK (session_cache_lock);
}
void
-g_tls_backend_gnutls_uncache_session_data (const gchar *session_id)
+g_tls_backend_gnutls_remove_session (gnutls_connection_end_t type,
+ GBytes *session_id)
{
+ GHashTable *cache;
+
G_LOCK (session_cache_lock);
- if (session_cache)
- g_hash_table_remove (session_cache, session_id);
+
+ cache = get_session_cache (type, FALSE);
+ if (cache)
+ g_hash_table_remove (cache, session_id);
+
G_UNLOCK (session_cache_lock);
}
-GByteArray *
-g_tls_backend_gnutls_lookup_session_data (const gchar *session_id)
+GBytes *
+g_tls_backend_gnutls_lookup_session (gnutls_connection_end_t type,
+ GBytes *session_id)
{
GTlsBackendGnutlsCacheData *cache_data;
- GByteArray *session_data = NULL;
+ GBytes *session_data = NULL;
+ GHashTable *cache;
G_LOCK (session_cache_lock);
- if (session_cache)
+
+ cache = get_session_cache (type, FALSE);
+ if (cache)
{
- cache_data = g_hash_table_lookup (session_cache, session_id);
+ cache_data = g_hash_table_lookup (cache, session_id);
if (cache_data)
{
cache_data->last_used = time (NULL);
- session_data = g_byte_array_ref (cache_data->session_data);
+ session_data = g_bytes_ref (cache_data->session_data);
}
}
+
G_UNLOCK (session_cache_lock);
return session_data;
diff --git a/tls/gnutls/gtlsbackend-gnutls.h b/tls/gnutls/gtlsbackend-gnutls.h
index 3a75dfe..ceb686a 100644
--- a/tls/gnutls/gtlsbackend-gnutls.h
+++ b/tls/gnutls/gtlsbackend-gnutls.h
@@ -46,11 +46,13 @@ struct _GTlsBackendGnutls
GType g_tls_backend_gnutls_get_type (void) G_GNUC_CONST;
void g_tls_backend_gnutls_register (GIOModule *module);
-void g_tls_backend_gnutls_cache_session_data (const gchar *session_id,
- guchar *session_data,
- gsize session_data_length);
-void g_tls_backend_gnutls_uncache_session_data (const gchar *session_id);
-GByteArray *g_tls_backend_gnutls_lookup_session_data (const gchar *session_id);
+void g_tls_backend_gnutls_store_session (gnutls_connection_end_t type,
+ GBytes *session_id,
+ GBytes *session_data);
+void g_tls_backend_gnutls_remove_session (gnutls_connection_end_t type,
+ GBytes *session_id);
+GBytes *g_tls_backend_gnutls_lookup_session (gnutls_connection_end_t type,
+ GBytes *session_id);
G_END_DECLS
diff --git a/tls/gnutls/gtlsclientconnection-gnutls.c b/tls/gnutls/gtlsclientconnection-gnutls.c
index da435bf..2292d05 100644
--- a/tls/gnutls/gtlsclientconnection-gnutls.c
+++ b/tls/gnutls/gtlsclientconnection-gnutls.c
@@ -58,7 +58,7 @@ struct _GTlsClientConnectionGnutlsPrivate
GSocketConnectable *server_identity;
gboolean use_ssl3;
- char *session_id;
+ GBytes *session_id;
gboolean cert_requested;
GPtrArray *accepted_cas;
@@ -111,17 +111,17 @@ g_tls_client_connection_gnutls_constructed (GObject *object)
{
GInetSocketAddress *isaddr = G_INET_SOCKET_ADDRESS (remote_addr);
const gchar *server_hostname;
- gchar *addrstr;
+ 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 (gnutls);
- gnutls->priv->session_id =
- g_strdup_printf ("%s/%s/%d", addrstr,
- server_hostname ? server_hostname : "",
- port);
+ session_id = g_strdup_printf ("%s/%s/%d", addrstr,
+ server_hostname ? server_hostname : "",
+ port);
+ gnutls->priv->session_id = g_bytes_new_take (session_id, strlen (session_id));
g_free (addrstr);
}
g_object_unref (remote_addr);
@@ -142,7 +142,7 @@ g_tls_client_connection_gnutls_finalize (GObject *object)
if (gnutls->priv->accepted_cas)
g_ptr_array_unref (gnutls->priv->accepted_cas);
if (gnutls->priv->session_id)
- g_free (gnutls->priv->session_id);
+ g_bytes_unref (gnutls->priv->session_id);
G_OBJECT_CLASS (g_tls_client_connection_gnutls_parent_class)->finalize (object);
}
@@ -262,6 +262,15 @@ g_tls_client_connection_gnutls_retrieve_function (gnutls_session_t s
}
static void
+g_tls_client_connection_gnutls_failed (GTlsConnectionGnutls *conn)
+{
+ GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (conn);
+
+ if (gnutls->priv->session_id)
+ g_tls_backend_gnutls_remove_session (GNUTLS_CLIENT, gnutls->priv->session_id);
+}
+
+static void
g_tls_client_connection_gnutls_begin_handshake (GTlsConnectionGnutls *conn)
{
GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (conn);
@@ -269,14 +278,15 @@ g_tls_client_connection_gnutls_begin_handshake (GTlsConnectionGnutls *conn)
/* Try to get a cached session */
if (gnutls->priv->session_id)
{
- GByteArray *session_data;
+ GBytes *session_data;
- session_data = g_tls_backend_gnutls_lookup_session_data (gnutls->priv->session_id);
+ session_data = g_tls_backend_gnutls_lookup_session (GNUTLS_CLIENT, gnutls->priv->session_id);
if (session_data)
{
gnutls_session_set_data (g_tls_connection_gnutls_get_session (conn),
- session_data->data, session_data->len);
- g_byte_array_unref (session_data);
+ g_bytes_get_data (session_data),
+ g_bytes_get_size (session_data));
+ g_bytes_unref (session_data);
}
}
@@ -341,19 +351,21 @@ g_tls_client_connection_gnutls_finish_handshake (GTlsConnectionGnutls *conn,
if (gnutls->priv->session_id)
{
- gnutls_datum session_data;
+ gnutls_datum session_datum;
if (success &&
gnutls_session_get_data2 (g_tls_connection_gnutls_get_session (conn),
- &session_data) == 0)
+ &session_datum) == 0)
{
- g_tls_backend_gnutls_cache_session_data (gnutls->priv->session_id,
- session_data.data,
- session_data.size);
- gnutls_free (session_data.data);
+ 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_uncache_session_data (gnutls->priv->session_id);
+ g_tls_backend_gnutls_remove_session (GNUTLS_CLIENT, gnutls->priv->session_id);
}
}
@@ -370,6 +382,7 @@ g_tls_client_connection_gnutls_class_init (GTlsClientConnectionGnutlsClass *klas
gobject_class->constructed = g_tls_client_connection_gnutls_constructed;
gobject_class->finalize = g_tls_client_connection_gnutls_finalize;
+ connection_gnutls_class->failed = g_tls_client_connection_gnutls_failed;
connection_gnutls_class->begin_handshake = g_tls_client_connection_gnutls_begin_handshake;
connection_gnutls_class->verify_peer = g_tls_client_connection_gnutls_verify_peer;
connection_gnutls_class->finish_handshake = g_tls_client_connection_gnutls_finish_handshake;
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index 36e0df2..f1655d6 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -487,6 +487,8 @@ end_gnutls_io (GTlsConnectionGnutls *gnutls,
{
if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
status = GNUTLS_E_AGAIN;
+ else
+ G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->failed (gnutls);
g_propagate_error (error, gnutls->priv->error);
gnutls->priv->error = NULL;
return status;
@@ -515,6 +517,7 @@ end_gnutls_io (GTlsConnectionGnutls *gnutls,
{
g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_EOF,
_("TLS connection closed unexpectedly"));
+ G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->failed (gnutls);
return status;
}
else
diff --git a/tls/gnutls/gtlsconnection-gnutls.h b/tls/gnutls/gtlsconnection-gnutls.h
index fa4f133..b69eca1 100644
--- a/tls/gnutls/gtlsconnection-gnutls.h
+++ b/tls/gnutls/gtlsconnection-gnutls.h
@@ -33,6 +33,8 @@ struct _GTlsConnectionGnutlsClass
{
GTlsConnectionClass parent_class;
+ void (*failed) (GTlsConnectionGnutls *gnutls);
+
void (*begin_handshake) (GTlsConnectionGnutls *gnutls);
gboolean (*verify_peer) (GTlsConnectionGnutls *gnutls,
GTlsCertificate *peer_certificate,
diff --git a/tls/gnutls/gtlsserverconnection-gnutls.c b/tls/gnutls/gtlsserverconnection-gnutls.c
index 24d9ac2..807895b 100644
--- a/tls/gnutls/gtlsserverconnection-gnutls.c
+++ b/tls/gnutls/gtlsserverconnection-gnutls.c
@@ -25,6 +25,7 @@
#include <gnutls/x509.h>
#include "gtlsserverconnection-gnutls.h"
+#include "gtlsbackend-gnutls.h"
#include "gtlscertificate-gnutls.h"
#include <glib/gi18n-lib.h>
@@ -45,6 +46,14 @@ static int g_tls_server_connection_gnutls_retrieve_function (gnutls_session_t
int pk_algos_length,
gnutls_retr2_st *st);
+static int g_tls_server_connection_gnutls_db_store (void *user_data,
+ gnutls_datum_t key,
+ gnutls_datum_t data);
+static int g_tls_server_connection_gnutls_db_remove (void *user_data,
+ gnutls_datum_t key);
+static gnutls_datum_t g_tls_server_connection_gnutls_db_retrieve (void *user_data,
+ gnutls_datum_t key);
+
static GInitableIface *g_tls_server_connection_gnutls_parent_initable_iface;
G_DEFINE_TYPE_WITH_CODE (GTlsServerConnectionGnutls, g_tls_server_connection_gnutls, G_TYPE_TLS_CONNECTION_GNUTLS,
@@ -63,11 +72,17 @@ static void
g_tls_server_connection_gnutls_init (GTlsServerConnectionGnutls *gnutls)
{
gnutls_certificate_credentials_t creds;
+ gnutls_session_t session;
gnutls->priv = G_TYPE_INSTANCE_GET_PRIVATE (gnutls, G_TYPE_TLS_SERVER_CONNECTION_GNUTLS, GTlsServerConnectionGnutlsPrivate);
creds = g_tls_connection_gnutls_get_credentials (G_TLS_CONNECTION_GNUTLS (gnutls));
gnutls_certificate_set_retrieve_function (creds, g_tls_server_connection_gnutls_retrieve_function);
+
+ session = g_tls_connection_gnutls_get_session (G_TLS_CONNECTION_GNUTLS (gnutls));
+ gnutls_db_set_retrieve_function (session, g_tls_server_connection_gnutls_db_retrieve);
+ gnutls_db_set_store_function (session, g_tls_server_connection_gnutls_db_store);
+ gnutls_db_set_remove_function (session, g_tls_server_connection_gnutls_db_remove);
}
static gboolean
@@ -143,6 +158,12 @@ g_tls_server_connection_gnutls_retrieve_function (gnutls_session_t s
}
static void
+g_tls_server_connection_gnutls_failed (GTlsConnectionGnutls *conn)
+{
+ gnutls_db_remove_session (g_tls_connection_gnutls_get_session (conn));
+}
+
+static void
g_tls_server_connection_gnutls_begin_handshake (GTlsConnectionGnutls *conn)
{
GTlsServerConnectionGnutls *gnutls = G_TLS_SERVER_CONNECTION_GNUTLS (conn);
@@ -206,6 +227,64 @@ g_tls_server_connection_gnutls_finish_handshake (GTlsConnectionGnutls *gnutls,
{
}
+/* Session cache management */
+
+static int
+g_tls_server_connection_gnutls_db_store (void *user_data,
+ gnutls_datum_t key,
+ gnutls_datum_t data)
+{
+ GBytes *session_id, *session_data;
+
+ session_id = g_bytes_new (key.data, key.size);
+ session_data = g_bytes_new (data.data, data.size);
+ g_tls_backend_gnutls_store_session (GNUTLS_SERVER, session_id, session_data);
+ g_bytes_unref (session_id);
+ g_bytes_unref (session_data);
+
+ return 0;
+}
+
+static int
+g_tls_server_connection_gnutls_db_remove (void *user_data,
+ gnutls_datum_t key)
+{
+ GBytes *session_id;
+
+ session_id = g_bytes_new (key.data, key.size);
+ g_tls_backend_gnutls_remove_session (GNUTLS_SERVER, session_id);
+ g_bytes_unref (session_id);
+
+ return 0;
+}
+
+static gnutls_datum_t
+g_tls_server_connection_gnutls_db_retrieve (void *user_data,
+ gnutls_datum_t key)
+{
+ GBytes *session_id, *session_data;
+ gnutls_datum_t data;
+
+ session_id = g_bytes_new (key.data, key.size);
+ session_data = g_tls_backend_gnutls_lookup_session (GNUTLS_SERVER, session_id);
+ g_bytes_unref (session_id);
+
+ if (session_data)
+ {
+ data.size = g_bytes_get_size (session_data);
+ data.data = gnutls_malloc (data.size);
+ memcpy (data.data, g_bytes_get_data (session_data), data.size);
+ g_bytes_unref (session_data);
+ }
+ else
+ {
+ data.size = 0;
+ data.data = NULL;
+ }
+
+ return data;
+}
+
static void
g_tls_server_connection_gnutls_class_init (GTlsServerConnectionGnutlsClass *klass)
{
@@ -217,6 +296,7 @@ g_tls_server_connection_gnutls_class_init (GTlsServerConnectionGnutlsClass *klas
gobject_class->get_property = g_tls_server_connection_gnutls_get_property;
gobject_class->set_property = g_tls_server_connection_gnutls_set_property;
+ connection_gnutls_class->failed = g_tls_server_connection_gnutls_failed;
connection_gnutls_class->begin_handshake = g_tls_server_connection_gnutls_begin_handshake;
connection_gnutls_class->verify_peer = g_tls_server_connection_gnutls_verify_peer;
connection_gnutls_class->finish_handshake = g_tls_server_connection_gnutls_finish_handshake;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]