Browse Source

[mod_gnutls] add memory session database

personal/stbuehler/wip
Stefan Bühler 9 years ago
parent
commit
9a70d79f66
  1. 2
      src/modules/Makefile.am
  2. 48
      src/modules/mod_gnutls.c
  3. 137
      src/modules/ssl-session-db.h

2
src/modules/Makefile.am

@ -5,7 +5,7 @@ common_cflags += $(GTHREAD_CFLAGS) $(LIBEV_CFLAGS) $(LUA_CFLAGS)
common_libs = $(GTHREAD_LIBS) $(LIBEV_LIBS) $(LUA_LIBS)
common_ldflags = -module -export-dynamic -avoid-version -no-undefined $(common_libs)
common_libadd = ../common/liblighttpd2-common.la ../main/liblighttpd2-shared.la
EXTRA_DIST=
EXTRA_DIST=ssl-session-db.h
luadir = $(datarootdir)/lighttpd2/lua

48
src/modules/mod_gnutls.c

@ -3,6 +3,7 @@
#include <lighttpd/throttle.h>
#include "gnutls_filter.h"
#include "ssl-session-db.h"
#include <gnutls/gnutls.h>
#include <glib-2.0/glib/galloca.h>
@ -34,6 +35,8 @@ struct mod_connection_ctx {
struct mod_context {
gint refcount;
liSSLSessionDB *session_db;
gnutls_certificate_credentials_t server_cert;
gnutls_dh_params_t dh_params;
gnutls_priority_t server_priority;
@ -61,6 +64,8 @@ static void mod_gnutls_context_release(mod_context *ctx) {
ctx->ticket_key.size = 0;
}
#endif
li_ssl_session_db_free(ctx->session_db);
ctx->session_db = NULL;
g_slice_free(mod_context, ctx);
}
@ -211,13 +216,36 @@ static int post_client_hello_cb(liGnuTLSFilter *f, gpointer data) {
return GNUTLS_E_SUCCESS;
}
static int session_db_store_cb(void *_sdb, gnutls_datum_t key, gnutls_datum_t data) {
liSSLSessionDB *sdb = _sdb;
li_ssl_session_db_store(sdb, key.data, key.size, data.data, data.size);
return 0;
}
static int session_db_remove_cb(void *_sdb, gnutls_datum_t key) {
liSSLSessionDB *sdb = _sdb;
li_ssl_session_db_remove(sdb, key.data, key.size);
return 0;
}
static gnutls_datum_t session_db_retrieve_cb(void *_sdb, gnutls_datum_t key) {
liSSLSessionDB *sdb = _sdb;
liSSLSessionDBData *data = li_ssl_session_db_lookup(sdb, key.data, key.size);
gnutls_datum_t result = { NULL, 0 };
if (NULL != data) {
result.size = data->size;
result.data = gnutls_malloc(result.size);
memcpy(result.data, data->data, result.size);
li_ssl_session_db_data_release(data);
}
return result;
}
static const liGnuTLSFilterCallbacks filter_callbacks = {
handshake_cb,
close_cb,
post_client_hello_cb
};
static void gnutlc_tcp_finished(liConnection *con, gboolean aborted) {
static void gnutls_tcp_finished(liConnection *con, gboolean aborted) {
mod_connection_ctx *conctx = con->con_sock.data;
UNUSED(aborted);
@ -253,7 +281,7 @@ static liThrottleState* gnutls_tcp_throttle_in(liConnection *con) {
}
static const liConnectionSocketCallbacks gnutls_tcp_cbs = {
gnutlc_tcp_finished,
gnutls_tcp_finished,
gnutls_tcp_throttle_out,
gnutls_tcp_throttle_in
};
@ -285,6 +313,13 @@ static gboolean mod_gnutls_con_new(liConnection *con, int fd) {
goto fail;
}
if (NULL != ctx->session_db) {
gnutls_db_set_ptr(session, ctx->session_db);
gnutls_db_set_remove_function(session, session_db_remove_cb);
gnutls_db_set_retrieve_function(session, session_db_retrieve_cb);
gnutls_db_set_store_function(session, session_db_store_cb);
}
#ifdef HAVE_SESSION_TICKET
if (GNUTLS_E_SUCCESS != (r = gnutls_session_ticket_enable_server(session, &ctx->ticket_key))) {
ERROR(srv, "gnutls_session_ticket_enable_server (%s): %s",
@ -358,6 +393,7 @@ static gboolean gnutls_setup(liServer *srv, liPlugin* p, liValue *val, gpointer
*pemfile = NULL, *ca_file = NULL;
gboolean
protect_against_beast = TRUE;
gint64 session_db_size = 256;
UNUSED(p); UNUSED(userdata);
@ -406,6 +442,12 @@ static gboolean gnutls_setup(liServer *srv, liPlugin* p, liValue *val, gpointer
return FALSE;
}
protect_against_beast = htval->data.boolean;
} else if (g_str_equal(htkey->str, "session-db-size")) {
if (htval->type != LI_VALUE_NUMBER) {
ERROR(srv, "%s", "gnutls session-db-size expects an integer as parameter");
return FALSE;
}
session_db_size = htval->data.number;
}
}
@ -430,6 +472,8 @@ static gboolean gnutls_setup(liServer *srv, liPlugin* p, liValue *val, gpointer
goto error_free_ctx;
}
if (session_db_size > 0) ctx->session_db = li_ssl_session_db_new(session_db_size);
if (NULL != dh_params_file) {
gchar *contents = NULL;
gsize length = 0;

137
src/modules/ssl-session-db.h

@ -0,0 +1,137 @@
#ifndef _LIGHTTPD_SSL_SESSION_DB_H_
#define _LIGHTTPD_SSL_SESSION_DB_H_
#include <lighttpd/base.h>
typedef struct liSSLSessionDBKey liSSLSessionDBKey;
struct liSSLSessionDBKey {
GList keys_link;
size_t size;
unsigned char data[];
};
typedef struct liSSLSessionDBData liSSLSessionDBData;
struct liSSLSessionDBData {
gint refcount;
size_t size;
unsigned char data[];
};
typedef struct liSSLSessionDB liSSLSessionDB;
struct liSSLSessionDB {
size_t max_entries;
GQueue keys; /* move recently added/used entries to end */
GMutex *mutex;
GHashTable *db; /* liSSLSessionDBData -> liSSLSessionDBData */
};
INLINE void li_ssl_session_db_data_release(liSSLSessionDBData *d) {
if (NULL == d) return;
assert(g_atomic_int_get(&d->refcount) > 0);
if (g_atomic_int_dec_and_test(&d->refcount)) {
g_slice_free1(d->size + sizeof(liSSLSessionDBData), d);
}
}
INLINE void li_ssl_session_db_data_free_cb(gpointer data) {
li_ssl_session_db_data_release(data);
}
INLINE liSSLSessionDBData* li_ssl_session_db_data_new(const unsigned char *data, size_t size) {
liSSLSessionDBData *d = g_slice_alloc0(size + sizeof(liSSLSessionDBData));
d->refcount = 1;
d->size = size;
memcpy(d->data, data, size);
return d;
}
INLINE void li_ssl_session_db_key_free_cb(gpointer data) {
liSSLSessionDBKey *d = data;
liSSLSessionDB *sdb;
if (NULL == d) return;
sdb = d->keys_link.data;
if (NULL != sdb) g_queue_unlink(&sdb->keys, &d->keys_link);
g_slice_free1(d->size + sizeof(liSSLSessionDBKey), d);
}
INLINE guint li_ssl_session_db_key_hash(gconstpointer data) {
const liSSLSessionDBKey *d = data;
const GString s = li_const_gstring((const gchar*)d->data, d->size);
return g_string_hash(&s);
}
INLINE gboolean li_ssl_session_db_key_equal(gconstpointer a, gconstpointer b) {
const liSSLSessionDBKey *da = a, *db = b;
if (da->size != db->size) return FALSE;
return 0 == memcmp(da->data, db->data, da->size);
}
INLINE liSSLSessionDBKey* li_ssl_session_db_key_new(const unsigned char *data, size_t size) {
liSSLSessionDBKey *d = g_slice_alloc0(size + sizeof(liSSLSessionDBKey));
d->size = size;
memcpy(d->data, data, size);
return d;
}
INLINE liSSLSessionDB* li_ssl_session_db_new(size_t max_entries) {
liSSLSessionDB *sdb = g_slice_new0(liSSLSessionDB);
sdb->max_entries = max_entries;
sdb->mutex = g_mutex_new();
sdb->db = g_hash_table_new_full(li_ssl_session_db_key_hash, li_ssl_session_db_key_equal,
li_ssl_session_db_key_free_cb, li_ssl_session_db_data_free_cb);
return sdb;
}
INLINE void li_ssl_session_db_free(liSSLSessionDB* sdb) {
if (NULL == sdb) return;
g_mutex_free(sdb->mutex);
sdb->mutex = NULL;
g_hash_table_destroy(sdb->db);
sdb->db = NULL;
g_slice_free(liSSLSessionDB, sdb);
}
INLINE void li_ssl_session_db_store(liSSLSessionDB *sdb, const unsigned char *key, size_t keylen, const unsigned char *value, size_t valuelen) {
liSSLSessionDBData *dvalue = li_ssl_session_db_data_new(value, valuelen);
liSSLSessionDBKey *dkey = li_ssl_session_db_key_new(key, keylen);
g_mutex_lock(sdb->mutex);
dkey->keys_link.data = sdb;
g_queue_push_tail_link(&sdb->keys, &dkey->keys_link);
g_hash_table_replace(sdb->db, dkey, dvalue);
while (sdb->keys.length > sdb->max_entries) {
liSSLSessionDBKey *purge_key = LI_CONTAINER_OF(sdb->keys.head, liSSLSessionDBKey, keys_link);
g_hash_table_remove(sdb->db, purge_key);
}
g_mutex_unlock(sdb->mutex);
}
INLINE liSSLSessionDBData* li_ssl_session_db_lookup(liSSLSessionDB *sdb, const unsigned char *key, size_t keylen) {
liSSLSessionDBData *dvalue = NULL;
liSSLSessionDBKey *dkey = li_ssl_session_db_key_new(key, keylen);
gpointer orig_key, value;
g_mutex_lock(sdb->mutex);
if (g_hash_table_lookup_extended(sdb->db, dkey, &orig_key, &value)) {
liSSLSessionDBKey *k = orig_key;
g_queue_unlink(&sdb->keys, &k->keys_link);
g_queue_push_tail_link(&sdb->keys, &k->keys_link);
dvalue = value;
assert(g_atomic_int_get(&dvalue->refcount) > 0);
g_atomic_int_inc(&dvalue->refcount);
}
g_mutex_unlock(sdb->mutex);
li_ssl_session_db_key_free_cb(dkey);
return dvalue;
}
INLINE void li_ssl_session_db_remove(liSSLSessionDB *sdb, const unsigned char *key, size_t keylen) {
liSSLSessionDBKey *dkey = li_ssl_session_db_key_new(key, keylen);
g_mutex_lock(sdb->mutex);
g_hash_table_remove(sdb->db, dkey);
g_mutex_unlock(sdb->mutex);
li_ssl_session_db_key_free_cb(dkey);
}
#endif
Loading…
Cancel
Save