diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mod_gnutls.c | 169 |
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 | ||||
73 | static apr_status_t gnutls_filter_input(ap_filter_t * f, | 71 | static apr_status_t gnutls_filter_input(ap_filter_t * f, | ||
74 | apr_bucket_brigade * bb, | 72 | apr_bucket_brigade * bb, | ||
7 | 2008-10-01 | ||||
| | |||||
* | updated README file to account for openpgp keys --patch by Jack Bates | tpd/mod_gnutls/tree/src/mod_gnutls.c?id=6a8a8396ceed9fb87a6586ebcb144b5f4b62a39a#n85'>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 | |||||
91 | static apr_status_t gnutls_filter_output(ap_filter_t * f, | 103 | static 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 | |||||
120 | static apr_status_t gnutls_cleanup_pre_config(void *data) | 213 | static 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 | ||||
350 | static int gnutls_hook_pre_connection(conn_rec * c, void *csd) | 441 | static 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 | ||||
512 | static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s) | 571 | static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s) | ||