From fcb122d264414b86ca89dddffba5f839963fc7fa Mon Sep 17 00:00:00 2001 From: Paul Querna Date: Tue, 5 Apr 2005 16:39:18 +0000 Subject: checkpoint the work so far. The DBM cache needs a little more work. --- include/mod_gnutls.h.in | 35 +++--- mod_gnutls.xcode/project.pbxproj | 75 ++++++++++++ src/gnutls_cache.c | 247 ++++++++++++++++++++++++++++++++++++-- src/gnutls_io.c | 61 ++++++---- src/mod_gnutls.c | 250 +++++++++++++++++++++++++++++++-------- 5 files changed, 568 insertions(+), 100 deletions(-) create mode 100644 mod_gnutls.xcode/project.pbxproj diff --git a/include/mod_gnutls.h.in b/include/mod_gnutls.h.in index 469e678..f9ff32b 100644 --- a/include/mod_gnutls.h.in +++ b/include/mod_gnutls.h.in @@ -1,5 +1,5 @@ -/* ==================================================================== - * Copyright 2004 Paul Querna +/** + * Copyright 2004-2005 Paul Querna * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,21 +42,14 @@ module AP_MODULE_DECLARE_DATA gnutls_module; #define GNUTLS_ENABLED_FALSE 0 #define GNUTLS_ENABLED_TRUE 1 - -/** - * GnuTLS changed the names of several structures between 1.0.X and 1.1.X - * This is just a simple hack so we can compile with both versions. - * There is a full list in , But I am just - * doing this for a few types we use. - */ -#ifndef gnutls_certificate_credentials_t -#define gnutls_certificate_credentials_t gnutls_certificate_credentials -#define gnutls_anon_server_credentials_t gnutls_anon_server_credentials -#define gnutls_session_t gnutls_session -#define gnutls_transport_ptr_t gnutls_transport_ptr -#define gnutls_dh_params_t gnutls_dh_params -#define gnutls_rsa_params_t gnutls_rsa_params +typedef enum +{ + mod_gnutls_cache_none, + mod_gnutls_cache_dbm, +#if HAVE_APR_MEMCACHE + mod_gnutls_cache_memcache #endif +} mod_gnutls_cache_e; typedef struct { @@ -70,7 +63,12 @@ typedef struct int macs[16]; int protocol[16]; int compression[16]; + int cert_types[16]; + apr_time_t cache_timeout; + mod_gnutls_cache_e cache_type; const char* cache_config; + const char* rsa_params_file; + const char* dh_params_file; } mod_gnutls_srvconf_rec; typedef struct { @@ -158,6 +156,11 @@ ssize_t mod_gnutls_transport_write(gnutls_transport_ptr_t ptr, const void *buffer, size_t len); +/** + * Init the Cache after Configuration is done + */ +int mod_gnutls_cache_post_config(apr_pool_t *p, server_rec *s, + mod_gnutls_srvconf_rec *sc); /** * Init the Cache inside each Process */ diff --git a/mod_gnutls.xcode/project.pbxproj b/mod_gnutls.xcode/project.pbxproj new file mode 100644 index 0000000..6d79e40 --- /dev/null +++ b/mod_gnutls.xcode/project.pbxproj @@ -0,0 +1,75 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 39; + objects = { + 45B624630802F1E200CBFD9A = { + children = ( + 45B6246D0802F20D00CBFD9A, + 45B6246E0802F20D00CBFD9A, + 45B6246F0802F20D00CBFD9A, + ); + isa = PBXGroup; + refType = 4; + sourceTree = ""; + }; + 45B624650802F1E200CBFD9A = { + buildSettings = { + COPY_PHASE_STRIP = NO; + }; + isa = PBXBuildStyle; + name = Development; + }; + 45B624660802F1E200CBFD9A = { + buildSettings = { + COPY_PHASE_STRIP = YES; + }; + isa = PBXBuildStyle; + name = Deployment; + }; + 45B624670802F1E200CBFD9A = { + buildSettings = { + }; + buildStyles = ( + 45B624650802F1E200CBFD9A, + 45B624660802F1E200CBFD9A, + ); + hasScannedForEncodings = 0; + isa = PBXProject; + mainGroup = 45B624630802F1E200CBFD9A; + projectDirPath = ""; + targets = ( + ); + }; + 45B6246D0802F20D00CBFD9A = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + name = gnutls_cache.c; + path = src/gnutls_cache.c; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + 45B6246E0802F20D00CBFD9A = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + name = gnutls_io.c; + path = src/gnutls_io.c; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + 45B6246F0802F20D00CBFD9A = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.c; + name = mod_gnutls.c; + path = src/mod_gnutls.c; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + }; + rootObject = 45B624670802F1E200CBFD9A; +} diff --git a/src/gnutls_cache.c b/src/gnutls_cache.c index c1a6f37..868568b 100644 --- a/src/gnutls_cache.c +++ b/src/gnutls_cache.c @@ -1,5 +1,5 @@ -/* ==================================================================== - * Copyright 2004 Paul Querna +/** + * Copyright 2004-2005 Paul Querna * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,8 +21,17 @@ #include "apr_memcache.h" #endif +#include "apr_dbm.h" + #include "ap_mpm.h" +#include +#include + +#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) +#include "unixd.h" +#endif + #define GNUTLS_SESSION_ID_STRING_LEN \ ((GNUTLS_MAX_SESSION_ID + 1) * 2) #define MC_TAG "mod_gnutls:" @@ -152,7 +161,7 @@ static int mc_cache_store(void* baton, gnutls_datum_t key, if(!strkey) return -1; - timeout = 3600; + timeout = ctxt->sc->cache_timeout; rv = apr_memcache_set(mc, strkey, data.data, data.size, timeout, 0); @@ -233,25 +242,239 @@ static int mc_cache_delete(void* baton, gnutls_datum_t key) #endif /* have_apr_memcache */ +#define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD ) + +static int dbm_cache_expire(mod_gnutls_handle_t *ctxt) +{ + apr_status_t rv; + apr_dbm_t *dbm; + + rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, + APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, + ctxt->c->base_server, + "[gnutls_cache] error opening cache '%s'", + ctxt->sc->cache_config); + return -1; + } + apr_dbm_close(dbm); + + return 0; +} + +static gnutls_datum_t dbm_cache_fetch(void* baton, gnutls_datum_t key) +{ + gnutls_datum_t data = { NULL, 0 }; + apr_dbm_t *dbm; + apr_datum_t dbmkey; + apr_datum_t dbmval; + mod_gnutls_handle_t *ctxt = baton; + apr_status_t rv; + + dbmkey.dptr = key.data; + dbmkey.dsize = key.size; + + rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, + APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, + ctxt->c->base_server, + "[gnutls_cache] error opening cache '%s'", + ctxt->sc->cache_config); + return data; + } + + rv = apr_dbm_fetch(dbm, dbmkey, &dbmval); + + if (rv != APR_SUCCESS) { + apr_dbm_close(dbm); + return data; + } + + if (dbmval.dptr == NULL || dbmval.dsize <= sizeof(apr_time_t)) { + apr_dbm_close(dbm); + return data; + } + + data.data = gnutls_malloc(dbmval.dsize - sizeof(apr_time_t)); + if (data.data == NULL) + return data; + + data.size = dbmval.dsize - sizeof(apr_time_t); + memcpy(data.data, dbmval.dptr+sizeof(apr_time_t), data.size); + + apr_dbm_close(dbm); + return data; +} + +static int dbm_cache_store(void* baton, gnutls_datum_t key, + gnutls_datum_t data) +{ + apr_dbm_t *dbm; + apr_datum_t dbmkey; + apr_datum_t dbmval; + mod_gnutls_handle_t *ctxt = baton; + apr_status_t rv; + apr_time_t timeout; + + dbmkey.dptr = (char *)key.data; + dbmkey.dsize = key.size; + + /* create DBM value */ + dbmval.dsize = data.size; + dbmval.dptr = (char *)malloc(dbmval.dsize+sizeof(apr_time_t)); + + memcpy((char *)dbmval.dptr+sizeof(apr_time_t), + data.data, data.size); + + rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, + APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, + ctxt->c->base_server, + "[gnutls_cache] error opening cache '%s'", + ctxt->sc->cache_config); + free(dbmval.dptr); + return -1; + } + + rv = apr_dbm_store(dbm, dbmkey, dbmval); + + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, + ctxt->c->base_server, + "[gnutls_cache] error storing in cache '%s'", + ctxt->sc->cache_config); + apr_dbm_close(dbm); + free(dbmval.dptr); + return -1; + } + + apr_dbm_close(dbm); + + free(dbmval.dptr); + + return 0; +} + +static int dbm_cache_delete(void* baton, gnutls_datum_t key) +{ + apr_dbm_t *dbm; + apr_datum_t dbmkey; + mod_gnutls_handle_t *ctxt = baton; + apr_status_t rv; + + dbmkey.dptr = (char *)key.data; + dbmkey.dsize = key.size; + + rv = apr_dbm_open(&dbm, ctxt->sc->cache_config, + APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, ctxt->c->pool); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, + ctxt->c->base_server, + "[gnutls_cache] error opening cache '%s'", + ctxt->sc->cache_config); + return -1; + } + + rv = apr_dbm_delete(dbm, dbmkey); + + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, + ctxt->c->base_server, + "[gnutls_cache] error storing in cache '%s'", + ctxt->sc->cache_config); + apr_dbm_close(dbm); + return -1; + } + + apr_dbm_close(dbm); + + return 0; +} + +static int dbm_cache_child_init(apr_pool_t *p, server_rec *s, + mod_gnutls_srvconf_rec *sc) +{ + apr_status_t rv; + apr_dbm_t *dbm; + const char* path1; + const char* path2; + + rv = apr_dbm_open(&dbm, sc->cache_config, APR_DBM_RWCREATE, + SSL_DBM_FILE_MODE, p); + + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, + "GnuTLS: Cannot create DBM Cache at `%s'", + sc->cache_config); + return rv; + } + + apr_dbm_close(dbm); + + apr_dbm_get_usednames(p, sc->cache_config, &path1, &path2); + + /* The Following Code takes logic directly from mod_ssl's DBM Cache */ +#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) + /* Running as Root */ + if (geteuid() == 0) { + chown(path1, unixd_config.user_id, -1); + if (path2 != NULL) { + chown(path2, unixd_config.user_id, -1); + } + } +#endif + + return rv; +} + +int mod_gnutls_cache_post_config(apr_pool_t *p, server_rec *s, + mod_gnutls_srvconf_rec *sc) +{ + if (sc->cache_type == mod_gnutls_cache_dbm) { + return dbm_cache_child_init(p, s, sc); + } + return 0; +} + int mod_gnutls_cache_child_init(apr_pool_t *p, server_rec *s, mod_gnutls_srvconf_rec *sc) { + if (sc->cache_type == mod_gnutls_cache_dbm) { + return 0; + } #if HAVE_APR_MEMCACHE - return mc_cache_child_init(p, s, sc); -#else - return 0; + else if (sc->cache_type == mod_gnutls_cache_memcache) { + return mc_cache_child_init(p, s, sc); + } #endif + return 0; } + #include + int mod_gnutls_cache_session_init(mod_gnutls_handle_t *ctxt) { + printf("Type: %d Params: %s\n",ctxt->sc->cache_type, ctxt->sc->cache_config); + if (ctxt->sc->cache_type == mod_gnutls_cache_dbm) { + gnutls_db_set_retrieve_function(ctxt->session, dbm_cache_fetch); + gnutls_db_set_remove_function(ctxt->session, dbm_cache_delete); + gnutls_db_set_store_function(ctxt->session, dbm_cache_store); + gnutls_db_set_ptr(ctxt->session, ctxt); + } #if HAVE_APR_MEMCACHE - gnutls_db_set_retrieve_function(ctxt->session, mc_cache_fetch); - gnutls_db_set_remove_function(ctxt->session, mc_cache_delete); - gnutls_db_set_store_function(ctxt->session, mc_cache_store); - gnutls_db_set_ptr(ctxt->session, ctxt); -#else - /* TODO: Alternative Cache Backends */ + else if (ctxt->sc->cache_type == mod_gnutls_cache_memcache) { + gnutls_db_set_retrieve_function(ctxt->session, mc_cache_fetch); + gnutls_db_set_remove_function(ctxt->session, mc_cache_delete); + gnutls_db_set_store_function(ctxt->session, mc_cache_store); + gnutls_db_set_ptr(ctxt->session, ctxt); + } #endif + else { + assert(1); + /* No Session Cache is Available. Opps. */ + } return 0; } diff --git a/src/gnutls_io.c b/src/gnutls_io.c index e92646b..a44ba9c 100644 --- a/src/gnutls_io.c +++ b/src/gnutls_io.c @@ -1,5 +1,5 @@ -/* ==================================================================== - * Copyright 2004 Paul Querna +/** + * Copyright 2004-2005 Paul Querna * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -342,33 +342,46 @@ static void gnutls_do_handshake(mod_gnutls_handle_t * ctxt) { int ret; - if (ctxt->status != 0) + if (ctxt->status != 0) { return; - ret = gnutls_handshake(ctxt->session); - if (ret < 0) { - if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED - || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) { - ret = gnutls_alert_get(ctxt->session); - ap_log_error(APLOG_MARK, APLOG_ERR, 0, ctxt->c->base_server, - "GnuTLS: Hanshake Alert (%d) '%s'.\n", ret, - gnutls_alert_get_name(ret)); - } - - gnutls_deinit(ctxt->session); + } + +tryagain: + + ret = gnutls_handshake(ctxt->session); + if (ret < 0) { + if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED + || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) { + ret = gnutls_alert_get(ctxt->session); ap_log_error(APLOG_MARK, APLOG_ERR, 0, ctxt->c->base_server, - "GnuTLS: Handshake Failed (%d) '%s'", ret, - gnutls_strerror(ret)); - ctxt->status = -1; - return; + "GnuTLS: Hanshake Alert (%d) '%s'.\n", ret, + gnutls_alert_get_name(ret)); } - else { - ctxt->status = 1; - return; /* all done with the handshake */ + + if (!gnutls_error_is_fatal(ret)) { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, ctxt->c->base_server, + "GnuTLS: Non-Fatal Handshake Error: (%d) '%s'", ret, + gnutls_strerror(ret)); + goto tryagain; } + + ap_log_error(APLOG_MARK, APLOG_ERR, 0, ctxt->c->base_server, + "GnuTLS: Handshake Failed (%d) '%s'", ret, + gnutls_strerror(ret)); + ctxt->status = -1; + gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL, + gnutls_error_to_alert(ret, NULL)); + gnutls_deinit(ctxt->session); + return; + } + else { + ctxt->status = 1; + return; /* all done with the handshake */ + } } -apr_status_t mod_gnutls_filter_input(ap_filter_t * f, +apr_status_t mod_gnutls_filter_input(ap_filter_t* f, apr_bucket_brigade * bb, ap_input_mode_t mode, apr_read_type_e block, @@ -455,7 +468,7 @@ apr_status_t mod_gnutls_filter_output(ap_filter_t * f, while (!APR_BRIGADE_EMPTY(bb)) { apr_bucket *bucket = APR_BRIGADE_FIRST(bb); - if (APR_BUCKET_IS_EOS(bucket) || AP_BUCKET_IS_EOC(bucket)) { + if (AP_BUCKET_IS_EOC(bucket)) { gnutls_bye(ctxt->session, GNUTLS_SHUT_WR); gnutls_deinit(ctxt->session); @@ -465,7 +478,7 @@ apr_status_t mod_gnutls_filter_output(ap_filter_t * f, } break; - } else if (APR_BUCKET_IS_FLUSH(bucket)) { + } else if (APR_BUCKET_IS_FLUSH(bucket) || APR_BUCKET_IS_EOS(bucket)) { if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) { return status; diff --git a/src/mod_gnutls.c b/src/mod_gnutls.c index a1668f3..edf7068 100644 --- a/src/mod_gnutls.c +++ b/src/mod_gnutls.c @@ -1,5 +1,5 @@ -/* ==================================================================== - * Copyright 2004 Paul Querna +/** + * Copyright 2004-2005 Paul Querna * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,17 +21,25 @@ GCRY_THREAD_OPTION_PTHREAD_IMPL; #endif +static apr_file_t* debug_log_fp; + static apr_status_t mod_gnutls_cleanup_pre_config(void *data) { gnutls_global_deinit(); return APR_SUCCESS; } +static void gnutls_debug_log_all( int level, const char* str) +{ + apr_file_printf(debug_log_fp, "<%d> %s\n", level, str); +} + static int mod_gnutls_hook_pre_config(apr_pool_t * pconf, apr_pool_t * plog, apr_pool_t * ptemp) { #if APR_HAS_THREADS + /* TODO: Check MPM Type here */ gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); #endif @@ -40,25 +48,68 @@ static int mod_gnutls_hook_pre_config(apr_pool_t * pconf, apr_pool_cleanup_register(pconf, NULL, mod_gnutls_cleanup_pre_config, apr_pool_cleanup_null); + apr_file_open(&debug_log_fp, "/tmp/gnutls_debug", + APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, pconf); + + gnutls_global_set_log_level(9); + gnutls_global_set_log_function(gnutls_debug_log_all); + return OK; } -#define DH_BITS 1024 -#ifdef USE_RSA -#define RSA_BITS 512 -#endif + +static gnutls_datum load_params(const char* file, server_rec* s, + apr_pool_t* pool) +{ + gnutls_datum ret = { NULL, 0 }; + apr_file_t* fp; + apr_finfo_t finfo; + apr_status_t rv; + apr_size_t br = 0; + + rv = apr_file_open(&fp, file, APR_READ|APR_BINARY, APR_OS_DEFAULT, + pool); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, + "GnuTLS failed to load params file at: %s", file); + return ret; + } + + rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp); + + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, + "GnuTLS failed to stat params file at: %s", file); + return ret; + } + + ret.data = apr_palloc(pool, finfo.size+1); + rv = apr_file_read_full(fp, ret.data, finfo.size, &br); + + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, + "GnuTLS failed to read params file at: %s", file); + return ret; + } + + ret.data[br] = '\0'; + ret.size = br; + + return ret; +} + static int mod_gnutls_hook_post_config(apr_pool_t * p, apr_pool_t * plog, apr_pool_t * ptemp, server_rec * base_server) { - mod_gnutls_srvconf_rec *sc; - void *data = NULL; - int first_run = 0; + int rv; server_rec *s; gnutls_dh_params_t dh_params; -#ifdef USE_RSA gnutls_rsa_params_t rsa_params; -#endif + mod_gnutls_srvconf_rec *sc; + mod_gnutls_srvconf_rec *sc_base; + void *data = NULL; + int first_run = 0; const char *userdata_key = "mod_gnutls_init"; apr_pool_userdata_get(&data, userdata_key, base_server->process->pool); @@ -70,35 +121,98 @@ static int mod_gnutls_hook_post_config(apr_pool_t * p, apr_pool_t * plog, } -// if(first_run) { - /* TODO: Should we regenerate these after X requests / X time ? */ + if (!first_run) { + gnutls_datum pdata; + apr_pool_t* tpool; + s = base_server; + sc_base = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config, + &gnutls_module); + + apr_pool_create(&tpool, p); + gnutls_dh_params_init(&dh_params); - gnutls_dh_params_generate2(dh_params, DH_BITS); -#ifdef USE_RSA + + pdata = load_params(sc_base->dh_params_file, s, tpool); + + if (pdata.size != 0) { + rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata, + GNUTLS_X509_FMT_PEM); + if (rv != 0) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, + "GnuTLS: Unable to load DH Params: (%d) %s", + rv, gnutls_strerror(rv)); + exit(rv); + } + } + else { + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, + "GnuTLS: Unable to load DH Params." + " Shutting Down."); + exit(-1); + } + apr_pool_clear(tpool); + gnutls_rsa_params_init(&rsa_params); - gnutls_rsa_params_generate2(rsa_params, RSA_BITS); -#endif -// } - for (s = base_server; s; s = s->next) { - sc = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config, - &gnutls_module); - if (sc->cert_file != NULL && sc->key_file != NULL) { - gnutls_certificate_set_x509_key_file(sc->certs, sc->cert_file, + pdata = load_params(sc_base->rsa_params_file, s, tpool); + + if (pdata.size != 0) { + rv = gnutls_rsa_params_import_pkcs1(rsa_params, &pdata, + GNUTLS_X509_FMT_PEM); + if (rv != 0) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, + "GnuTLS: Unable to load RSA Params: (%d) %s", + rv, gnutls_strerror(rv)); + exit(rv); + } + } + else { + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, + "GnuTLS: Unable to load RSA Params." + " Shutting Down."); + exit(-1); + } + + apr_pool_destroy(tpool); + rv = mod_gnutls_cache_post_config(p, s, sc_base); + if (rv != 0) { + ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, + "GnuTLS: Post Config for GnuTLSCache Failed." + " Shutting Down."); + exit(-1); + } + + for (s = base_server; s; s = s->next) { + sc = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config, + &gnutls_module); + sc->cache_type = sc_base->cache_type; + sc->cache_config = sc_base->cache_config; + + if (sc->cert_file != NULL && sc->key_file != NULL) { + rv = gnutls_certificate_set_x509_key_file(sc->certs, sc->cert_file, sc->key_file, GNUTLS_X509_FMT_PEM); -#ifdef USE_RSA - gnutls_certificate_set_rsa_export_params(sc->certs, rsa_params); -#endif - gnutls_certificate_set_dh_params(sc->certs, dh_params); - } - else if (sc->enabled == GNUTLS_ENABLED_TRUE) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, - "[GnuTLS] - Host '%s:%d' is missing a Cert and Key File!", + if (rv != 0) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, + "[GnuTLS] - Host '%s:%d' has an invalid key or certificate:" + "(%s,%s) (%d) %s", + s->server_hostname, s->port, sc->cert_file, sc->key_file, + rv, gnutls_strerror(rv)); + } + else { + gnutls_certificate_set_rsa_export_params(sc->certs, + rsa_params); + gnutls_certificate_set_dh_params(sc->certs, dh_params); + } + } + else if (sc->enabled == GNUTLS_ENABLED_TRUE) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, + "[GnuTLS] - Host '%s:%d' is missing a " + "Cert and Key File!", s->server_hostname, s->port); + } } - } - + } /* first_run */ ap_add_version_component(p, "GnuTLS/" LIBGNUTLS_VERSION); @@ -111,7 +225,7 @@ static void mod_gnutls_hook_child_init(apr_pool_t *p, server_rec *s) mod_gnutls_srvconf_rec *sc = ap_get_module_config(s->module_config, &gnutls_module); - if(sc->cache_config != NULL) { + if (sc->cache_type != mod_gnutls_cache_none) { rv = mod_gnutls_cache_child_init(p, s, sc); if(rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, @@ -119,8 +233,8 @@ static void mod_gnutls_hook_child_init(apr_pool_t *p, server_rec *s) } } else { - ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, - "[GnuTLS] - No Cache Configured. Hint: GnuTLSCache"); + ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, + "[GnuTLS] - No Cache Configured. Hint: GnuTLSCache"); } } @@ -176,21 +290,21 @@ static mod_gnutls_handle_t* create_gnutls_handle(apr_pool_t* pool, conn_rec * c) gnutls_init(&ctxt->session, GNUTLS_SERVER); + gnutls_protocol_set_priority(ctxt->session, sc->protocol); gnutls_cipher_set_priority(ctxt->session, sc->ciphers); gnutls_compression_set_priority(ctxt->session, sc->compression); gnutls_kx_set_priority(ctxt->session, sc->key_exchange); - gnutls_protocol_set_priority(ctxt->session, sc->protocol); gnutls_mac_set_priority(ctxt->session, sc->macs); + gnutls_certificate_type_set_priority(ctxt->session, sc->cert_types); gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE, sc->certs); + // if(anon) { // gnutls_credentials_set(ctxt->session, GNUTLS_CRD_ANON, sc->anoncred); // } gnutls_certificate_server_set_request(ctxt->session, GNUTLS_CERT_IGNORE); - gnutls_dh_set_prime_bits(ctxt->session, DH_BITS); - mod_gnutls_cache_session_init(ctxt); return ctxt; } @@ -216,8 +330,11 @@ static int mod_gnutls_hook_pre_connection(conn_rec * c, void *csd) gnutls_transport_set_push_function(ctxt->session, mod_gnutls_transport_write); gnutls_transport_set_ptr(ctxt->session, ctxt); - ctxt->input_filter = ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c); - ctxt->output_filter = ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c); + + ctxt->input_filter = ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, + NULL, c); + ctxt->output_filter = ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, + NULL, c); return OK; } @@ -233,6 +350,7 @@ static int mod_gnutls_hook_fixups(request_rec *r) if(!ctxt) { return DECLINED; } + apr_table_setn(env, "HTTPS", "on"); apr_table_setn(env, "SSL_PROTOCOL", gnutls_protocol_get_name(gnutls_protocol_get_version(ctxt->session))); @@ -271,7 +389,7 @@ static const char *gnutls_set_key_file(cmd_parms * parms, void *dummy, } static const char *gnutls_set_cache(cmd_parms * parms, void *dummy, - const char *arg) + const char *type, const char* arg) { const char* err; mod_gnutls_srvconf_rec *sc = ap_get_module_config(parms->server-> @@ -281,7 +399,28 @@ static const char *gnutls_set_cache(cmd_parms * parms, void *dummy, return err; } - sc->cache_config = apr_pstrdup(parms->pool, arg); + if (strcasecmp("none", type) == 0) { + sc->cache_type = mod_gnutls_cache_none; + } + else if (strcasecmp("dbm", type) == 0) { + sc->cache_type = mod_gnutls_cache_dbm; + } +#if HAVE_APR_MEMCACHE + else if (strcasecmp("memcache", type) == 0) { + sc->cache_type = mod_gnutls_cache_memcache; + } +#endif + else { + return "Invalid Type for GnuTLSCache!"; + } + + if (sc->cache_type == mod_gnutls_cache_dbm) { + sc->cache_config = ap_server_root_relative(parms->pool, arg); + } + else { + sc->cache_config = apr_pstrdup(parms->pool, arg); + } + return NULL; } @@ -314,10 +453,10 @@ static const command_rec gnutls_cmds[] = { NULL, RSRC_CONF, "SSL Server Certificate file"), - AP_INIT_TAKE1("GnuTLSCache", gnutls_set_cache, + AP_INIT_TAKE2("GnuTLSCache", gnutls_set_cache, NULL, RSRC_CONF, - "SSL Server Certificate file"), + "Cache Configuration"), AP_INIT_TAKE1("GnuTLSEnable", gnutls_set_enabled, NULL, RSRC_CONF, "Whether this server has GnuTLS Enabled. Default: Off"), @@ -372,8 +511,16 @@ static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s) gnutls_anon_allocate_server_credentials(&sc->anoncred); sc->key_file = NULL; sc->cert_file = NULL; - sc->cache_config = NULL; + sc->cache_timeout = apr_time_from_sec(3600); + sc->cache_type = mod_gnutls_cache_dbm; + sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache"); + + /* TODO: Make this Configurable ! */ + sc->dh_params_file = ap_server_root_relative(p, "conf/dhfile"); + sc->rsa_params_file = ap_server_root_relative(p, "conf/rsafile"); + /* TODO: Make this Configurable ! */ + /* meh. mod_ssl uses a flex based parser for this part.. sigh */ i = 0; sc->ciphers[i++] = GNUTLS_CIPHER_AES_256_CBC; sc->ciphers[i++] = GNUTLS_CIPHER_AES_128_CBC; @@ -383,11 +530,14 @@ static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s) sc->ciphers[i] = 0; i = 0; - sc->key_exchange[i++] = GNUTLS_KX_DHE_DSS; sc->key_exchange[i++] = GNUTLS_KX_RSA; - sc->key_exchange[i++] = GNUTLS_KX_DHE_RSA; sc->key_exchange[i++] = GNUTLS_KX_RSA_EXPORT; sc->key_exchange[i++] = GNUTLS_KX_DHE_DSS; + sc->key_exchange[i++] = GNUTLS_KX_DHE_RSA; + sc->key_exchange[i++] = GNUTLS_KX_ANON_DH; + sc->key_exchange[i++] = GNUTLS_KX_SRP; + sc->key_exchange[i++] = GNUTLS_KX_SRP_RSA; + sc->key_exchange[i++] = GNUTLS_KX_SRP_DSS; sc->key_exchange[i] = 0; i = 0; @@ -408,6 +558,10 @@ static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s) sc->compression[i++] = GNUTLS_COMP_LZO; sc->compression[i] = 0; + i = 0; + sc->cert_types[i++] = GNUTLS_CRT_X509; + sc->cert_types[i] = 0; + return sc; } -- cgit