summaryrefslogtreecommitdiffstatsabout
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/gnutls_cache.c206
-rw-r--r--src/gnutls_io.c30
-rw-r--r--src/mod_gnutls.c46
4 files changed, 244 insertions, 40 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 05d2fab..1f1860b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,7 +2,7 @@ CLEANFILES = .libs/libmod_gnutls *~
2 2
3libmod_gnutls_la_SOURCES = mod_gnutls.c gnutls_io.c gnutls_cache.c 3libmod_gnutls_la_SOURCES = mod_gnutls.c gnutls_io.c gnutls_cache.c
4libmod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS} 4libmod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS}
5libmod_gnutls_la_LDFLAGS = ${MODULE_LIBS} 5libmod_gnutls_la_LDFLAGS = -rpath ${AP_LIBEXECDIR} -module -avoid-version ${MODULE_LIBS}
6 6
7lib_LTLIBRARIES = libmod_gnutls.la 7lib_LTLIBRARIES = libmod_gnutls.la
8 8
diff --git a/src/gnutls_cache.c b/src/gnutls_cache.c
index 683cdf4..bc13440 100644
--- a/src/gnutls_cache.c
+++ b/src/gnutls_cache.c
@@ -16,46 +16,212 @@
16 */ 16 */
17 17
18#include "mod_gnutls.h" 18#include "mod_gnutls.h"
19#include "ap_mpm.h"
19 20
20/** 21/**
21 * GnuTLS Session Cache using libmemcached 22 * GnuTLS Session Cache using libmemcached
22 * 23 *
23 */ 24 */
24/*
25#include "memcache.h"
26 25
27int mod_gnutls_cache_init() 26/* The underlying apr_memcache system is thread safe... woohoo */
27static apr_memcache_t* mc;
28
29int mod_gnutls_cache_child_init(apr_pool_t *p, server_rec *s,
30 mod_gnutls_srvconf_rec *sc)
28{ 31{
29 return 0; 32 apr_status_t rv = APR_SUCCESS;
33 int thread_limit = 0;
34 int nservers = 0;
35 char* cache_config;
36 char* split;
37 char* tok;
38
39 ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
40
41 /* Find all the servers in the first run to get a total count */
42 cache_config = apr_pstrdup(p, sc->cache_config);
43 split = apr_strtok(cache_config, " ", &tok);
44 while (split) {
45 nservers++;
46 split = apr_strtok(NULL," ", &tok);
47 }
48
49 rv = apr_memcache_create(p, nservers, 0, &mc);
50 if (rv != APR_SUCCESS) {
51 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
52 "[gnutls_cache] Failed to create Memcache Object of '%d' size.",
53 nservers);
54 return rv;
55 }
56
57 /* Now add each server to the memcache */
58 cache_config = apr_pstrdup(p, sc->cache_config);
59 split = apr_strtok(cache_config, " ", &tok);
60 while (split) {
61 apr_memcache_server_t* st;
62 char* split2;
63 char* host_str;
64 char* port_str;
65 int port;
66
67 host_str = apr_strtok(split,":", &split2);
68 port_str = apr_strtok(NULL,":", &split2);
69 if (!port_str) {
70 port = 11211; /* default port */
71 }
72 else {
73 port = atoi(port_str);
74 }
75
76 /* Should Max Conns be (thread_limit / nservers) ? */
77 rv = apr_memcache_server_create(p,
78 host_str, port,
79 0,
80 1,
81 thread_limit,
82 600,
83 &st);
84 if(rv != APR_SUCCESS) {
85 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
86 "[gnutls_cache] Failed to Create Server: %s:%d",
87 host_str, port);
88 return rv;
89 }
90
91 rv = apr_memcache_add_server(mc, st);
92 if(rv != APR_SUCCESS) {
93 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
94 "[gnutls_cache] Failed to Add Server: %s:%d",
95 host_str, port);
96 return rv;
97 }
98
99 split = apr_strtok(NULL," ", &tok);
100 }
101 return rv;
30} 102}
31static int cache_store((void* baton, gnutls_datum_t key, gnutls_datum_t data) 103
104/* thanks mod_ssl */
105#define GNUTLS_SESSION_ID_STRING_LEN \
106 ((GNUTLS_MAX_SESSION_ID + 1) * 2)
107#define MC_TAG "mod_gnutls:"
108#define MC_TAG_LEN \
109 (sizeof(MC_TAG))
110#define STR_SESSION_LEN (GNUTLS_SESSION_ID_STRING_LEN + MC_TAG_LEN)
111
112
113static char *gnutls_session_id2sz(unsigned char *id, int idlen,
114 char *str, int strsize)
32{ 115{
33 mc_set(struct memcache *mc, 116 char *cp;
34 key->data, key->size, 117 int n;
35 data->data, data->size, 118
36 3600, 0); 119 cp = apr_cpystrn(str, MC_TAG, MC_TAG_LEN);
37 return 0; 120 for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) {
121 apr_snprintf(cp, strsize - (cp-str), "%02X", id[n]);
122 cp += 2;
123 }
124 *cp = '\0';
125 return str;
38} 126}
39 127
40static int cache_fetch(void* baton, gnutls_datum_t key) 128
129static int cache_store(void* baton, gnutls_datum_t key, gnutls_datum_t data)
41{ 130{
131 apr_status_t rv = APR_SUCCESS;
42 mod_gnutls_handle_t *ctxt = baton; 132 mod_gnutls_handle_t *ctxt = baton;
43 return 0; 133 char buf[STR_SESSION_LEN];
134 char* strkey = NULL;
135 apr_uint32_t timeout;
136
137 strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf));
138 if(!strkey)
139 return -1;
140
141 timeout = 3600;
142
143 rv = apr_memcache_set(mc, strkey, data.data, data.size, timeout, 0);
144
145 if(rv != APR_SUCCESS) {
146 ap_log_error(APLOG_MARK, APLOG_CRIT, rv,
147 ctxt->c->base_server,
148 "[gnutls_cache] error setting key '%s' "
149 "with %d bytes of data", strkey, data.size);
150 return -1;
151 }
152
153 return 0;
154}
155
156static gnutls_datum_t cache_fetch(void* baton, gnutls_datum_t key)
157{
158 apr_status_t rv = APR_SUCCESS;
159 mod_gnutls_handle_t *ctxt = baton;
160 char buf[STR_SESSION_LEN];
161 char* strkey = NULL;
162 char* value;
163 apr_size_t value_len;
164 gnutls_datum_t data = { NULL, 0 };
165
166 strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf));
167 if(!strkey) {
168 return data;
169 }
170
171 rv = apr_memcache_getp(mc, ctxt->c->pool, strkey,
172 &value, &value_len, NULL);
173
174 if(rv != APR_SUCCESS) {
175 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
176 ctxt->c->base_server,
177 "[gnutls_cache] error fetching key '%s' ",
178 strkey);
179
180 data.size = 0;
181 data.data = NULL;
182 return data;
183 }
184
185 /* TODO: Eliminate this memcpy. ffs. gnutls-- */
186 data.data = gnutls_malloc(value_len);
187 if (data.data == NULL)
188 return data;
189
190 data.size = value_len;
191 memcpy(data.data, value, value_len);
192
193 return data;
44} 194}
45 195
46static int cache_delete(void* baton, gnutls_datum_t key) 196static int cache_delete(void* baton, gnutls_datum_t key)
47{ 197{
198 apr_status_t rv = APR_SUCCESS;
48 mod_gnutls_handle_t *ctxt = baton; 199 mod_gnutls_handle_t *ctxt = baton;
49 return 0; 200 char buf[STR_SESSION_LEN];
201 char* strkey = NULL;
202
203 strkey = gnutls_session_id2sz(key.data, key.size, buf, sizeof(buf));
204 if(!strkey)
205 return -1;
206
207 rv = apr_memcache_delete(mc, strkey, 0);
208
209 if(rv != APR_SUCCESS) {
210 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
211 ctxt->c->base_server,
212 "[gnutls_cache] error deleting key '%s' ",
213 strkey);
214 return -1;
215 }
216
217 return 0;
50} 218}
51 219
52int mod_gnutls_cache_session_init(mod_gnutls_handle_t *ctxt) 220int mod_gnutls_cache_session_init(mod_gnutls_handle_t *ctxt)
53{ 221{
54 gnutls_db_set_cache_expiration 222 gnutls_db_set_retrieve_function(ctxt->session, cache_fetch);
55 gnutls_db_set_retrieve_function(session, cache_fetch); 223 gnutls_db_set_remove_function(ctxt->session, cache_delete);
56 gnutls_db_set_remove_function(session, cache_delete); 224 gnutls_db_set_store_function(ctxt->session, cache_store);
57 gnutls_db_set_store_function(session, cache_store); 225 gnutls_db_set_ptr(ctxt->session, ctxt);
58 gnutls_db_set_ptr(session, NULL); 226 return 0;
59 return 0;
60} 227}
61*/
diff --git a/src/gnutls_io.c b/src/gnutls_io.c
index e1c84be..e92646b 100644
--- a/src/gnutls_io.c
+++ b/src/gnutls_io.c
@@ -273,10 +273,16 @@ static apr_status_t gnutls_io_input_read(mod_gnutls_handle_t * ctxt,
273 } 273 }
274 else { 274 else {
275 /* Some Other Error. Report it. Die. */ 275 /* Some Other Error. Report it. Die. */
276 ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->input_rc, 276 if(gnutls_error_is_fatal(rc)) {
277 ctxt->c->base_server, 277 ap_log_error(APLOG_MARK, APLOG_INFO, ctxt->input_rc,
278 "GnuTLS: Error reading data. (%d) '%s'", rc, 278 ctxt->c->base_server,
279 gnutls_strerror(rc)); 279 "GnuTLS: Error reading data. (%d) '%s'", rc,
280 gnutls_strerror(rc));
281 }
282 else if(*len > 0) {
283 ctxt->input_rc = APR_SUCCESS;
284 break;
285 }
280 } 286 }
281 287
282 if (ctxt->input_rc == APR_SUCCESS) { 288 if (ctxt->input_rc == APR_SUCCESS) {
@@ -449,9 +455,10 @@ apr_status_t mod_gnutls_filter_output(ap_filter_t * f,
449 455
450 while (!APR_BRIGADE_EMPTY(bb)) { 456 while (!APR_BRIGADE_EMPTY(bb)) {
451 apr_bucket *bucket = APR_BRIGADE_FIRST(bb); 457 apr_bucket *bucket = APR_BRIGADE_FIRST(bb);
452 if (APR_BUCKET_IS_EOS(bucket)) { 458 if (APR_BUCKET_IS_EOS(bucket) || AP_BUCKET_IS_EOC(bucket)) {
453 459
454 /* gnutls_bye(ctxt->session, GNUTLS_SHUT_RDWR); */ 460 gnutls_bye(ctxt->session, GNUTLS_SHUT_WR);
461 gnutls_deinit(ctxt->session);
455 462
456 if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) { 463 if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
457 return status; 464 return status;
@@ -464,17 +471,6 @@ apr_status_t mod_gnutls_filter_output(ap_filter_t * f,
464 return status; 471 return status;
465 } 472 }
466 break; 473 break;
467
468 }
469 else if (AP_BUCKET_IS_EOC(bucket)) {
470
471 gnutls_bye(ctxt->session, GNUTLS_SHUT_WR);
472 gnutls_deinit(ctxt->session);
473 if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
474 return status;
475 }
476 break;
477
478 } 474 }
479 else { 475 else {
480 /* filter output */ 476 /* filter output */
diff --git a/src/mod_gnutls.c b/src/mod_gnutls.c
index 3dfbd9a..833edc2 100644
--- a/src/mod_gnutls.c
+++ b/src/mod_gnutls.c
@@ -70,7 +70,7 @@ static int mod_gnutls_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
70 } 70 }
71 71
72 72
73 if(first_run) { 73// if(first_run) {
74 /* TODO: Should we regenerate these after X requests / X time ? */ 74 /* TODO: Should we regenerate these after X requests / X time ? */
75 gnutls_dh_params_init(&dh_params); 75 gnutls_dh_params_init(&dh_params);
76 gnutls_dh_params_generate2(dh_params, DH_BITS); 76 gnutls_dh_params_generate2(dh_params, DH_BITS);
@@ -78,7 +78,7 @@ static int mod_gnutls_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
78 gnutls_rsa_params_init(&rsa_params); 78 gnutls_rsa_params_init(&rsa_params);
79 gnutls_rsa_params_generate2(rsa_params, RSA_BITS); 79 gnutls_rsa_params_generate2(rsa_params, RSA_BITS);
80#endif 80#endif
81 } 81// }
82 82
83 for (s = base_server; s; s = s->next) { 83 for (s = base_server; s; s = s->next) {
84 sc = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config, 84 sc = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config,
@@ -105,6 +105,25 @@ static int mod_gnutls_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
105 return OK; 105 return OK;
106} 106}
107 107
108static void mod_gnutls_hook_child_init(apr_pool_t *p, server_rec *s)
109{
110 apr_status_t rv = APR_SUCCESS;
111 mod_gnutls_srvconf_rec *sc = ap_get_module_config(s->module_config,
112 &gnutls_module);
113
114 if(sc->cache_config != NULL) {
115 rv = mod_gnutls_cache_child_init(p, s, sc);
116 if(rv != APR_SUCCESS) {
117 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
118 "[GnuTLS] - Failed to run Cache Init");
119 }
120 }
121 else {
122 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
123 "[GnuTLS] - No Cache Configured. Hint: GnuTLSCache");
124 }
125}
126
108static const char *mod_gnutls_hook_http_method(const request_rec * r) 127static const char *mod_gnutls_hook_http_method(const request_rec * r)
109{ 128{
110 mod_gnutls_srvconf_rec *sc = 129 mod_gnutls_srvconf_rec *sc =
@@ -172,6 +191,7 @@ static mod_gnutls_handle_t* create_gnutls_handle(apr_pool_t* pool, conn_rec * c)
172 191
173 gnutls_dh_set_prime_bits(ctxt->session, DH_BITS); 192 gnutls_dh_set_prime_bits(ctxt->session, DH_BITS);
174 193
194 mod_gnutls_cache_session_init(ctxt);
175 return ctxt; 195 return ctxt;
176} 196}
177 197
@@ -250,6 +270,21 @@ static const char *gnutls_set_key_file(cmd_parms * parms, void *dummy,
250 return NULL; 270 return NULL;
251} 271}
252 272
273static const char *gnutls_set_cache(cmd_parms * parms, void *dummy,
274 const char *arg)
275{
276 const char* err;
277 mod_gnutls_srvconf_rec *sc = ap_get_module_config(parms->server->
278 module_config,
279 &gnutls_module);
280 if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
281 return err;
282 }
283
284 sc->cache_config = apr_pstrdup(parms->pool, arg);
285 return NULL;
286}
287
253static const char *gnutls_set_enabled(cmd_parms * parms, void *dummy, 288static const char *gnutls_set_enabled(cmd_parms * parms, void *dummy,
254 const char *arg) 289 const char *arg)
255{ 290{
@@ -279,6 +314,10 @@ static const command_rec gnutls_cmds[] = {
279 NULL, 314 NULL,
280 RSRC_CONF, 315 RSRC_CONF,
281 "SSL Server Certificate file"), 316 "SSL Server Certificate file"),
317 AP_INIT_TAKE1("GnuTLSCache", gnutls_set_cache,
318 NULL,
319 RSRC_CONF,
320 "SSL Server Certificate file"),
282 AP_INIT_TAKE1("GnuTLSEnable", gnutls_set_enabled, 321 AP_INIT_TAKE1("GnuTLSEnable", gnutls_set_enabled,
283 NULL, RSRC_CONF, 322 NULL, RSRC_CONF,
284 "Whether this server has GnuTLS Enabled. Default: Off"), 323 "Whether this server has GnuTLS Enabled. Default: Off"),
@@ -299,6 +338,8 @@ static void gnutls_hooks(apr_pool_t * p)
299 APR_HOOK_MIDDLE); 338 APR_HOOK_MIDDLE);
300 ap_hook_post_config(mod_gnutls_hook_post_config, NULL, NULL, 339 ap_hook_post_config(mod_gnutls_hook_post_config, NULL, NULL,
301 APR_HOOK_MIDDLE); 340 APR_HOOK_MIDDLE);
341 ap_hook_child_init(mod_gnutls_hook_child_init, NULL, NULL,
342 APR_HOOK_MIDDLE);
302 ap_hook_http_method(mod_gnutls_hook_http_method, NULL, NULL, 343 ap_hook_http_method(mod_gnutls_hook_http_method, NULL, NULL,
303 APR_HOOK_MIDDLE); 344 APR_HOOK_MIDDLE);
304 ap_hook_default_port(mod_gnutls_hook_default_port, NULL, NULL, 345 ap_hook_default_port(mod_gnutls_hook_default_port, NULL, NULL,
@@ -331,6 +372,7 @@ static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s)
331 gnutls_anon_allocate_server_credentials(&sc->anoncred); 372 gnutls_anon_allocate_server_credentials(&sc->anoncred);
332 sc->key_file = NULL; 373 sc->key_file = NULL;
333 sc->cert_file = NULL; 374 sc->cert_file = NULL;
375 sc->cache_config = NULL;
334 376
335 i = 0; 377 i = 0;
336 sc->ciphers[i++] = GNUTLS_CIPHER_AES_256_CBC; 378 sc->ciphers[i++] = GNUTLS_CIPHER_AES_256_CBC;