summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
-rw-r--r--src/mod_gnutls.c169
1 files changed, 114 insertions, 55 deletions
diff --git a/src/mod_gnutls.c b/src/mod_gnutls.c
index e9ad89c..e696ec6 100644
--- a/src/mod_gnutls.c
+++ b/src/mod_gnutls.c
@@ -49,7 +49,6 @@ typedef struct {
49 char *key_file; 49 char *key_file;
50 char *cert_file; 50 char *cert_file;
51 int enabled; 51 int enabled;
52 int non_https;
53 int ciphers[16]; 52 int ciphers[16];
54 int key_exchange[16]; 53 int key_exchange[16];
55 int macs[16]; 54 int macs[16];
@@ -62,14 +61,13 @@ struct gnutls_handle_t
62{ 61{
63 gnutls_srvconf_rec *sc; 62 gnutls_srvconf_rec *sc;
64 gnutls_session_t session; 63 gnutls_session_t session;
65#ifdef GNUTLS_AS_FILTER
66 ap_filter_t *input_filter; 64 ap_filter_t *input_filter;
67 apr_bucket_brigade *input_bb; 65 apr_bucket_brigade *input_bb;
68 apr_read_type_e input_block; 66 apr_read_type_e input_block;
69#endif 67 int status;
68 int non_https;
70}; 69};
71 70
72#ifdef GNUTLS_AS_FILTER
73static apr_status_t gnutls_filter_input(ap_filter_t * f, 71static apr_status_t gnutls_filter_input(ap_filter_t * f,
74 apr_bucket_brigade * bb, 72 apr_bucket_brigade * bb,
75 ap_input_mode_t mode, 73 ap_input_mode_t mode,
@@ -85,38 +83,133 @@ static apr_status_t gnutls_filter_input(ap_filter_t * f,
85 return APR_ECONNABORTED; 83 return APR_ECONNABORTED;
86 } 84 }
87 85
86
87 for (b = APR_BRIGADE_FIRST(bb);
88 b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) {
89 if (APR_BUCKET_IS_EOS(b)) {
90 /* end of connection */
91 }
92 else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ)
93 == APR_SUCCESS) {
94 /* more data */
95 }
96 }
97
88 return status; 98 return status;
89} 99}
90 100
101#define HANDSHAKE_ATTEMPTS 10
102
91static apr_status_t gnutls_filter_output(ap_filter_t * f, 103static apr_status_t gnutls_filter_output(ap_filter_t * f,
92 apr_bucket_brigade * bb) 104 apr_bucket_brigade * bb)
93{ 105{
94 apr_bucket *b; 106 int ret, i;
95 const char *buf = 0; 107 const char *buf = 0;
96 apr_size_t bytes = 0; 108 apr_size_t bytes = 0;
97 gnutls_handle_t *ctxt = (gnutls_handle_t *) f->ctx; 109 gnutls_handle_t *ctxt = (gnutls_handle_t *) f->ctx;
98 apr_status_t status = APR_SUCCESS; 110 apr_status_t status = APR_SUCCESS;
111 apr_read_type_e rblock = APR_NONBLOCK_READ;
112
113 if (f->c->aborted) {
114 apr_brigade_cleanup(bb);
115 return APR_ECONNABORTED;
116 }
117
118 if(ctxt->status == 0) {
119 for (i=HANDSHAKE_ATTEMPTS; i>0; i--){
120 ret = gnutls_handshake(ctxt->session);
121
122 if(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN){
123 continue;
124 }
99 125
100 if (!ctxt) { 126 if (ret < 0) {
101 /* first run. */ 127 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
128 ret = gnutls_alert_get(ctxt->session);
129 ap_log_error(APLOG_MARK, APLOG_ERR, 0, f->c->base_server,
130 "GnuTLS: Hanshake Alert (%d) '%s'.\n", ret, gnutls_alert_get_name(ret));
131 }
132
133 if (gnutls_error_is_fatal(ret) != 0) {
134 gnutls_deinit(ctxt->session);
135 ap_log_error(APLOG_MARK, APLOG_ERR, 0, f->c->base_server,
136 "GnuTLS: Handshake Failed (%d) '%s'",ret, gnutls_strerror(ret));
137 ctxt->status = -1;
138 break;
139 }
140 }
141 else {
142 ctxt->status = 1;
143 break; /* all done with the handshake */
144 }
145 }
102 } 146 }
103 147
104 for (b = APR_BRIGADE_FIRST(bb); 148 if (ctxt->status < 0) {
105 b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) { 149 return ap_pass_brigade(f->next, bb);
106 if (APR_BUCKET_IS_EOS(b)) { 150 }
107 /* end of connection */ 151
152 while (!APR_BRIGADE_EMPTY(bb)) {
153 apr_bucket *bucket = APR_BRIGADE_FIRST(bb);
154 if (APR_BUCKET_IS_EOS(bucket) || APR_BUCKET_IS_FLUSH(bucket)) {
155 /** TODO: GnuTLS doesn't have a special flush method? **/
156 if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
157 return status;
158 }
159 break;
108 } 160 }
109 else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) 161 else if(AP_BUCKET_IS_EOC(bucket)) {
110 == APR_SUCCESS) { 162 gnutls_bye(ctxt->session, GNUTLS_SHUT_WR);
111 /* more data */ 163
164 if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
165 return status;
166 }
167 break;
168 }
169 else {
170 /* filter output */
171 const char *data;
172 apr_size_t len;
173
174 status = apr_bucket_read(bucket, &data, &len, rblock);
175
176 if (APR_STATUS_IS_EAGAIN(status)) {
177 rblock = APR_BLOCK_READ;
178 continue; /* and try again with a blocking read. */
179 }
180
181 rblock = APR_NONBLOCK_READ;
182
183 if (!APR_STATUS_IS_EOF(status) && (status != APR_SUCCESS)) {
184 break;
185 }
186
187 ret = gnutls_record_send(ctxt->session, data, len);
188 status = ssl_filter_write(f, data, len);
189 if(ret < 0) {
190 /* error sending output */
191 }
192 else if ((apr_size_t)res != len) {
193 /* not all of the data was sent. */
194 /* mod_ssl basicly errors out here.. this doesn't seem right? */
195 }
196 else {
197 /* send complete */
198
199 }
200
201 apr_bucket_delete(bucket);
202
203 if (status != APR_SUCCESS) {
204 break;
205 }
206
112 } 207 }
113 } 208 }
114 209
115 return status; 210 return status;
116} 211}
117 212
118#endif /* GNUTLS_AS_FILTER */
119
120static apr_status_t gnutls_cleanup_pre_config(void *data) 213static apr_status_t gnutls_cleanup_pre_config(void *data)
121{ 214{
122 gnutls_global_deinit(); 215 gnutls_global_deinit();
@@ -206,7 +299,6 @@ static apr_port_t gnutls_hook_default_port(const request_rec * r)
206 return 443; 299 return 443;
207} 300}
208 301
209#ifdef GNUTLS_AS_FILTER
210/** 302/**
211 * From mod_ssl / ssl_engine_io.c 303 * From mod_ssl / ssl_engine_io.c
212 * This function will read from a brigade and discard the read buckets as it 304 * This function will read from a brigade and discard the read buckets as it
@@ -345,14 +437,9 @@ static ssize_t gnutls_transport_write(gnutls_transport_ptr_t ptr,
345 //APR_BRIGADE_INSERT_TAIL(outctx->bb, bucket); 437 //APR_BRIGADE_INSERT_TAIL(outctx->bb, bucket);
346 return 0; 438 return 0;
347} 439}
348#endif /* GNUTLS_AS_FILTER */
349 440
350static int gnutls_hook_pre_connection(conn_rec * c, void *csd) 441static int gnutls_hook_pre_connection(conn_rec * c, void *csd)
351{ 442{
352#ifndef GNUTLS_AS_FILTER
353 int cfd;
354 int ret;
355#endif
356 gnutls_handle_t *ctxt; 443 gnutls_handle_t *ctxt;
357 gnutls_srvconf_rec *sc = 444 gnutls_srvconf_rec *sc =
358 (gnutls_srvconf_rec *) ap_get_module_config(c->base_server-> 445 (gnutls_srvconf_rec *) ap_get_module_config(c->base_server->
@@ -366,6 +453,7 @@ static int gnutls_hook_pre_connection(conn_rec * c, void *csd)
366 ctxt = apr_pcalloc(c->pool, sizeof(*ctxt)); 453 ctxt = apr_pcalloc(c->pool, sizeof(*ctxt));
367 454
368 ctxt->sc = sc; 455 ctxt->sc = sc;
456 ctxt->status = 0;
369 gnutls_init(&ctxt->session, GNUTLS_SERVER); 457 gnutls_init(&ctxt->session, GNUTLS_SERVER);
370 458
371 gnutls_cipher_set_priority(ctxt->session, sc->ciphers); 459 gnutls_cipher_set_priority(ctxt->session, sc->ciphers);
@@ -375,6 +463,10 @@ static int gnutls_hook_pre_connection(conn_rec * c, void *csd)
375 gnutls_mac_set_priority(ctxt->session, sc->macs); 463 gnutls_mac_set_priority(ctxt->session, sc->macs);
376 464
377 gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE, sc->certs); 465 gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE, sc->certs);
466// if(anon) {
467// gnutls_credentials_set(ctxt->session, GNUTLS_CRD_ANON, sc->anoncred);
468// }
469
378 gnutls_certificate_server_set_request(ctxt->session, GNUTLS_CERT_IGNORE); 470 gnutls_certificate_server_set_request(ctxt->session, GNUTLS_CERT_IGNORE);
379 471
380// gnutls_dh_set_prime_bits(ctxt->session, DH_BITS); 472// gnutls_dh_set_prime_bits(ctxt->session, DH_BITS);
@@ -382,43 +474,12 @@ static int gnutls_hook_pre_connection(conn_rec * c, void *csd)
382 474
383 ap_set_module_config(c->conn_config, &gnutls_module, ctxt); 475 ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
384 476
385#ifdef GNUTLS_AS_FILTER
386 gnutls_transport_set_pull_function(ctxt->session, gnutls_transport_read); 477 gnutls_transport_set_pull_function(ctxt->session, gnutls_transport_read);
387 gnutls_transport_set_push_function(ctxt->session, gnutls_transport_write); 478 gnutls_transport_set_push_function(ctxt->session, gnutls_transport_write);
388 gnutls_transport_set_ptr(ctxt->session, ctxt); 479 gnutls_transport_set_ptr(ctxt->session, ctxt);
389
390 ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c); 480 ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c);
391 ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c); 481 ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c);
392#else
393 apr_os_sock_get(&cfd, csd);
394 gnutls_transport_set_ptr(ctxt->session, (gnutls_transport_ptr)cfd);
395 gnutls_credentials_set(ctxt->session, GNUTLS_CRD_ANON, sc->anoncred);
396 482
397 do{
398 ret = gnutls_handshake(ctxt->session);
399
400 if(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN){
401 continue;
402 }
403
404 if (ret < 0) {
405 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
406 ret = gnutls_alert_get(ctxt->session);
407 ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server,
408 "GnuTLS: Hanshake Alert (%d) '%s'.\n", ret, gnutls_alert_get_name(ret));
409 }
410
411 if (gnutls_error_is_fatal(ret) != 0) {
412 gnutls_deinit(ctxt->session);
413 ap_log_error(APLOG_MARK, APLOG_ERR, 0, c->base_server,
414 "GnuTLS: Handshake Failed (%d) '%s'",ret, gnutls_strerror(ret));
415 sc->non_https = 1;
416 break;
417 }
418 }
419 break; /* all done with the handshake */
420 } while(1);
421#endif
422 return OK; 483 return OK;
423} 484}
424 485
@@ -501,12 +562,10 @@ static void gnutls_hooks(apr_pool_t * p)
501 /* ap_register_output_filter ("UPGRADE_FILTER", 562 /* ap_register_output_filter ("UPGRADE_FILTER",
502 * ssl_io_filter_Upgrade, NULL, AP_FTYPE_PROTOCOL + 5); 563 * ssl_io_filter_Upgrade, NULL, AP_FTYPE_PROTOCOL + 5);
503 */ 564 */
504#ifdef GNUTLS_AS_FILTER
505 ap_register_input_filter(GNUTLS_INPUT_FILTER_NAME, gnutls_filter_input, 565 ap_register_input_filter(GNUTLS_INPUT_FILTER_NAME, gnutls_filter_input,
506 NULL, AP_FTYPE_CONNECTION + 5); 566 NULL, AP_FTYPE_CONNECTION + 5);
507 ap_register_output_filter(GNUTLS_OUTPUT_FILTER_NAME, gnutls_filter_output, 567 ap_register_output_filter(GNUTLS_OUTPUT_FILTER_NAME, gnutls_filter_output,
508 NULL, AP_FTYPE_CONNECTION + 5); 568 NULL, AP_FTYPE_CONNECTION + 5);
509#endif
510} 569}
511 570
512static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s) 571static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s)