aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/mod_gnutls.h.in75
-rw-r--r--mod_gnutls.xcode/project.pbxproj10
-rw-r--r--src/Makefile.am2
-rw-r--r--src/gnutls_cache.c40
-rw-r--r--src/gnutls_config.c42
-rw-r--r--src/gnutls_hooks.c654
-rw-r--r--src/gnutls_io.c32
-rw-r--r--src/mod_gnutls.c665
8 files changed, 788 insertions, 732 deletions
diff --git a/include/mod_gnutls.h.in b/include/mod_gnutls.h.in
index 61b0198..b5a84c0 100644
--- a/include/mod_gnutls.h.in
+++ b/include/mod_gnutls.h.in
@@ -62,17 +62,17 @@ module AP_MODULE_DECLARE_DATA gnutls_module;
62 62
63typedef enum 63typedef enum
64{ 64{
65 mod_gnutls_cache_none, 65 mgs_cache_none,
66 mod_gnutls_cache_dbm, 66 mgs_cache_dbm,
67#if HAVE_APR_MEMCACHE 67#if HAVE_APR_MEMCACHE
68 mod_gnutls_cache_memcache 68 mgs_cache_memcache
69#endif 69#endif
70} mod_gnutls_cache_e; 70} mgs_cache_e;
71 71
72typedef struct 72typedef struct
73{ 73{
74 int client_verify_mode; 74 int client_verify_mode;
75} mod_gnutls_dirconf_rec; 75} mgs_dirconf_rec;
76 76
77typedef struct 77typedef struct
78{ 78{
@@ -88,21 +88,21 @@ typedef struct
88 int compression[16]; 88 int compression[16];
89 int cert_types[16]; 89 int cert_types[16];
90 apr_time_t cache_timeout; 90 apr_time_t cache_timeout;
91 mod_gnutls_cache_e cache_type; 91 mgs_cache_e cache_type;
92 const char* cache_config; 92 const char* cache_config;
93 const char* rsa_params_file; 93 const char* rsa_params_file;
94 const char* dh_params_file; 94 const char* dh_params_file;
95 int client_verify_mode; 95 int client_verify_mode;
96} mod_gnutls_srvconf_rec; 96} mgs_srvconf_rec;
97 97
98typedef struct { 98typedef struct {
99 int length; 99 int length;
100 char *value; 100 char *value;
101} mod_gnutls_char_buffer_t; 101} mgs_char_buffer_t;
102 102
103typedef struct 103typedef struct
104{ 104{
105 mod_gnutls_srvconf_rec *sc; 105 mgs_srvconf_rec *sc;
106 conn_rec* c; 106 conn_rec* c;
107 gnutls_session_t session; 107 gnutls_session_t session;
108 108
@@ -111,7 +111,7 @@ typedef struct
111 apr_bucket_brigade *input_bb; 111 apr_bucket_brigade *input_bb;
112 apr_read_type_e input_block; 112 apr_read_type_e input_block;
113 ap_input_mode_t input_mode; 113 ap_input_mode_t input_mode;
114 mod_gnutls_char_buffer_t input_cbuf; 114 mgs_char_buffer_t input_cbuf;
115 char input_buffer[AP_IOBUFSIZE]; 115 char input_buffer[AP_IOBUFSIZE];
116 116
117 apr_status_t output_rc; 117 apr_status_t output_rc;
@@ -123,12 +123,12 @@ typedef struct
123 123
124 int status; 124 int status;
125 int non_https; 125 int non_https;
126} mod_gnutls_handle_t; 126} mgs_handle_t;
127 127
128/** Functions in gnutls_io.c **/ 128/** Functions in gnutls_io.c **/
129 129
130/** 130/**
131 * mod_gnutls_filter_input will filter the input data 131 * mgs_filter_input will filter the input data
132 * by decrypting it using GnuTLS and passes it cleartext. 132 * by decrypting it using GnuTLS and passes it cleartext.
133 * 133 *
134 * @param f the filter info record 134 * @param f the filter info record
@@ -137,26 +137,26 @@ typedef struct
137 * @param block a block index we shall read from? 137 * @param block a block index we shall read from?
138 * @return result status 138 * @return result status
139 */ 139 */
140apr_status_t mod_gnutls_filter_input(ap_filter_t * f, 140apr_status_t mgs_filter_input(ap_filter_t * f,
141 apr_bucket_brigade * bb, 141 apr_bucket_brigade * bb,
142 ap_input_mode_t mode, 142 ap_input_mode_t mode,
143 apr_read_type_e block, 143 apr_read_type_e block,
144 apr_off_t readbytes); 144 apr_off_t readbytes);
145 145
146/** 146/**
147 * mod_gnutls_filter_output will filter the encrypt 147 * mgs_filter_output will filter the encrypt
148 * the incoming bucket using GnuTLS and passes it onto the next filter. 148 * the incoming bucket using GnuTLS and passes it onto the next filter.
149 * 149 *
150 * @param f the filter info record 150 * @param f the filter info record
151 * @param bb the bucket brigade, where to store the result to 151 * @param bb the bucket brigade, where to store the result to
152 * @return result status 152 * @return result status
153 */ 153 */
154apr_status_t mod_gnutls_filter_output(ap_filter_t * f, 154apr_status_t mgs_filter_output(ap_filter_t * f,
155 apr_bucket_brigade * bb); 155 apr_bucket_brigade * bb);
156 156
157 157
158/** 158/**
159 * mod_gnutls_transport_read is called from GnuTLS to provide encrypted 159 * mgs_transport_read is called from GnuTLS to provide encrypted
160 * data from the client. 160 * data from the client.
161 * 161 *
162 * @param ptr pointer to the filter context 162 * @param ptr pointer to the filter context
@@ -164,11 +164,11 @@ apr_status_t mod_gnutls_filter_output(ap_filter_t * f,
164 * @param len maximum size 164 * @param len maximum size
165 * @return size length of the data stored in buffer 165 * @return size length of the data stored in buffer
166 */ 166 */
167ssize_t mod_gnutls_transport_read(gnutls_transport_ptr_t ptr, 167ssize_t mgs_transport_read(gnutls_transport_ptr_t ptr,
168 void *buffer, size_t len); 168 void *buffer, size_t len);
169 169
170/** 170/**
171 * mod_gnutls_transport_write is called from GnuTLS to 171 * mgs_transport_write is called from GnuTLS to
172 * write data to the client. 172 * write data to the client.
173 * 173 *
174 * @param ptr pointer to the filter context 174 * @param ptr pointer to the filter context
@@ -176,28 +176,28 @@ ssize_t mod_gnutls_transport_read(gnutls_transport_ptr_t ptr,
176 * @param len size of the buffer 176 * @param len size of the buffer
177 * @return size length of the data written 177 * @return size length of the data written
178 */ 178 */
179ssize_t mod_gnutls_transport_write(gnutls_transport_ptr_t ptr, 179ssize_t mgs_transport_write(gnutls_transport_ptr_t ptr,
180 const void *buffer, size_t len); 180 const void *buffer, size_t len);
181 181
182 182
183int mod_gnutls_rehandshake(mod_gnutls_handle_t * ctxt); 183int mgs_rehandshake(mgs_handle_t * ctxt);
184 184
185 185
186 186
187/** 187/**
188 * Init the Cache after Configuration is done 188 * Init the Cache after Configuration is done
189 */ 189 */
190int mod_gnutls_cache_post_config(apr_pool_t *p, server_rec *s, 190int mgs_cache_post_config(apr_pool_t *p, server_rec *s,
191 mod_gnutls_srvconf_rec *sc); 191 mgs_srvconf_rec *sc);
192/** 192/**
193 * Init the Cache inside each Process 193 * Init the Cache inside each Process
194 */ 194 */
195int mod_gnutls_cache_child_init(apr_pool_t *p, server_rec *s, 195int mgs_cache_child_init(apr_pool_t *p, server_rec *s,
196 mod_gnutls_srvconf_rec *sc); 196 mgs_srvconf_rec *sc);
197/** 197/**
198 * Setup the Session Caching 198 * Setup the Session Caching
199 */ 199 */
200int mod_gnutls_cache_session_init(mod_gnutls_handle_t *ctxt); 200int mgs_cache_session_init(mgs_handle_t *ctxt);
201 201
202#define GNUTLS_SESSION_ID_STRING_LEN \ 202#define GNUTLS_SESSION_ID_STRING_LEN \
203 ((GNUTLS_MAX_SESSION_ID + 1) * 2) 203 ((GNUTLS_MAX_SESSION_ID + 1) * 2)
@@ -209,9 +209,10 @@ int mod_gnutls_cache_session_init(mod_gnutls_handle_t *ctxt);
209 * @param str Location to store the Hex Encoded String 209 * @param str Location to store the Hex Encoded String
210 * @param strsize The Maximum Length that can be stored in str 210 * @param strsize The Maximum Length that can be stored in str
211 */ 211 */
212char *mod_gnutls_session_id2sz(unsigned char *id, int idlen, 212char *mgs_session_id2sz(unsigned char *id, int idlen,
213 char *str, int strsize); 213 char *str, int strsize);
214 214
215
215/* Configuration Functions */ 216/* Configuration Functions */
216 217
217const char *mgs_set_cert_file(cmd_parms * parms, void *dummy, 218const char *mgs_set_cert_file(cmd_parms * parms, void *dummy,
@@ -239,4 +240,26 @@ void *mgs_config_server_create(apr_pool_t * p, server_rec * s);
239 240
240void *mgs_config_dir_create(apr_pool_t *p, char *dir); 241void *mgs_config_dir_create(apr_pool_t *p, char *dir);
241 242
243
244/* mod_gnutls Hooks. */
245
246int mgs_hook_pre_config(apr_pool_t * pconf,
247 apr_pool_t * plog, apr_pool_t * ptemp);
248
249int mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
250 apr_pool_t * ptemp,
251 server_rec * base_server);
252
253void mgs_hook_child_init(apr_pool_t *p, server_rec *s);
254
255const char *mgs_hook_http_scheme(const request_rec * r);
256
257apr_port_t mgs_hook_default_port(const request_rec * r);
258
259int mgs_hook_pre_connection(conn_rec * c, void *csd);
260
261int mgs_hook_fixups(request_rec *r);
262
263int mgs_hook_authz(request_rec *r);
264
242#endif /* __mod_gnutls_h_inc */ 265#endif /* __mod_gnutls_h_inc */
diff --git a/mod_gnutls.xcode/project.pbxproj b/mod_gnutls.xcode/project.pbxproj
index fd24bb2..08b50e1 100644
--- a/mod_gnutls.xcode/project.pbxproj
+++ b/mod_gnutls.xcode/project.pbxproj
@@ -14,9 +14,19 @@
14 refType = 2; 14 refType = 2;
15 sourceTree = SOURCE_ROOT; 15 sourceTree = SOURCE_ROOT;
16 }; 16 };
17 4541F3C5081C4F2B007457C1 = {
18 fileEncoding = 30;
19 isa = PBXFileReference;
20 lastKnownFileType = sourcecode.c.c;
21 name = gnutls_hooks.c;
22 path = src/gnutls_hooks.c;
23 refType = 2;
24 sourceTree = SOURCE_ROOT;
25 };
17 45B624630802F1E200CBFD9A = { 26 45B624630802F1E200CBFD9A = {
18 children = ( 27 children = (
19 4541F3BA081C4B1A007457C1, 28 4541F3BA081C4B1A007457C1,
29 4541F3C5081C4F2B007457C1,
20 45B6246D0802F20D00CBFD9A, 30 45B6246D0802F20D00CBFD9A,
21 45B6247D0802F85B00CBFD9A, 31 45B6247D0802F85B00CBFD9A,
22 45B6247A0802F84500CBFD9A, 32 45B6247A0802F84500CBFD9A,
diff --git a/src/Makefile.am b/src/Makefile.am
index a15fc57..c6d42c9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,6 @@
1CLEANFILES = .libs/libmod_gnutls *~ 1CLEANFILES = .libs/libmod_gnutls *~
2 2
3libmod_gnutls_la_SOURCES = mod_gnutls.c gnutls_io.c gnutls_cache.c gnutls_config.c 3libmod_gnutls_la_SOURCES = mod_gnutls.c gnutls_io.c gnutls_cache.c gnutls_config.c gnutls_hooks.c
4libmod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS} 4libmod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS}
5libmod_gnutls_la_LDFLAGS = -rpath ${AP_LIBEXECDIR} -module -avoid-version ${MODULE_LIBS} 5libmod_gnutls_la_LDFLAGS = -rpath ${AP_LIBEXECDIR} -module -avoid-version ${MODULE_LIBS}
6 6
diff --git a/src/gnutls_cache.c b/src/gnutls_cache.c
index 8499b84..4c094fa 100644
--- a/src/gnutls_cache.c
+++ b/src/gnutls_cache.c
@@ -53,7 +53,7 @@ static char *gnutls_session_id2sz(unsigned char *id, int idlen,
53 return str; 53 return str;
54} 54}
55 55
56char *mod_gnutls_session_id2sz(unsigned char *id, int idlen, 56char *mgs_session_id2sz(unsigned char *id, int idlen,
57 char *str, int strsize) 57 char *str, int strsize)
58{ 58{
59 char *cp; 59 char *cp;
@@ -80,7 +80,7 @@ char *mod_gnutls_session_id2sz(unsigned char *id, int idlen,
80static apr_memcache_t* mc; 80static apr_memcache_t* mc;
81 81
82static int mc_cache_child_init(apr_pool_t *p, server_rec *s, 82static int mc_cache_child_init(apr_pool_t *p, server_rec *s,
83 mod_gnutls_srvconf_rec *sc) 83 mgs_srvconf_rec *sc)
84{ 84{
85 apr_status_t rv = APR_SUCCESS; 85 apr_status_t rv = APR_SUCCESS;
86 int thread_limit = 0; 86 int thread_limit = 0;
@@ -166,7 +166,7 @@ static int mc_cache_store(void* baton, gnutls_datum_t key,
166 gnutls_datum_t data) 166 gnutls_datum_t data)
167{ 167{
168 apr_status_t rv = APR_SUCCESS; 168 apr_status_t rv = APR_SUCCESS;
169 mod_gnutls_handle_t *ctxt = baton; 169 mgs_handle_t *ctxt = baton;
170 char buf[STR_SESSION_LEN]; 170 char buf[STR_SESSION_LEN];
171 char* strkey = NULL; 171 char* strkey = NULL;
172 apr_uint32_t timeout; 172 apr_uint32_t timeout;
@@ -193,7 +193,7 @@ static int mc_cache_store(void* baton, gnutls_datum_t key,
193static gnutls_datum_t mc_cache_fetch(void* baton, gnutls_datum_t key) 193static gnutls_datum_t mc_cache_fetch(void* baton, gnutls_datum_t key)
194{ 194{
195 apr_status_t rv = APR_SUCCESS; 195 apr_status_t rv = APR_SUCCESS;
196 mod_gnutls_handle_t *ctxt = baton; 196 mgs_handle_t *ctxt = baton;
197 char buf[STR_SESSION_LEN]; 197 char buf[STR_SESSION_LEN];
198 char* strkey = NULL; 198 char* strkey = NULL;
199 char* value; 199 char* value;
@@ -234,7 +234,7 @@ static gnutls_datum_t mc_cache_fetch(void* baton, gnutls_datum_t key)
234static int mc_cache_delete(void* baton, gnutls_datum_t key) 234static int mc_cache_delete(void* baton, gnutls_datum_t key)
235{ 235{
236 apr_status_t rv = APR_SUCCESS; 236 apr_status_t rv = APR_SUCCESS;
237 mod_gnutls_handle_t *ctxt = baton; 237 mgs_handle_t *ctxt = baton;
238 char buf[STR_SESSION_LEN]; 238 char buf[STR_SESSION_LEN];
239 char* strkey = NULL; 239 char* strkey = NULL;
240 240
@@ -259,7 +259,7 @@ static int mc_cache_delete(void* baton, gnutls_datum_t key)
259 259
260#define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD ) 260#define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )
261 261
262static int dbm_cache_expire(mod_gnutls_handle_t *ctxt) 262static int dbm_cache_expire(mgs_handle_t *ctxt)
263{ 263{
264 apr_status_t rv; 264 apr_status_t rv;
265 apr_dbm_t *dbm; 265 apr_dbm_t *dbm;
@@ -346,7 +346,7 @@ static gnutls_datum_t dbm_cache_fetch(void* baton, gnutls_datum_t key)
346 apr_dbm_t *dbm; 346 apr_dbm_t *dbm;
347 apr_datum_t dbmkey; 347 apr_datum_t dbmkey;
348 apr_datum_t dbmval; 348 apr_datum_t dbmval;
349 mod_gnutls_handle_t *ctxt = baton; 349 mgs_handle_t *ctxt = baton;
350 apr_status_t rv; 350 apr_status_t rv;
351 351
352 dbmkey.dptr = key.data; 352 dbmkey.dptr = key.data;
@@ -395,7 +395,7 @@ static int dbm_cache_store(void* baton, gnutls_datum_t key,
395 apr_dbm_t *dbm; 395 apr_dbm_t *dbm;
396 apr_datum_t dbmkey; 396 apr_datum_t dbmkey;
397 apr_datum_t dbmval; 397 apr_datum_t dbmval;
398 mod_gnutls_handle_t *ctxt = baton; 398 mgs_handle_t *ctxt = baton;
399 apr_status_t rv; 399 apr_status_t rv;
400 apr_time_t expiry; 400 apr_time_t expiry;
401 401
@@ -448,7 +448,7 @@ static int dbm_cache_delete(void* baton, gnutls_datum_t key)
448{ 448{
449 apr_dbm_t *dbm; 449 apr_dbm_t *dbm;
450 apr_datum_t dbmkey; 450 apr_datum_t dbmkey;
451 mod_gnutls_handle_t *ctxt = baton; 451 mgs_handle_t *ctxt = baton;
452 apr_status_t rv; 452 apr_status_t rv;
453 453
454 dbmkey.dptr = (char *)key.data; 454 dbmkey.dptr = (char *)key.data;
@@ -483,7 +483,7 @@ static int dbm_cache_delete(void* baton, gnutls_datum_t key)
483} 483}
484 484
485static int dbm_cache_post_config(apr_pool_t *p, server_rec *s, 485static int dbm_cache_post_config(apr_pool_t *p, server_rec *s,
486 mod_gnutls_srvconf_rec *sc) 486 mgs_srvconf_rec *sc)
487{ 487{
488 apr_status_t rv; 488 apr_status_t rv;
489 apr_dbm_t *dbm; 489 apr_dbm_t *dbm;
@@ -518,23 +518,23 @@ static int dbm_cache_post_config(apr_pool_t *p, server_rec *s,
518 return rv; 518 return rv;
519} 519}
520 520
521int mod_gnutls_cache_post_config(apr_pool_t *p, server_rec *s, 521int mgs_cache_post_config(apr_pool_t *p, server_rec *s,
522 mod_gnutls_srvconf_rec *sc) 522 mgs_srvconf_rec *sc)
523{ 523{
524 if (sc->cache_type == mod_gnutls_cache_dbm) { 524 if (sc->cache_type == mgs_cache_dbm) {
525 return dbm_cache_post_config(p, s, sc); 525 return dbm_cache_post_config(p, s, sc);
526 } 526 }
527 return 0; 527 return 0;
528} 528}
529 529
530int mod_gnutls_cache_child_init(apr_pool_t *p, server_rec *s, 530int mgs_cache_child_init(apr_pool_t *p, server_rec *s,
531 mod_gnutls_srvconf_rec *sc) 531 mgs_srvconf_rec *sc)
532{ 532{
533 if (sc->cache_type == mod_gnutls_cache_dbm) { 533 if (sc->cache_type == mgs_cache_dbm) {
534 return 0; 534 return 0;
535 } 535 }
536#if HAVE_APR_MEMCACHE 536#if HAVE_APR_MEMCACHE
537 else if (sc->cache_type == mod_gnutls_cache_memcache) { 537 else if (sc->cache_type == mgs_cache_memcache) {
538 return mc_cache_child_init(p, s, sc); 538 return mc_cache_child_init(p, s, sc);
539 } 539 }
540#endif 540#endif
@@ -543,16 +543,16 @@ int mod_gnutls_cache_child_init(apr_pool_t *p, server_rec *s,
543 543
544 #include <assert.h> 544 #include <assert.h>
545 545
546int mod_gnutls_cache_session_init(mod_gnutls_handle_t *ctxt) 546int mgs_cache_session_init(mgs_handle_t *ctxt)
547{ 547{
548 if (ctxt->sc->cache_type == mod_gnutls_cache_dbm) { 548 if (ctxt->sc->cache_type == mgs_cache_dbm) {
549 gnutls_db_set_retrieve_function(ctxt->session, dbm_cache_fetch); 549 gnutls_db_set_retrieve_function(ctxt->session, dbm_cache_fetch);
550 gnutls_db_set_remove_function(ctxt->session, dbm_cache_delete); 550 gnutls_db_set_remove_function(ctxt->session, dbm_cache_delete);
551 gnutls_db_set_store_function(ctxt->session, dbm_cache_store); 551 gnutls_db_set_store_function(ctxt->session, dbm_cache_store);
552 gnutls_db_set_ptr(ctxt->session, ctxt); 552 gnutls_db_set_ptr(ctxt->session, ctxt);
553 } 553 }
554#if HAVE_APR_MEMCACHE 554#if HAVE_APR_MEMCACHE
555 else if (ctxt->sc->cache_type == mod_gnutls_cache_memcache) { 555 else if (ctxt->sc->cache_type == mgs_cache_memcache) {
556 gnutls_db_set_retrieve_function(ctxt->session, mc_cache_fetch); 556 gnutls_db_set_retrieve_function(ctxt->session, mc_cache_fetch);
557 gnutls_db_set_remove_function(ctxt->session, mc_cache_delete); 557 gnutls_db_set_remove_function(ctxt->session, mc_cache_delete);
558 gnutls_db_set_store_function(ctxt->session, mc_cache_store); 558 gnutls_db_set_store_function(ctxt->session, mc_cache_store);
diff --git a/src/gnutls_config.c b/src/gnutls_config.c
index 2c29ccb..f9a315c 100644
--- a/src/gnutls_config.c
+++ b/src/gnutls_config.c
@@ -59,8 +59,8 @@ const char *mgs_set_cert_file(cmd_parms * parms, void *dummy,
59 gnutls_datum_t data; 59 gnutls_datum_t data;
60 const char* file; 60 const char* file;
61 apr_pool_t* spool; 61 apr_pool_t* spool;
62 mod_gnutls_srvconf_rec *sc = 62 mgs_srvconf_rec *sc =
63 (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server-> 63 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
64 module_config, 64 module_config,
65 &gnutls_module); 65 &gnutls_module);
66 apr_pool_create(&spool, parms->pool); 66 apr_pool_create(&spool, parms->pool);
@@ -91,8 +91,8 @@ const char *mgs_set_key_file(cmd_parms * parms, void *dummy,
91 gnutls_datum_t data; 91 gnutls_datum_t data;
92 const char* file; 92 const char* file;
93 apr_pool_t* spool; 93 apr_pool_t* spool;
94 mod_gnutls_srvconf_rec *sc = 94 mgs_srvconf_rec *sc =
95 (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server-> 95 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
96 module_config, 96 module_config,
97 &gnutls_module); 97 &gnutls_module);
98 apr_pool_create(&spool, parms->pool); 98 apr_pool_create(&spool, parms->pool);
@@ -119,7 +119,7 @@ const char *mgs_set_cache(cmd_parms * parms, void *dummy,
119 const char *type, const char* arg) 119 const char *type, const char* arg)
120{ 120{
121 const char* err; 121 const char* err;
122 mod_gnutls_srvconf_rec *sc = ap_get_module_config(parms->server-> 122 mgs_srvconf_rec *sc = ap_get_module_config(parms->server->
123 module_config, 123 module_config,
124 &gnutls_module); 124 &gnutls_module);
125 if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) { 125 if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
@@ -127,21 +127,21 @@ const char *mgs_set_cache(cmd_parms * parms, void *dummy,
127 } 127 }
128 128
129 if (strcasecmp("none", type) == 0) { 129 if (strcasecmp("none", type) == 0) {
130 sc->cache_type = mod_gnutls_cache_none; 130 sc->cache_type = mgs_cache_none;
131 } 131 }
132 else if (strcasecmp("dbm", type) == 0) { 132 else if (strcasecmp("dbm", type) == 0) {
133 sc->cache_type = mod_gnutls_cache_dbm; 133 sc->cache_type = mgs_cache_dbm;
134 } 134 }
135#if HAVE_APR_MEMCACHE 135#if HAVE_APR_MEMCACHE
136 else if (strcasecmp("memcache", type) == 0) { 136 else if (strcasecmp("memcache", type) == 0) {
137 sc->cache_type = mod_gnutls_cache_memcache; 137 sc->cache_type = mgs_cache_memcache;
138 } 138 }
139#endif 139#endif
140 else { 140 else {
141 return "Invalid Type for GnuTLSCache!"; 141 return "Invalid Type for GnuTLSCache!";
142 } 142 }
143 143
144 if (sc->cache_type == mod_gnutls_cache_dbm) { 144 if (sc->cache_type == mgs_cache_dbm) {
145 sc->cache_config = ap_server_root_relative(parms->pool, arg); 145 sc->cache_config = ap_server_root_relative(parms->pool, arg);
146 } 146 }
147 else { 147 else {
@@ -155,8 +155,8 @@ const char *mgs_set_cache_timeout(cmd_parms * parms, void *dummy,
155 const char *arg) 155 const char *arg)
156{ 156{
157 int argint; 157 int argint;
158 mod_gnutls_srvconf_rec *sc = 158 mgs_srvconf_rec *sc =
159 (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server-> 159 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
160 module_config, 160 module_config,
161 &gnutls_module); 161 &gnutls_module);
162 162
@@ -195,12 +195,12 @@ const char *mgs_set_client_verify(cmd_parms * parms, void *dummy,
195 195
196 /* This was set from a directory context */ 196 /* This was set from a directory context */
197 if (parms->path) { 197 if (parms->path) {
198 mod_gnutls_dirconf_rec *dc = (mod_gnutls_dirconf_rec *)dummy; 198 mgs_dirconf_rec *dc = (mgs_dirconf_rec *)dummy;
199 dc->client_verify_mode = mode; 199 dc->client_verify_mode = mode;
200 } 200 }
201 else { 201 else {
202 mod_gnutls_srvconf_rec *sc = 202 mgs_srvconf_rec *sc =
203 (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server-> 203 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
204 module_config, 204 module_config,
205 &gnutls_module); 205 &gnutls_module);
206 sc->client_verify_mode = mode; 206 sc->client_verify_mode = mode;
@@ -214,8 +214,8 @@ const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy,
214{ 214{
215 int rv; 215 int rv;
216 const char* file; 216 const char* file;
217 mod_gnutls_srvconf_rec *sc = 217 mgs_srvconf_rec *sc =
218 (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server-> 218 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
219 module_config, 219 module_config,
220 &gnutls_module); 220 &gnutls_module);
221 file = ap_server_root_relative(parms->pool, arg); 221 file = ap_server_root_relative(parms->pool, arg);
@@ -233,8 +233,8 @@ const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy,
233const char *mgs_set_enabled(cmd_parms * parms, void *dummy, 233const char *mgs_set_enabled(cmd_parms * parms, void *dummy,
234 const char *arg) 234 const char *arg)
235{ 235{
236 mod_gnutls_srvconf_rec *sc = 236 mgs_srvconf_rec *sc =
237 (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server-> 237 (mgs_srvconf_rec *) ap_get_module_config(parms->server->
238 module_config, 238 module_config,
239 &gnutls_module); 239 &gnutls_module);
240 if (!strcasecmp(arg, "On")) { 240 if (!strcasecmp(arg, "On")) {
@@ -253,7 +253,7 @@ const char *mgs_set_enabled(cmd_parms * parms, void *dummy,
253void *mgs_config_server_create(apr_pool_t * p, server_rec * s) 253void *mgs_config_server_create(apr_pool_t * p, server_rec * s)
254{ 254{
255 int i; 255 int i;
256 mod_gnutls_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc)); 256 mgs_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc));
257 257
258 sc->enabled = GNUTLS_ENABLED_FALSE; 258 sc->enabled = GNUTLS_ENABLED_FALSE;
259 259
@@ -261,7 +261,7 @@ void *mgs_config_server_create(apr_pool_t * p, server_rec * s)
261 sc->privkey_x509 = NULL; 261 sc->privkey_x509 = NULL;
262 sc->cert_x509 = NULL; 262 sc->cert_x509 = NULL;
263 sc->cache_timeout = apr_time_from_sec(300); 263 sc->cache_timeout = apr_time_from_sec(300);
264 sc->cache_type = mod_gnutls_cache_dbm; 264 sc->cache_type = mgs_cache_dbm;
265 sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache"); 265 sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache");
266 266
267 /* TODO: Make this Configurable. But it isn't configurable in mod_ssl? */ 267 /* TODO: Make this Configurable. But it isn't configurable in mod_ssl? */
@@ -319,7 +319,7 @@ void *mgs_config_server_create(apr_pool_t * p, server_rec * s)
319 319
320void *mgs_config_dir_create(apr_pool_t *p, char *dir) 320void *mgs_config_dir_create(apr_pool_t *p, char *dir)
321{ 321{
322 mod_gnutls_dirconf_rec *dc = apr_palloc(p, sizeof(*dc)); 322 mgs_dirconf_rec *dc = apr_palloc(p, sizeof(*dc));
323 323
324 dc->client_verify_mode = -1; 324 dc->client_verify_mode = -1;
325 325
diff --git a/src/gnutls_hooks.c b/src/gnutls_hooks.c
new file mode 100644
index 0000000..5429d66
--- /dev/null
+++ b/src/gnutls_hooks.c
@@ -0,0 +1,654 @@
1/**
2 * Copyright 2004-2005 Paul Querna
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18#include "mod_gnutls.h"
19#include "http_vhost.h"
20
21#if !USING_2_1_RECENT
22extern server_rec *ap_server_conf;
23#endif
24
25#if APR_HAS_THREADS
26GCRY_THREAD_OPTION_PTHREAD_IMPL;
27#endif
28
29#if MOD_GNUTLS_DEBUG
30static apr_file_t* debug_log_fp;
31#endif
32
33static apr_status_t mgs_cleanup_pre_config(void *data)
34{
35 gnutls_global_deinit();
36 return APR_SUCCESS;
37}
38
39#if MOD_GNUTLS_DEBUG
40static void gnutls_debug_log_all( int level, const char* str)
41{
42 apr_file_printf(debug_log_fp, "<%d> %s\n", level, str);
43}
44#endif
45
46int mgs_hook_pre_config(apr_pool_t * pconf,
47 apr_pool_t * plog, apr_pool_t * ptemp)
48{
49
50#if APR_HAS_THREADS
51 /* TODO: Check MPM Type here */
52 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
53#endif
54
55 gnutls_global_init();
56
57 apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config,
58 apr_pool_cleanup_null);
59
60#if MOD_GNUTLS_DEBUG
61 apr_file_open(&debug_log_fp, "/tmp/gnutls_debug",
62 APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, pconf);
63
64 gnutls_global_set_log_level(9);
65 gnutls_global_set_log_function(gnutls_debug_log_all);
66#endif
67
68 return OK;
69}
70
71
72static gnutls_datum load_params(const char* file, server_rec* s,
73 apr_pool_t* pool)
74{
75 gnutls_datum ret = { NULL, 0 };
76 apr_file_t* fp;
77 apr_finfo_t finfo;
78 apr_status_t rv;
79 apr_size_t br = 0;
80
81 rv = apr_file_open(&fp, file, APR_READ|APR_BINARY, APR_OS_DEFAULT,
82 pool);
83 if (rv != APR_SUCCESS) {
84 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
85 "GnuTLS failed to load params file at: %s", file);
86 return ret;
87 }
88
89 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
90
91 if (rv != APR_SUCCESS) {
92 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
93 "GnuTLS failed to stat params file at: %s", file);
94 return ret;
95 }
96
97 ret.data = apr_palloc(pool, finfo.size+1);
98 rv = apr_file_read_full(fp, ret.data, finfo.size, &br);
99
100 if (rv != APR_SUCCESS) {
101 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
102 "GnuTLS failed to read params file at: %s", file);
103 return ret;
104 }
105 apr_file_close(fp);
106 ret.data[br] = '\0';
107 ret.size = br;
108
109 return ret;
110}
111
112int mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
113 apr_pool_t * ptemp,
114 server_rec * base_server)
115{
116 int rv;
117 int data_len;
118 server_rec *s;
119 gnutls_dh_params_t dh_params;
120 gnutls_rsa_params_t rsa_params;
121 mgs_srvconf_rec *sc;
122 mgs_srvconf_rec *sc_base;
123 void *data = NULL;
124 int first_run = 0;
125 const char *userdata_key = "mgs_init";
126
127 apr_pool_userdata_get(&data, userdata_key, base_server->process->pool);
128 if (data == NULL) {
129 first_run = 1;
130 apr_pool_userdata_set((const void *)1, userdata_key,
131 apr_pool_cleanup_null,
132 base_server->process->pool);
133 }
134
135
136 {
137 gnutls_datum pdata;
138 apr_pool_t* tpool;
139 s = base_server;
140 sc_base = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
141 &gnutls_module);
142
143 apr_pool_create(&tpool, p);
144
145 gnutls_dh_params_init(&dh_params);
146
147 pdata = load_params(sc_base->dh_params_file, s, tpool);
148
149 if (pdata.size != 0) {
150 rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata,
151 GNUTLS_X509_FMT_PEM);
152 if (rv != 0) {
153 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
154 "GnuTLS: Unable to load DH Params: (%d) %s",
155 rv, gnutls_strerror(rv));
156 exit(rv);
157 }
158 }
159 else {
160 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
161 "GnuTLS: Unable to load DH Params."
162 " Shutting Down.");
163 exit(-1);
164 }
165 apr_pool_clear(tpool);
166
167 gnutls_rsa_params_init(&rsa_params);
168
169 pdata = load_params(sc_base->rsa_params_file, s, tpool);
170
171 if (pdata.size != 0) {
172 rv = gnutls_rsa_params_import_pkcs1(rsa_params, &pdata,
173 GNUTLS_X509_FMT_PEM);
174 if (rv != 0) {
175 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
176 "GnuTLS: Unable to load RSA Params: (%d) %s",
177 rv, gnutls_strerror(rv));
178 exit(rv);
179 }
180 }
181 else {
182 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
183 "GnuTLS: Unable to load RSA Params."
184 " Shutting Down.");
185 exit(-1);
186 }
187
188 apr_pool_destroy(tpool);
189 rv = mgs_cache_post_config(p, s, sc_base);
190 if (rv != 0) {
191 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
192 "GnuTLS: Post Config for GnuTLSCache Failed."
193 " Shutting Down.");
194 exit(-1);
195 }
196
197 for (s = base_server; s; s = s->next) {
198 sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
199 &gnutls_module);
200 sc->cache_type = sc_base->cache_type;
201 sc->cache_config = sc_base->cache_config;
202
203 gnutls_certificate_set_rsa_export_params(sc->certs,
204 rsa_params);
205 gnutls_certificate_set_dh_params(sc->certs, dh_params);
206
207 if (sc->cert_x509 == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
208 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
209 "[GnuTLS] - Host '%s:%d' is missing a "
210 "Certificate File!",
211 s->server_hostname, s->port);
212 exit(-1);
213 }
214
215 if (sc->privkey_x509 == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
216 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
217 "[GnuTLS] - Host '%s:%d' is missing a "
218 "Private Key File!",
219 s->server_hostname, s->port);
220 exit(-1);
221 }
222
223 rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509,
224 GNUTLS_OID_X520_COMMON_NAME, 0, 0,
225 NULL, &data_len);
226
227 if (data_len < 1) {
228 sc->enabled = GNUTLS_ENABLED_FALSE;
229 sc->cert_cn = NULL;
230 continue;
231 }
232
233 sc->cert_cn = apr_palloc(p, data_len);
234 rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509,
235 GNUTLS_OID_X520_COMMON_NAME, 0, 0,
236 sc->cert_cn, &data_len);
237 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
238 s,
239 "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X sc: 0x%08X", sc->cert_cn, rv,
240 gnutls_pk_algorithm_get_name(gnutls_x509_privkey_get_pk_algorithm(sc->privkey_x509)),
241 (unsigned int)s, (unsigned int)sc);
242 }
243 }
244
245 ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION);
246
247 return OK;
248}
249
250void mgs_hook_child_init(apr_pool_t *p, server_rec *s)
251{
252 apr_status_t rv = APR_SUCCESS;
253 mgs_srvconf_rec *sc = ap_get_module_config(s->module_config,
254 &gnutls_module);
255
256 if (sc->cache_type != mgs_cache_none) {
257 rv = mgs_cache_child_init(p, s, sc);
258 if(rv != APR_SUCCESS) {
259 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
260 "[GnuTLS] - Failed to run Cache Init");
261 }
262 }
263 else {
264 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
265 "[GnuTLS] - No Cache Configured. Hint: GnuTLSCache");
266 }
267}
268
269const char *mgs_hook_http_scheme(const request_rec * r)
270{
271 mgs_srvconf_rec *sc =
272 (mgs_srvconf_rec *) ap_get_module_config(r->server->
273 module_config,
274 &gnutls_module);
275
276 if (sc->enabled == GNUTLS_ENABLED_FALSE) {
277 return NULL;
278 }
279
280 return "https";
281}
282
283apr_port_t mgs_hook_default_port(const request_rec * r)
284{
285 mgs_srvconf_rec *sc =
286 (mgs_srvconf_rec *) ap_get_module_config(r->server->
287 module_config,
288 &gnutls_module);
289
290 if (sc->enabled == GNUTLS_ENABLED_FALSE) {
291 return 0;
292 }
293
294 return 443;
295}
296
297#define MAX_HOST_LEN 255
298
299#if USING_2_1_RECENT
300typedef struct
301{
302 mgs_handle_t *ctxt;
303 gnutls_retr_st* ret;
304 const char* sni_name;
305} vhost_cb_rec;
306
307static int vhost_cb (void* baton, conn_rec* conn, server_rec* s)
308{
309 mgs_srvconf_rec *tsc;
310 vhost_cb_rec* x = baton;
311
312 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
313 &gnutls_module);
314
315 if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) {
316 return 0;
317 }
318
319 /* The CN can contain a * -- this will match those too. */
320 if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) {
321 /* found a match */
322 x->ret->cert.x509 = &tsc->cert_x509;
323 x->ret->key.x509 = tsc->privkey_x509;
324#if MOD_GNUTLS_DEBUG
325 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
326 x->ctxt->c->base_server,
327 "GnuTLS: Virtual Host CB: "
328 "'%s' == '%s'", tsc->cert_cn, x->sni_name);
329#endif
330 /* Because we actually change the server used here, we need to reset
331 * things like ClientVerify.
332 */
333 x->ctxt->sc = tsc;
334 /* Shit. Crap. Dammit. We *really* should rehandshake here, as our
335 * certificate structure *should* change when the server changes.
336 * acccckkkkkk.
337 */
338 gnutls_certificate_server_set_request(x->ctxt->session, x->ctxt->sc->client_verify_mode);
339 return 1;
340 }
341 return 0;
342}
343#endif
344
345static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st* ret)
346{
347 int rv;
348 int sni_type;
349 int data_len = MAX_HOST_LEN;
350 char sni_name[MAX_HOST_LEN];
351 mgs_handle_t *ctxt;
352#if USING_2_1_RECENT
353 vhost_cb_rec cbx;
354#else
355 server_rec* s;
356 mgs_srvconf_rec *tsc;
357#endif
358
359 ctxt = gnutls_transport_get_ptr(session);
360
361 sni_type = gnutls_certificate_type_get(session);
362 if (sni_type != GNUTLS_CRT_X509) {
363 /* In theory, we could support OpenPGP Certificates. Theory != code. */
364 ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
365 ctxt->c->base_server,
366 "GnuTLS: Only x509 Certificates are currently supported.");
367 return -1;
368 }
369
370 ret->type = GNUTLS_CRT_X509;
371 ret->ncerts = 1;
372 ret->deinit_all = 0;
373
374 rv = gnutls_server_name_get(ctxt->session, sni_name,
375 &data_len, &sni_type, 0);
376
377 if (rv != 0) {
378 goto use_default_crt;
379 }
380
381 if (sni_type != GNUTLS_NAME_DNS) {
382 ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
383 ctxt->c->base_server,
384 "GnuTLS: Unknown type '%d' for SNI: "
385 "'%s'", sni_type, sni_name);
386 goto use_default_crt;
387 }
388
389 /**
390 * Code in the Core already sets up the c->base_server as the base
391 * for this IP/Port combo. Trust that the core did the 'right' thing.
392 */
393#if USING_2_1_RECENT
394 cbx.ctxt = ctxt;
395 cbx.ret = ret;
396 cbx.sni_name = sni_name;
397
398 rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
399 if (rv == 1) {
400 return 0;
401 }
402#else
403 for (s = ap_server_conf; s; s = s->next) {
404
405 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
406 &gnutls_module);
407 if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
408 continue;
409 }
410#if MOD_GNUTLS_DEBUG
411 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
412 ctxt->c->base_server,
413 "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X sc: 0x%08X", tsc->cert_cn, rv,
414 gnutls_pk_algorithm_get_name(gnutls_x509_privkey_get_pk_algorithm(ctxt->sc->privkey_x509)),
415 (unsigned int)s, (unsigned int)s->next, (unsigned int)tsc);
416#endif
417 /* The CN can contain a * -- this will match those too. */
418 if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) {
419 /* found a match */
420 ret->cert.x509 = &tsc->cert_x509;
421 ret->key.x509 = tsc->privkey_x509;
422#if MOD_GNUTLS_DEBUG
423 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
424 ctxt->c->base_server,
425 "GnuTLS: Virtual Host: "
426 "'%s' == '%s'", tsc->cert_cn, sni_name);
427#endif
428 ctxt->sc = tsc;
429 gnutls_certificate_server_set_request(ctxt->session, ctxt->sc->client_verify_mode);
430 return 0;
431 }
432 }
433#endif
434
435 /**
436 * If the client does not support the Server Name Indication, give the default
437 * certificate for this server.
438 */
439use_default_crt:
440 ret->cert.x509 = &ctxt->sc->cert_x509;
441 ret->key.x509 = ctxt->sc->privkey_x509;
442#if MOD_GNUTLS_DEBUG
443 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
444 ctxt->c->base_server,
445 "GnuTLS: Using Default Certificate.");
446#endif
447 return 0;
448}
449
450static mgs_handle_t* create_gnutls_handle(apr_pool_t* pool, conn_rec * c)
451{
452 mgs_handle_t *ctxt;
453 mgs_srvconf_rec *sc =
454 (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
455 module_config,
456 &gnutls_module);
457
458 ctxt = apr_pcalloc(pool, sizeof(*ctxt));
459 ctxt->c = c;
460 ctxt->sc = sc;
461 ctxt->status = 0;
462
463 ctxt->input_rc = APR_SUCCESS;
464 ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc);
465 ctxt->input_cbuf.length = 0;
466
467 ctxt->output_rc = APR_SUCCESS;
468 ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc);
469 ctxt->output_blen = 0;
470 ctxt->output_length = 0;
471
472 gnutls_init(&ctxt->session, GNUTLS_SERVER);
473
474 gnutls_protocol_set_priority(ctxt->session, sc->protocol);
475 gnutls_cipher_set_priority(ctxt->session, sc->ciphers);
476 gnutls_compression_set_priority(ctxt->session, sc->compression);
477 gnutls_kx_set_priority(ctxt->session, sc->key_exchange);
478 gnutls_mac_set_priority(ctxt->session, sc->macs);
479 gnutls_certificate_type_set_priority(ctxt->session, sc->cert_types);
480
481 mgs_cache_session_init(ctxt);
482
483 gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
484
485 gnutls_certificate_server_set_retrieve_function(sc->certs, cert_retrieve_fn);
486 gnutls_certificate_server_set_request(ctxt->session, ctxt->sc->client_verify_mode);
487 return ctxt;
488}
489
490int mgs_hook_pre_connection(conn_rec * c, void *csd)
491{
492 mgs_handle_t *ctxt;
493 mgs_srvconf_rec *sc =
494 (mgs_srvconf_rec *) ap_get_module_config(c->base_server->
495 module_config,
496 &gnutls_module);
497
498 if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) {
499 return DECLINED;
500 }
501
502 ctxt = create_gnutls_handle(c->pool, c);
503
504 ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
505
506 gnutls_transport_set_pull_function(ctxt->session,
507 mgs_transport_read);
508 gnutls_transport_set_push_function(ctxt->session,
509 mgs_transport_write);
510 gnutls_transport_set_ptr(ctxt->session, ctxt);
511
512 ctxt->input_filter = ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt,
513 NULL, c);
514 ctxt->output_filter = ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt,
515 NULL, c);
516
517 return OK;
518}
519
520int mgs_hook_fixups(request_rec *r)
521{
522 unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
523 char buf[GNUTLS_SESSION_ID_STRING_LEN];
524 const char* tmp;
525 int len;
526 mgs_handle_t *ctxt;
527 apr_table_t *env = r->subprocess_env;
528
529 ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module);
530
531 if(!ctxt) {
532 return DECLINED;
533 }
534
535 apr_table_setn(env, "HTTPS", "on");
536
537 apr_table_setn(env, "GNUTLS_VERSION_INTERFACE", MOD_GNUTLS_VERSION);
538 apr_table_setn(env, "GNUTLS_VERSION_LIBRARY", LIBGNUTLS_VERSION);
539
540 apr_table_setn(env, "SSL_PROTOCOL",
541 gnutls_protocol_get_name(gnutls_protocol_get_version(ctxt->session)));
542
543 apr_table_setn(env, "SSL_CIPHER",
544 gnutls_cipher_get_name(gnutls_cipher_get(ctxt->session)));
545
546 apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE");
547
548 tmp = apr_psprintf(r->pool, "%d",
549 8 * gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session)));
550
551 apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp);
552
553 apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp);
554
555 len = sizeof(sbuf);
556 gnutls_session_get_id(ctxt->session, sbuf, &len);
557 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf));
558 apr_table_setn(env, "SSL_SESSION_ID", tmp);
559
560 return OK;
561}
562
563int mgs_hook_authz(request_rec *r)
564{
565 int rv;
566 int status;
567 mgs_handle_t *ctxt;
568 mgs_dirconf_rec *dc = ap_get_module_config(r->per_dir_config,
569 &gnutls_module);
570
571 ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module);
572
573 if (!ctxt) {
574 return DECLINED;
575 }
576
577 if (!dc) {
578 dc = mgs_config_dir_create(r->pool, NULL);
579 }
580
581 if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) {
582 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
583 "GnuTLS: Directory set to Ignore Client Certificate!");
584 return DECLINED;
585 }
586
587 if (ctxt->sc->client_verify_mode < dc->client_verify_mode) {
588 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
589 "GnuTLS: Attempting to rehandshake with peer. %d %d",
590 ctxt->sc->client_verify_mode, dc->client_verify_mode);
591
592 gnutls_certificate_server_set_request(ctxt->session,
593 dc->client_verify_mode);
594
595 if (mgs_rehandshake(ctxt) != 0) {
596 return HTTP_FORBIDDEN;
597 }
598 }
599 else if (ctxt->sc->client_verify_mode == GNUTLS_CERT_IGNORE) {
600#if MOD_GNUTLS_DEBUG
601 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
602 "GnuTLS: Peer is set to IGNORE");
603#endif
604 return DECLINED;
605 }
606
607 rv = gnutls_certificate_verify_peers2(ctxt->session, &status);
608
609 if (rv < 0) {
610 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
611 "GnuTLS: Failed to Verify Peer: (%d) %s",
612 rv, gnutls_strerror(rv));
613 return HTTP_FORBIDDEN;
614 }
615
616 if (status < 0) {
617 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
618 "GnuTLS: Peer Status is invalid.");
619 return HTTP_FORBIDDEN;
620 }
621
622 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
623 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
624 "GnuTLS: Could not find Signer for Peer Certificate");
625 }
626
627 if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
628 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
629 "GnuTLS: Could not find CA for Peer Certificate");
630 }
631
632 if (status & GNUTLS_CERT_INVALID) {
633 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
634 "GnuTLS: Peer Certificate is invalid.");
635 return HTTP_FORBIDDEN;
636 }
637 else if (status & GNUTLS_CERT_REVOKED) {
638 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
639 "GnuTLS: Peer Certificate is revoked.");
640 return HTTP_FORBIDDEN;
641 }
642
643 /* TODO: OpenPGP Certificates */
644 if (gnutls_certificate_type_get(ctxt->session) != GNUTLS_CRT_X509) {
645 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
646 "GnuTLS: Only x509 is supported for client certificates");
647 return HTTP_FORBIDDEN;
648 }
649 /* TODO: Further Verification. */
650 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
651 "GnuTLS: Verified Peer.");
652 return OK;
653}
654
diff --git a/src/gnutls_io.c b/src/gnutls_io.c
index dee2c4f..acb6095 100644
--- a/src/gnutls_io.c
+++ b/src/gnutls_io.c
@@ -35,7 +35,7 @@ static apr_status_t gnutls_io_filter_error(ap_filter_t * f,
35 apr_bucket_brigade * bb, 35 apr_bucket_brigade * bb,
36 apr_status_t status) 36 apr_status_t status)
37{ 37{
38 mod_gnutls_handle_t *ctxt = (mod_gnutls_handle_t *) f->ctx; 38 mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx;
39 apr_bucket *bucket; 39 apr_bucket *bucket;
40 40
41 switch (status) { 41 switch (status) {
@@ -63,7 +63,7 @@ static apr_status_t gnutls_io_filter_error(ap_filter_t * f,
63 return APR_SUCCESS; 63 return APR_SUCCESS;
64} 64}
65 65
66static int char_buffer_read(mod_gnutls_char_buffer_t * buffer, char *in, 66static int char_buffer_read(mgs_char_buffer_t * buffer, char *in,
67 int inl) 67 int inl)
68{ 68{
69 if (!buffer->length) { 69 if (!buffer->length) {
@@ -87,7 +87,7 @@ static int char_buffer_read(mod_gnutls_char_buffer_t * buffer, char *in,
87 return inl; 87 return inl;
88} 88}
89 89
90static int char_buffer_write(mod_gnutls_char_buffer_t * buffer, char *in, 90static int char_buffer_write(mgs_char_buffer_t * buffer, char *in,
91 int inl) 91 int inl)
92{ 92{
93 buffer->value = in; 93 buffer->value = in;
@@ -181,7 +181,7 @@ static apr_status_t brigade_consume(apr_bucket_brigade * bb,
181} 181}
182 182
183 183
184static apr_status_t gnutls_io_input_read(mod_gnutls_handle_t * ctxt, 184static apr_status_t gnutls_io_input_read(mgs_handle_t * ctxt,
185 char *buf, apr_size_t * len) 185 char *buf, apr_size_t * len)
186{ 186{
187 apr_size_t wanted = *len; 187 apr_size_t wanted = *len;
@@ -310,7 +310,7 @@ static apr_status_t gnutls_io_input_read(mod_gnutls_handle_t * ctxt,
310 return ctxt->input_rc; 310 return ctxt->input_rc;
311} 311}
312 312
313static apr_status_t gnutls_io_input_getline(mod_gnutls_handle_t * ctxt, 313static apr_status_t gnutls_io_input_getline(mgs_handle_t * ctxt,
314 char *buf, apr_size_t * len) 314 char *buf, apr_size_t * len)
315{ 315{
316 const char *pos = NULL; 316 const char *pos = NULL;
@@ -353,7 +353,7 @@ static apr_status_t gnutls_io_input_getline(mod_gnutls_handle_t * ctxt,
353 return APR_SUCCESS; 353 return APR_SUCCESS;
354} 354}
355 355
356static int gnutls_do_handshake(mod_gnutls_handle_t * ctxt) 356static int gnutls_do_handshake(mgs_handle_t * ctxt)
357{ 357{
358 int ret; 358 int ret;
359 int errcode; 359 int errcode;
@@ -403,7 +403,7 @@ tryagain:
403 } 403 }
404} 404}
405 405
406int mod_gnutls_rehandshake(mod_gnutls_handle_t * ctxt) 406int mgs_rehandshake(mgs_handle_t * ctxt)
407{ 407{
408 int rv; 408 int rv;
409 409
@@ -424,14 +424,14 @@ int mod_gnutls_rehandshake(mod_gnutls_handle_t * ctxt)
424} 424}
425 425
426 426
427apr_status_t mod_gnutls_filter_input(ap_filter_t* f, 427apr_status_t mgs_filter_input(ap_filter_t* f,
428 apr_bucket_brigade * bb, 428 apr_bucket_brigade * bb,
429 ap_input_mode_t mode, 429 ap_input_mode_t mode,
430 apr_read_type_e block, 430 apr_read_type_e block,
431 apr_off_t readbytes) 431 apr_off_t readbytes)
432{ 432{
433 apr_status_t status = APR_SUCCESS; 433 apr_status_t status = APR_SUCCESS;
434 mod_gnutls_handle_t *ctxt = (mod_gnutls_handle_t *) f->ctx; 434 mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx;
435 apr_size_t len = sizeof(ctxt->input_buffer); 435 apr_size_t len = sizeof(ctxt->input_buffer);
436 436
437 if (f->c->aborted) { 437 if (f->c->aborted) {
@@ -488,12 +488,12 @@ apr_status_t mod_gnutls_filter_input(ap_filter_t* f,
488 return status; 488 return status;
489} 489}
490 490
491apr_status_t mod_gnutls_filter_output(ap_filter_t * f, 491apr_status_t mgs_filter_output(ap_filter_t * f,
492 apr_bucket_brigade * bb) 492 apr_bucket_brigade * bb)
493{ 493{
494 apr_size_t ret; 494 apr_size_t ret;
495 apr_bucket* e; 495 apr_bucket* e;
496 mod_gnutls_handle_t *ctxt = (mod_gnutls_handle_t *) f->ctx; 496 mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx;
497 apr_status_t status = APR_SUCCESS; 497 apr_status_t status = APR_SUCCESS;
498 apr_read_type_e rblock = APR_NONBLOCK_READ; 498 apr_read_type_e rblock = APR_NONBLOCK_READ;
499 499
@@ -592,10 +592,10 @@ apr_status_t mod_gnutls_filter_output(ap_filter_t * f,
592 return status; 592 return status;
593} 593}
594 594
595ssize_t mod_gnutls_transport_read(gnutls_transport_ptr_t ptr, 595ssize_t mgs_transport_read(gnutls_transport_ptr_t ptr,
596 void *buffer, size_t len) 596 void *buffer, size_t len)
597{ 597{
598 mod_gnutls_handle_t *ctxt = ptr; 598 mgs_handle_t *ctxt = ptr;
599 apr_status_t rc; 599 apr_status_t rc;
600 apr_size_t in = len; 600 apr_size_t in = len;
601 apr_read_type_e block = ctxt->input_block; 601 apr_read_type_e block = ctxt->input_block;
@@ -659,7 +659,7 @@ ssize_t mod_gnutls_transport_read(gnutls_transport_ptr_t ptr,
659} 659}
660 660
661 661
662static ssize_t write_flush(mod_gnutls_handle_t * ctxt) 662static ssize_t write_flush(mgs_handle_t * ctxt)
663{ 663{
664 apr_bucket *e; 664 apr_bucket *e;
665 665
@@ -691,10 +691,10 @@ static ssize_t write_flush(mod_gnutls_handle_t * ctxt)
691 return (ctxt->output_rc == APR_SUCCESS) ? 1 : -1; 691 return (ctxt->output_rc == APR_SUCCESS) ? 1 : -1;
692} 692}
693 693
694ssize_t mod_gnutls_transport_write(gnutls_transport_ptr_t ptr, 694ssize_t mgs_transport_write(gnutls_transport_ptr_t ptr,
695 const void *buffer, size_t len) 695 const void *buffer, size_t len)
696{ 696{
697 mod_gnutls_handle_t *ctxt = ptr; 697 mgs_handle_t *ctxt = ptr;
698 698
699 /* pass along the encrypted data 699 /* pass along the encrypted data
700 * need to flush since we're using SSL's malloc-ed buffer 700 * need to flush since we're using SSL's malloc-ed buffer
diff --git a/src/mod_gnutls.c b/src/mod_gnutls.c
index fbcbc52..a2c36ee 100644
--- a/src/mod_gnutls.c
+++ b/src/mod_gnutls.c
@@ -16,676 +16,45 @@
16 */ 16 */
17 17
18#include "mod_gnutls.h" 18#include "mod_gnutls.h"
19#include "http_vhost.h"
20 19
21extern server_rec *ap_server_conf;
22
23#if APR_HAS_THREADS
24GCRY_THREAD_OPTION_PTHREAD_IMPL;
25#endif
26
27#if MOD_GNUTLS_DEBUG
28static apr_file_t* debug_log_fp;
29#endif
30
31static apr_status_t mod_gnutls_cleanup_pre_config(void *data)
32{
33 gnutls_global_deinit();
34 return APR_SUCCESS;
35}
36
37#if MOD_GNUTLS_DEBUG
38static void gnutls_debug_log_all( int level, const char* str)
39{
40 apr_file_printf(debug_log_fp, "<%d> %s\n", level, str);
41}
42#endif
43
44static int mod_gnutls_hook_pre_config(apr_pool_t * pconf,
45 apr_pool_t * plog, apr_pool_t * ptemp)
46{
47
48#if APR_HAS_THREADS
49 /* TODO: Check MPM Type here */
50 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
51#endif
52
53 gnutls_global_init();
54
55 apr_pool_cleanup_register(pconf, NULL, mod_gnutls_cleanup_pre_config,
56 apr_pool_cleanup_null);
57
58#if MOD_GNUTLS_DEBUG
59 apr_file_open(&debug_log_fp, "/tmp/gnutls_debug",
60 APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, pconf);
61
62 gnutls_global_set_log_level(9);
63 gnutls_global_set_log_function(gnutls_debug_log_all);
64#endif
65
66 return OK;
67}
68
69
70static gnutls_datum load_params(const char* file, server_rec* s,
71 apr_pool_t* pool)
72{
73 gnutls_datum ret = { NULL, 0 };
74 apr_file_t* fp;
75 apr_finfo_t finfo;
76 apr_status_t rv;
77 apr_size_t br = 0;
78
79 rv = apr_file_open(&fp, file, APR_READ|APR_BINARY, APR_OS_DEFAULT,
80 pool);
81 if (rv != APR_SUCCESS) {
82 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
83 "GnuTLS failed to load params file at: %s", file);
84 return ret;
85 }
86
87 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
88
89 if (rv != APR_SUCCESS) {
90 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
91 "GnuTLS failed to stat params file at: %s", file);
92 return ret;
93 }
94
95 ret.data = apr_palloc(pool, finfo.size+1);
96 rv = apr_file_read_full(fp, ret.data, finfo.size, &br);
97
98 if (rv != APR_SUCCESS) {
99 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
100 "GnuTLS failed to read params file at: %s", file);
101 return ret;
102 }
103 apr_file_close(fp);
104 ret.data[br] = '\0';
105 ret.size = br;
106
107 return ret;
108}
109
110static int mod_gnutls_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
111 apr_pool_t * ptemp,
112 server_rec * base_server)
113{
114 int rv;
115 int data_len;
116 server_rec *s;
117 gnutls_dh_params_t dh_params;
118 gnutls_rsa_params_t rsa_params;
119 mod_gnutls_srvconf_rec *sc;
120 mod_gnutls_srvconf_rec *sc_base;
121 void *data = NULL;
122 int first_run = 0;
123 const char *userdata_key = "mod_gnutls_init";
124
125 apr_pool_userdata_get(&data, userdata_key, base_server->process->pool);
126 if (data == NULL) {
127 first_run = 1;
128 apr_pool_userdata_set((const void *)1, userdata_key,
129 apr_pool_cleanup_null,
130 base_server->process->pool);
131 }
132
133
134 {
135 gnutls_datum pdata;
136 apr_pool_t* tpool;
137 s = base_server;
138 sc_base = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config,
139 &gnutls_module);
140
141 apr_pool_create(&tpool, p);
142
143 gnutls_dh_params_init(&dh_params);
144
145 pdata = load_params(sc_base->dh_params_file, s, tpool);
146
147 if (pdata.size != 0) {
148 rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata,
149 GNUTLS_X509_FMT_PEM);
150 if (rv != 0) {
151 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
152 "GnuTLS: Unable to load DH Params: (%d) %s",
153 rv, gnutls_strerror(rv));
154 exit(rv);
155 }
156 }
157 else {
158 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
159 "GnuTLS: Unable to load DH Params."
160 " Shutting Down.");
161 exit(-1);
162 }
163 apr_pool_clear(tpool);
164
165 gnutls_rsa_params_init(&rsa_params);
166
167 pdata = load_params(sc_base->rsa_params_file, s, tpool);
168
169 if (pdata.size != 0) {
170 rv = gnutls_rsa_params_import_pkcs1(rsa_params, &pdata,
171 GNUTLS_X509_FMT_PEM);
172 if (rv != 0) {
173 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
174 "GnuTLS: Unable to load RSA Params: (%d) %s",
175 rv, gnutls_strerror(rv));
176 exit(rv);
177 }
178 }
179 else {
180 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
181 "GnuTLS: Unable to load RSA Params."
182 " Shutting Down.");
183 exit(-1);
184 }
185
186 apr_pool_destroy(tpool);
187 rv = mod_gnutls_cache_post_config(p, s, sc_base);
188 if (rv != 0) {
189 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
190 "GnuTLS: Post Config for GnuTLSCache Failed."
191 " Shutting Down.");
192 exit(-1);
193 }
194
195 for (s = base_server; s; s = s->next) {
196 sc = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config,
197 &gnutls_module);
198 sc->cache_type = sc_base->cache_type;
199 sc->cache_config = sc_base->cache_config;
200
201 gnutls_certificate_set_rsa_export_params(sc->certs,
202 rsa_params);
203 gnutls_certificate_set_dh_params(sc->certs, dh_params);
204
205 if (sc->cert_x509 == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
206 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
207 "[GnuTLS] - Host '%s:%d' is missing a "
208 "Certificate File!",
209 s->server_hostname, s->port);
210 exit(-1);
211 }
212
213 if (sc->privkey_x509 == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
214 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
215 "[GnuTLS] - Host '%s:%d' is missing a "
216 "Private Key File!",
217 s->server_hostname, s->port);
218 exit(-1);
219 }
220
221 rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509,
222 GNUTLS_OID_X520_COMMON_NAME, 0, 0,
223 NULL, &data_len);
224
225 if (data_len < 1) {
226 sc->enabled = GNUTLS_ENABLED_FALSE;
227 sc->cert_cn = NULL;
228 continue;
229 }
230
231 sc->cert_cn = apr_palloc(p, data_len);
232 rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509,
233 GNUTLS_OID_X520_COMMON_NAME, 0, 0,
234 sc->cert_cn, &data_len);
235 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
236 s,
237 "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X sc: 0x%08X", sc->cert_cn, rv,
238 gnutls_pk_algorithm_get_name(gnutls_x509_privkey_get_pk_algorithm(sc->privkey_x509)),
239 (unsigned int)s, (unsigned int)sc);
240 }
241 }
242
243 ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION);
244
245 return OK;
246}
247
248static void mod_gnutls_hook_child_init(apr_pool_t *p, server_rec *s)
249{
250 apr_status_t rv = APR_SUCCESS;
251 mod_gnutls_srvconf_rec *sc = ap_get_module_config(s->module_config,
252 &gnutls_module);
253
254 if (sc->cache_type != mod_gnutls_cache_none) {
255 rv = mod_gnutls_cache_child_init(p, s, sc);
256 if(rv != APR_SUCCESS) {
257 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
258 "[GnuTLS] - Failed to run Cache Init");
259 }
260 }
261 else {
262 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
263 "[GnuTLS] - No Cache Configured. Hint: GnuTLSCache");
264 }
265}
266
267static const char *mod_gnutls_hook_http_scheme(const request_rec * r)
268{
269 mod_gnutls_srvconf_rec *sc =
270 (mod_gnutls_srvconf_rec *) ap_get_module_config(r->server->
271 module_config,
272 &gnutls_module);
273
274 if (sc->enabled == GNUTLS_ENABLED_FALSE) {
275 return NULL;
276 }
277
278 return "https";
279}
280
281static apr_port_t mod_gnutls_hook_default_port(const request_rec * r)
282{
283 mod_gnutls_srvconf_rec *sc =
284 (mod_gnutls_srvconf_rec *) ap_get_module_config(r->server->
285 module_config,
286 &gnutls_module);
287
288 if (sc->enabled == GNUTLS_ENABLED_FALSE) {
289 return 0;
290 }
291
292 return 443;
293}
294
295#define MAX_HOST_LEN 255
296
297#if USING_2_1_RECENT
298typedef struct
299{
300 mod_gnutls_handle_t *ctxt;
301 gnutls_retr_st* ret;
302 const char* sni_name;
303} vhost_cb_rec;
304
305int vhost_cb (void* baton, conn_rec* conn, server_rec* s)
306{
307 mod_gnutls_srvconf_rec *tsc;
308 vhost_cb_rec* x = baton;
309
310 tsc = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config,
311 &gnutls_module);
312
313 if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) {
314 return 0;
315 }
316
317 /* The CN can contain a * -- this will match those too. */
318 if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) {
319 /* found a match */
320 x->ret->cert.x509 = &tsc->cert_x509;
321 x->ret->key.x509 = tsc->privkey_x509;
322#if MOD_GNUTLS_DEBUG
323 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
324 x->ctxt->c->base_server,
325 "GnuTLS: Virtual Host CB: "
326 "'%s' == '%s'", tsc->cert_cn, x->sni_name);
327#endif
328 /* Because we actually change the server used here, we need to reset
329 * things like ClientVerify.
330 */
331 x->ctxt->sc = tsc;
332 /* Shit. Crap. Dammit. We *really* should rehandshake here, as our
333 * certificate structure *should* change when the server changes.
334 * acccckkkkkk.
335 */
336 gnutls_certificate_server_set_request(x->ctxt->session, x->ctxt->sc->client_verify_mode);
337 return 1;
338 }
339 return 0;
340}
341#endif
342
343static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st* ret)
344{
345 int rv;
346 int sni_type;
347 int data_len = MAX_HOST_LEN;
348 char sni_name[MAX_HOST_LEN];
349 mod_gnutls_handle_t *ctxt;
350#if USING_2_1_RECENT
351 vhost_cb_rec cbx;
352#else
353 server_rec* s;
354 mod_gnutls_srvconf_rec *tsc;
355#endif
356
357 ctxt = gnutls_transport_get_ptr(session);
358
359 sni_type = gnutls_certificate_type_get(session);
360 if (sni_type != GNUTLS_CRT_X509) {
361 /* In theory, we could support OpenPGP Certificates. Theory != code. */
362 ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
363 ctxt->c->base_server,
364 "GnuTLS: Only x509 Certificates are currently supported.");
365 return -1;
366 }
367
368 ret->type = GNUTLS_CRT_X509;
369 ret->ncerts = 1;
370 ret->deinit_all = 0;
371
372 rv = gnutls_server_name_get(ctxt->session, sni_name,
373 &data_len, &sni_type, 0);
374
375 if (rv != 0) {
376 goto use_default_crt;
377 }
378
379 if (sni_type != GNUTLS_NAME_DNS) {
380 ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
381 ctxt->c->base_server,
382 "GnuTLS: Unknown type '%d' for SNI: "
383 "'%s'", sni_type, sni_name);
384 goto use_default_crt;
385 }
386
387 /**
388 * Code in the Core already sets up the c->base_server as the base
389 * for this IP/Port combo. Trust that the core did the 'right' thing.
390 */
391#if USING_2_1_RECENT
392 cbx.ctxt = ctxt;
393 cbx.ret = ret;
394 cbx.sni_name = sni_name;
395
396 rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
397 if (rv == 1) {
398 return 0;
399 }
400#else
401 for (s = ap_server_conf; s; s = s->next) {
402
403 tsc = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config,
404 &gnutls_module);
405 if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
406 continue;
407 }
408#if MOD_GNUTLS_DEBUG
409 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
410 ctxt->c->base_server,
411 "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X sc: 0x%08X", tsc->cert_cn, rv,
412 gnutls_pk_algorithm_get_name(gnutls_x509_privkey_get_pk_algorithm(ctxt->sc->privkey_x509)),
413 (unsigned int)s, (unsigned int)s->next, (unsigned int)tsc);
414#endif
415 /* The CN can contain a * -- this will match those too. */
416 if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) {
417 /* found a match */
418 ret->cert.x509 = &tsc->cert_x509;
419 ret->key.x509 = tsc->privkey_x509;
420#if MOD_GNUTLS_DEBUG
421 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
422 ctxt->c->base_server,
423 "GnuTLS: Virtual Host: "
424 "'%s' == '%s'", tsc->cert_cn, sni_name);
425#endif
426 ctxt->sc = tsc;
427 gnutls_certificate_server_set_request(ctxt->session, ctxt->sc->client_verify_mode);
428 return 0;
429 }
430 }
431#endif
432
433 /**
434 * If the client does not support the Server Name Indication, give the default
435 * certificate for this server.
436 */
437use_default_crt:
438 ret->cert.x509 = &ctxt->sc->cert_x509;
439 ret->key.x509 = ctxt->sc->privkey_x509;
440#if MOD_GNUTLS_DEBUG
441 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
442 ctxt->c->base_server,
443 "GnuTLS: Using Default Certificate.");
444#endif
445 return 0;
446}
447
448static mod_gnutls_handle_t* create_gnutls_handle(apr_pool_t* pool, conn_rec * c)
449{
450 mod_gnutls_handle_t *ctxt;
451 mod_gnutls_srvconf_rec *sc =
452 (mod_gnutls_srvconf_rec *) ap_get_module_config(c->base_server->
453 module_config,
454 &gnutls_module);
455
456 ctxt = apr_pcalloc(pool, sizeof(*ctxt));
457 ctxt->c = c;
458 ctxt->sc = sc;
459 ctxt->status = 0;
460
461 ctxt->input_rc = APR_SUCCESS;
462 ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc);
463 ctxt->input_cbuf.length = 0;
464
465 ctxt->output_rc = APR_SUCCESS;
466 ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc);
467 ctxt->output_blen = 0;
468 ctxt->output_length = 0;
469
470 gnutls_init(&ctxt->session, GNUTLS_SERVER);
471
472 gnutls_protocol_set_priority(ctxt->session, sc->protocol);
473 gnutls_cipher_set_priority(ctxt->session, sc->ciphers);
474 gnutls_compression_set_priority(ctxt->session, sc->compression);
475 gnutls_kx_set_priority(ctxt->session, sc->key_exchange);
476 gnutls_mac_set_priority(ctxt->session, sc->macs);
477 gnutls_certificate_type_set_priority(ctxt->session, sc->cert_types);
478
479 mod_gnutls_cache_session_init(ctxt);
480
481 gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
482
483 gnutls_certificate_server_set_retrieve_function(sc->certs, cert_retrieve_fn);
484 gnutls_certificate_server_set_request(ctxt->session, ctxt->sc->client_verify_mode);
485 return ctxt;
486}
487
488static int mod_gnutls_hook_pre_connection(conn_rec * c, void *csd)
489{
490 mod_gnutls_handle_t *ctxt;
491 mod_gnutls_srvconf_rec *sc =
492 (mod_gnutls_srvconf_rec *) ap_get_module_config(c->base_server->
493 module_config,
494 &gnutls_module);
495
496 if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) {
497 return DECLINED;
498 }
499
500 ctxt = create_gnutls_handle(c->pool, c);
501
502 ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
503
504 gnutls_transport_set_pull_function(ctxt->session,
505 mod_gnutls_transport_read);
506 gnutls_transport_set_push_function(ctxt->session,
507 mod_gnutls_transport_write);
508 gnutls_transport_set_ptr(ctxt->session, ctxt);
509
510 ctxt->input_filter = ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt,
511 NULL, c);
512 ctxt->output_filter = ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt,
513 NULL, c);
514
515 return OK;
516}
517
518static int mod_gnutls_hook_fixups(request_rec *r)
519{
520 unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
521 char buf[GNUTLS_SESSION_ID_STRING_LEN];
522 const char* tmp;
523 int len;
524 mod_gnutls_handle_t *ctxt;
525 apr_table_t *env = r->subprocess_env;
526
527 ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module);
528
529 if(!ctxt) {
530 return DECLINED;
531 }
532
533 apr_table_setn(env, "HTTPS", "on");
534
535 apr_table_setn(env, "GNUTLS_VERSION_INTERFACE", MOD_GNUTLS_VERSION);
536 apr_table_setn(env, "GNUTLS_VERSION_LIBRARY", LIBGNUTLS_VERSION);
537
538 apr_table_setn(env, "SSL_PROTOCOL",
539 gnutls_protocol_get_name(gnutls_protocol_get_version(ctxt->session)));
540
541 apr_table_setn(env, "SSL_CIPHER",
542 gnutls_cipher_get_name(gnutls_cipher_get(ctxt->session)));
543
544 apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE");
545
546 tmp = apr_psprintf(r->pool, "%d",
547 8 * gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session)));
548
549 apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp);
550
551 apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp);
552
553 len = sizeof(sbuf);
554 gnutls_session_get_id(ctxt->session, sbuf, &len);
555 tmp = mod_gnutls_session_id2sz(sbuf, len, buf, sizeof(buf));
556 apr_table_setn(env, "SSL_SESSION_ID", tmp);
557
558 return OK;
559}
560
561int mod_gnutls_hook_authz(request_rec *r)
562{
563 int rv;
564 int status;
565 mod_gnutls_handle_t *ctxt;
566 mod_gnutls_dirconf_rec *dc = ap_get_module_config(r->per_dir_config,
567 &gnutls_module);
568
569 ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module);
570
571 if (!ctxt) {
572 return DECLINED;
573 }
574
575 if (!dc) {
576 dc = mgs_config_dir_create(r->pool, NULL);
577 }
578
579 if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) {
580 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
581 "GnuTLS: Directory set to Ignore Client Certificate!");
582 return DECLINED;
583 }
584
585 if (ctxt->sc->client_verify_mode < dc->client_verify_mode) {
586 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
587 "GnuTLS: Attempting to rehandshake with peer. %d %d",
588 ctxt->sc->client_verify_mode, dc->client_verify_mode);
589
590 gnutls_certificate_server_set_request(ctxt->session,
591 dc->client_verify_mode);
592
593 if (mod_gnutls_rehandshake(ctxt) != 0) {
594 return HTTP_FORBIDDEN;
595 }
596 }
597 else if (ctxt->sc->client_verify_mode == GNUTLS_CERT_IGNORE) {
598#if MOD_GNUTLS_DEBUG
599 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
600 "GnuTLS: Peer is set to IGNORE");
601#endif
602 return DECLINED;
603 }
604
605 rv = gnutls_certificate_verify_peers2(ctxt->session, &status);
606
607 if (rv < 0) {
608 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
609 "GnuTLS: Failed to Verify Peer: (%d) %s",
610 rv, gnutls_strerror(rv));
611 return HTTP_FORBIDDEN;
612 }
613
614 if (status < 0) {
615 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
616 "GnuTLS: Peer Status is invalid.");
617 return HTTP_FORBIDDEN;
618 }
619
620 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
621 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
622 "GnuTLS: Could not find Signer for Peer Certificate");
623 }
624
625 if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
626 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
627 "GnuTLS: Could not find CA for Peer Certificate");
628 }
629
630 if (status & GNUTLS_CERT_INVALID) {
631 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
632 "GnuTLS: Peer Certificate is invalid.");
633 return HTTP_FORBIDDEN;
634 }
635 else if (status & GNUTLS_CERT_REVOKED) {
636 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
637 "GnuTLS: Peer Certificate is revoked.");
638 return HTTP_FORBIDDEN;
639 }
640
641 /* TODO: OpenPGP Certificates */
642 if (gnutls_certificate_type_get(ctxt->session) != GNUTLS_CRT_X509) {
643 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
644 "GnuTLS: Only x509 is supported for client certificates");
645 return HTTP_FORBIDDEN;
646 }
647 /* TODO: Further Verification. */
648 ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
649 "GnuTLS: Verified Peer.");
650 return OK;
651}
652 20
653static void gnutls_hooks(apr_pool_t * p) 21static void gnutls_hooks(apr_pool_t * p)
654{ 22{
655 ap_hook_pre_connection(mod_gnutls_hook_pre_connection, NULL, NULL, 23 ap_hook_pre_connection(mgs_hook_pre_connection, NULL, NULL,
656 APR_HOOK_MIDDLE); 24 APR_HOOK_MIDDLE);
657 ap_hook_post_config(mod_gnutls_hook_post_config, NULL, NULL, 25 ap_hook_post_config(mgs_hook_post_config, NULL, NULL,
658 APR_HOOK_MIDDLE);
659 ap_hook_child_init(mod_gnutls_hook_child_init, NULL, NULL,
660 APR_HOOK_MIDDLE); 26 APR_HOOK_MIDDLE);
27 ap_hook_child_init(mgs_hook_child_init, NULL, NULL,
28 APR_HOOK_MIDDLE);
661#if USING_2_1_RECENT 29#if USING_2_1_RECENT
662 ap_hook_http_scheme(mod_gnutls_hook_http_scheme, NULL, NULL, 30 ap_hook_http_scheme(mgs_hook_http_scheme, NULL, NULL,
663 APR_HOOK_MIDDLE); 31 APR_HOOK_MIDDLE);
664#else 32#else
665 ap_hook_http_method(mod_gnutls_hook_http_scheme, NULL, NULL, 33 ap_hook_http_method(mgs_hook_http_scheme, NULL, NULL,
666 APR_HOOK_MIDDLE); 34 APR_HOOK_MIDDLE);
667#endif 35#endif
668 ap_hook_default_port(mod_gnutls_hook_default_port, NULL, NULL, 36 ap_hook_default_port(mgs_hook_default_port, NULL, NULL,
669 APR_HOOK_MIDDLE); 37 APR_HOOK_MIDDLE);
670 ap_hook_pre_config(mod_gnutls_hook_pre_config, NULL, NULL, 38 ap_hook_pre_config(mgs_hook_pre_config, NULL, NULL,
671 APR_HOOK_MIDDLE); 39 APR_HOOK_MIDDLE);
672 40
673 ap_hook_access_checker(mod_gnutls_hook_authz, NULL, NULL, APR_HOOK_REALLY_FIRST); 41 ap_hook_access_checker(mgs_hook_authz, NULL, NULL, APR_HOOK_REALLY_FIRST);
674 42
675 ap_hook_fixups(mod_gnutls_hook_fixups, NULL, NULL, APR_HOOK_REALLY_FIRST); 43 ap_hook_fixups(mgs_hook_fixups, NULL, NULL, APR_HOOK_REALLY_FIRST);
676 44
677 /* TODO: HTTP Upgrade Filter */ 45 /* TODO: HTTP Upgrade Filter */
678 /* ap_register_output_filter ("UPGRADE_FILTER", 46 /* ap_register_output_filter ("UPGRADE_FILTER",
679 * ssl_io_filter_Upgrade, NULL, AP_FTYPE_PROTOCOL + 5); 47 * ssl_io_filter_Upgrade, NULL, AP_FTYPE_PROTOCOL + 5);
680 */ 48*/
681 ap_register_input_filter(GNUTLS_INPUT_FILTER_NAME, 49 ap_register_input_filter(GNUTLS_INPUT_FILTER_NAME,
682 mod_gnutls_filter_input, NULL, 50 mgs_filter_input, NULL,
683 AP_FTYPE_CONNECTION + 5); 51 AP_FTYPE_CONNECTION + 5);
684 ap_register_output_filter(GNUTLS_OUTPUT_FILTER_NAME, 52 ap_register_output_filter(GNUTLS_OUTPUT_FILTER_NAME,
685 mod_gnutls_filter_output, NULL, 53 mgs_filter_output, NULL,
686 AP_FTYPE_CONNECTION + 5); 54 AP_FTYPE_CONNECTION + 5);
687} 55}
688 56
57
689static const command_rec mgs_config_cmds[] = { 58static const command_rec mgs_config_cmds[] = {
690 AP_INIT_TAKE1("GnuTLSClientVerify", mgs_set_client_verify, 59 AP_INIT_TAKE1("GnuTLSClientVerify", mgs_set_client_verify,
691 NULL, 60 NULL,