summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
-rw-r--r--include/mod_gnutls.h122
-rw-r--r--src/Makefile.am2
-rw-r--r--src/gnutls_io.c307
-rw-r--r--src/mod_gnutls.c385
4 files changed, 460 insertions, 356 deletions
diff --git a/include/mod_gnutls.h b/include/mod_gnutls.h
new file mode 100644
index 0000000..70e641f
--- /dev/null
+++ b/include/mod_gnutls.h
@@ -0,0 +1,122 @@
1/* ====================================================================
2 * Copyright 2004 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#ifndef __mod_gnutls_h_inc
19#define __mod_gnutls_h_inc
20
21#include "httpd.h"
22#include "http_config.h"
23#include "http_protocol.h"
24#include "http_connection.h"
25#include "http_core.h"
26#include "http_log.h"
27#include "apr_buckets.h"
28#include "apr_strings.h"
29#include "apr_tables.h"
30
31#include <gcrypt.h>
32#include <gnutls/gnutls.h>
33
34module AP_MODULE_DECLARE_DATA gnutls_module;
35
36#define GNUTLS_OUTPUT_FILTER_NAME "gnutls_output_filter"
37#define GNUTLS_INPUT_FILTER_NAME "gnutls_input_filter"
38
39#define GNUTLS_ENABLED_FALSE 0
40#define GNUTLS_ENABLED_TRUE 1
41
42
43typedef struct
44{
45 gnutls_certificate_credentials_t certs;
46 gnutls_anon_server_credentials_t anoncred;
47 char *key_file;
48 char *cert_file;
49 int enabled;
50 int ciphers[16];
51 int key_exchange[16];
52 int macs[16];
53 int protocol[16];
54 int compression[16];
55} gnutls_srvconf_rec;
56
57typedef struct gnutls_handle_t gnutls_handle_t;
58struct gnutls_handle_t
59{
60 gnutls_srvconf_rec *sc;
61 gnutls_session_t session;
62 ap_filter_t *input_filter;
63 apr_bucket_brigade *input_bb;
64 apr_read_type_e input_block;
65 int status;
66 int non_https;
67};
68
69/** Functions in gnutls_io.c **/
70
71/**
72 * mod_gnutls_filter_input will filter the input data
73 * by decrypting it using GnuTLS and passes it cleartext.
74 *
75 * @param f the filter info record
76 * @param bb the bucket brigade, where to store the result to
77 * @param mode what shall we read?
78 * @param block a block index we shall read from?
79 * @return result status
80 */
81apr_status_t mod_gnutls_filter_input(ap_filter_t * f,
82 apr_bucket_brigade * bb,
83 ap_input_mode_t mode,
84 apr_read_type_e block, apr_off_t readbytes);
85
86/**
87 * mod_gnutls_filter_output will filter the encrypt
88 * the incoming bucket using GnuTLS and passes it onto the next filter.
89 *
90 * @param f the filter info record
91 * @param bb the bucket brigade, where to store the result to
92 * @return result status
93 */
94apr_status_t mod_gnutls_filter_output(ap_filter_t * f, apr_bucket_brigade * bb);
95
96
97/**
98 * mod_gnutls_transport_read is called from GnuTLS to provide encrypted
99 * data from the client.
100 *
101 * @param ptr pointer to the filter context
102 * @param buffer place to put data
103 * @param len maximum size
104 * @return size length of the data stored in buffer
105 */
106ssize_t mod_gnutls_transport_read(gnutls_transport_ptr_t ptr,
107 void *buffer, size_t len);
108
109/**
110 * mod_gnutls_transport_write is called from GnuTLS to
111 * write data to the client.
112 *
113 * @param ptr pointer to the filter context
114 * @param buffer buffer to write to the client
115 * @param len size of the buffer
116 * @return size length of the data written
117 */
118ssize_t mod_gnutls_transport_write(gnutls_transport_ptr_t ptr,
119 const void *buffer, size_t len);
120
121
122#endif /* __mod_gnutls_h_inc */
diff --git a/src/Makefile.am b/src/Makefile.am
index 00ef272..ebbe176 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 3libmod_gnutls_la_SOURCES = mod_gnutls.c gnutls_io.c
4libmod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS} 4libmod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS}
5libmod_gnutls_la_LDFLAGS = ${MODULE_LIBS} 5libmod_gnutls_la_LDFLAGS = ${MODULE_LIBS}
6 6
diff --git a/src/gnutls_io.c b/src/gnutls_io.c
new file mode 100644
index 0000000..6b0a15b
--- /dev/null
+++ b/src/gnutls_io.c
@@ -0,0 +1,307 @@
1/* ====================================================================
2 * Copyright 2004 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
20/**
21 * Describe how the GnuTLS Filter system works here
22 * - It is basicly the same as what mod_ssl uses in that respect.
23 */
24
25apr_status_t mod_gnutls_filter_input(ap_filter_t * f,
26 apr_bucket_brigade * bb,
27 ap_input_mode_t mode,
28 apr_read_type_e block,
29 apr_off_t readbytes)
30{
31 apr_bucket* b;
32 apr_status_t status = APR_SUCCESS;
33 gnutls_handle_t *ctxt = (gnutls_handle_t *) f->ctx;
34
35 if (f->c->aborted) {
36 apr_bucket *bucket = apr_bucket_eos_create(f->c->bucket_alloc);
37 APR_BRIGADE_INSERT_TAIL(bb, bucket);
38 return APR_ECONNABORTED;
39 }
40
41#if 0
42 for (b = APR_BRIGADE_FIRST(bb);
43 b != APR_BRIGADE_SENTINEL(bb); b = APR_BUCKET_NEXT(b)) {
44 if (APR_BUCKET_IS_EOS(b)) {
45 /* end of connection */
46 }
47 else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ)
48 == APR_SUCCESS) {
49 /* more data */
50 }
51 }
52#endif
53 return status;
54}
55
56#define GNUTLS_HANDSHAKE_ATTEMPTS 10
57
58apr_status_t mod_gnutls_filter_output(ap_filter_t * f,
59 apr_bucket_brigade * bb)
60{
61 int ret, i;
62 const char *buf = 0;
63 apr_size_t bytes = 0;
64 gnutls_handle_t *ctxt = (gnutls_handle_t *) f->ctx;
65 apr_status_t status = APR_SUCCESS;
66 apr_read_type_e rblock = APR_NONBLOCK_READ;
67
68 if (f->c->aborted) {
69 apr_brigade_cleanup(bb);
70 return APR_ECONNABORTED;
71 }
72
73 if (ctxt->status == 0) {
74 for (i = GNUTLS_HANDSHAKE_ATTEMPTS; i > 0; i--) {
75 ret = gnutls_handshake(ctxt->session);
76
77 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
78 continue;
79 }
80
81 if (ret < 0) {
82 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED
83 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {
84 ret = gnutls_alert_get(ctxt->session);
85 ap_log_error(APLOG_MARK, APLOG_ERR, 0, f->c->base_server,
86 "GnuTLS: Hanshake Alert (%d) '%s'.\n", ret,
87 gnutls_alert_get_name(ret));
88 }
89
90 if (gnutls_error_is_fatal(ret) != 0) {
91 gnutls_deinit(ctxt->session);
92 ap_log_error(APLOG_MARK, APLOG_ERR, 0, f->c->base_server,
93 "GnuTLS: Handshake Failed (%d) '%s'", ret,
94 gnutls_strerror(ret));
95 ctxt->status = -1;
96 break;
97 }
98 }
99 else {
100 ctxt->status = 1;
101 break; /* all done with the handshake */
102 }
103 }
104 }
105
106 if (ctxt->status < 0) {
107 return ap_pass_brigade(f->next, bb);
108 }
109
110 while (!APR_BRIGADE_EMPTY(bb)) {
111 apr_bucket *bucket = APR_BRIGADE_FIRST(bb);
112 if (APR_BUCKET_IS_EOS(bucket) || APR_BUCKET_IS_FLUSH(bucket)) {
113 /** TODO: GnuTLS doesn't have a special flush method? **/
114 if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
115 return status;
116 }
117 break;
118 }
119 else if (AP_BUCKET_IS_EOC(bucket)) {
120 gnutls_bye(ctxt->session, GNUTLS_SHUT_WR);
121
122 if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
123 return status;
124 }
125 break;
126 }
127 else {
128 /* filter output */
129 const char *data;
130 apr_size_t len;
131
132 status = apr_bucket_read(bucket, &data, &len, rblock);
133
134 if (APR_STATUS_IS_EAGAIN(status)) {
135 rblock = APR_BLOCK_READ;
136 continue; /* and try again with a blocking read. */
137 }
138
139 rblock = APR_NONBLOCK_READ;
140
141 if (!APR_STATUS_IS_EOF(status) && (status != APR_SUCCESS)) {
142 break;
143 }
144
145 ret = gnutls_record_send(ctxt->session, data, len);
146 if (ret < 0) {
147 /* error sending output */
148 }
149 else if ((apr_size_t) ret != len) {
150 /* not all of the data was sent. */
151 /* mod_ssl basicly errors out here.. this doesn't seem right? */
152 }
153 else {
154 /* send complete */
155
156 }
157
158 apr_bucket_delete(bucket);
159
160 if (status != APR_SUCCESS) {
161 break;
162 }
163
164 }
165 }
166
167 return status;
168}
169
170/**
171 * From mod_ssl / ssl_engine_io.c
172 * This function will read from a brigade and discard the read buckets as it
173 * proceeds. It will read at most *len bytes.
174 */
175static apr_status_t brigade_consume(apr_bucket_brigade * bb,
176 apr_read_type_e block,
177 char *c, apr_size_t * len)
178{
179 apr_size_t actual = 0;
180 apr_status_t status = APR_SUCCESS;
181
182 while (!APR_BRIGADE_EMPTY(bb)) {
183 apr_bucket *b = APR_BRIGADE_FIRST(bb);
184 const char *str;
185 apr_size_t str_len;
186 apr_size_t consume;
187
188 /* Justin points out this is an http-ism that might
189 * not fit if brigade_consume is added to APR. Perhaps
190 * apr_bucket_read(eos_bucket) should return APR_EOF?
191 * Then this becomes mainline instead of a one-off.
192 */
193 if (APR_BUCKET_IS_EOS(b)) {
194 status = APR_EOF;
195 break;
196 }
197
198 /* The reason I'm not offering brigade_consume yet
199 * across to apr-util is that the following call
200 * illustrates how borked that API really is. For
201 * this sort of case (caller provided buffer) it
202 * would be much more trivial for apr_bucket_consume
203 * to do all the work that follows, based on the
204 * particular characteristics of the bucket we are
205 * consuming here.
206 */
207 status = apr_bucket_read(b, &str, &str_len, block);
208
209 if (status != APR_SUCCESS) {
210 if (APR_STATUS_IS_EOF(status)) {
211 /* This stream bucket was consumed */
212 apr_bucket_delete(b);
213 continue;
214 }
215 break;
216 }
217
218 if (str_len > 0) {
219 /* Do not block once some data has been consumed */
220 block = APR_NONBLOCK_READ;
221
222 /* Assure we don't overflow. */
223 consume = (str_len + actual > *len) ? *len - actual : str_len;
224
225 memcpy(c, str, consume);
226
227 c += consume;
228 actual += consume;
229
230 if (consume >= b->length) {
231 /* This physical bucket was consumed */
232 apr_bucket_delete(b);
233 }
234 else {
235 /* Only part of this physical bucket was consumed */
236 b->start += consume;
237 b->length -= consume;
238 }
239 }
240 else if (b->length == 0) {
241 apr_bucket_delete(b);
242 }
243
244 /* This could probably be actual == *len, but be safe from stray
245 * photons. */
246 if (actual >= *len) {
247 break;
248 }
249 }
250
251 *len = actual;
252 return status;
253}
254
255
256ssize_t mod_gnutls_transport_read(gnutls_transport_ptr_t ptr,
257 void *buffer, size_t len)
258{
259 gnutls_handle_t *ctxt = ptr;
260 apr_status_t rc;
261 apr_size_t in = len;
262 /* If Len = 0, we don't do anything. */
263 if (!len)
264 return 0;
265
266 if (APR_BRIGADE_EMPTY(ctxt->input_bb)) {
267
268 rc = ap_get_brigade(ctxt->input_filter->next, ctxt->input_bb,
269 AP_MODE_READBYTES, ctxt->input_block, in);
270
271 /* Not a problem, there was simply no data ready yet.
272 */
273 if (APR_STATUS_IS_EAGAIN(rc) || APR_STATUS_IS_EINTR(rc)
274 || (rc == APR_SUCCESS && APR_BRIGADE_EMPTY(ctxt->input_bb))) {
275 return 0;
276 }
277
278 if (rc != APR_SUCCESS) {
279 /* Unexpected errors discard the brigade */
280 apr_brigade_cleanup(ctxt->input_bb);
281 ctxt->input_bb = NULL;
282 return -1;
283 }
284 }
285
286// brigade_consume(ctxt->input_bb, ctxt->input_block, buffer, &len);
287
288
289 ap_get_brigade(ctxt->input_filter->next, ctxt->input_bb,
290 AP_MODE_READBYTES, ctxt->input_block, len);
291
292 return len;
293}
294
295ssize_t mod_gnutls_transport_write(gnutls_transport_ptr_t ptr,
296 const void *buffer, size_t len)
297{
298 gnutls_handle_t *ctxt = ptr;
299
300// apr_bucket *bucket = apr_bucket_transient_create(in, inl,
301// outctx->bb->
302// bucket_alloc);
303
304 // outctx->length += inl;
305 //APR_BRIGADE_INSERT_TAIL(outctx->bb, bucket);
306 return 0;
307}
diff --git a/src/mod_gnutls.c b/src/mod_gnutls.c
index e696ec6..14bf319 100644
--- a/src/mod_gnutls.c
+++ b/src/mod_gnutls.c
@@ -15,201 +15,12 @@
15 * 15 *
16 */ 16 */
17 17
18#include "httpd.h" 18#include "mod_gnutls.h"
19#include "http_config.h"
20#include "http_protocol.h"
21#include "http_connection.h"
22#include "http_core.h"
23#include "http_log.h"
24#include "apr_buckets.h"
25#include "apr_strings.h"
26#include "apr_tables.h"
27
28#include <gcrypt.h>
29#include <gnutls/gnutls.h>
30 19
31#if APR_HAS_THREADS 20#if APR_HAS_THREADS
32GCRY_THREAD_OPTION_PTHREAD_IMPL; 21GCRY_THREAD_OPTION_PTHREAD_IMPL;
33#endif 22#endif
34 23
35module AP_MODULE_DECLARE_DATA gnutls_module;
36
37#ifdef GNUTLS_AS_FILTER
38#define GNUTLS_OUTPUT_FILTER_NAME "GnuTLS Output Filter"
39#define GNUTLS_INPUT_FILTER_NAME "GnuTLS Input Filter"
40#endif
41
42#define GNUTLS_ENABLED_FALSE 0
43#define GNUTLS_ENABLED_TRUE 1
44
45
46typedef struct {
47 gnutls_certificate_credentials_t certs;
48 gnutls_anon_server_credentials_t anoncred;
49 char *key_file;
50 char *cert_file;
51 int enabled;
52 int ciphers[16];
53 int key_exchange[16];
54 int macs[16];
55 int protocol[16];
56 int compression[16];
57} gnutls_srvconf_rec;
58
59typedef struct gnutls_handle_t gnutls_handle_t;
60struct gnutls_handle_t
61{
62 gnutls_srvconf_rec *sc;
63 gnutls_session_t session;
64 ap_filter_t *input_filter;
65 apr_bucket_brigade *input_bb;
66 apr_read_type_e input_block;
67 int status;
68 int non_https;
69};
70
71static apr_status_t gnutls_filter_input(ap_filter_t * f,
72 apr_bucket_brigade * bb,
73 ap_input_mode_t mode,
74 apr_read_type_e block,
75 apr_off_t readbytes)
76{
77 apr_status_t status = APR_SUCCESS;
78 gnutls_handle_t *ctxt = (gnutls_handle_t *) f->ctx;
79
80 if (f->c->aborted) {
81 apr_bucket *bucket = apr_bucket_eos_create(f->c->bucket_alloc);
82 APR_BRIGADE_INSERT_TAIL(bb, bucket);
83 return APR_ECONNABORTED;
84 }
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
98 return status;
99}
100
101#define HANDSHAKE_ATTEMPTS 10
102
103static apr_status_t gnutls_filter_output(ap_filter_t * f,
104 apr_bucket_brigade * bb)
105{
106 int ret, i;
107 const char *buf = 0;
108 apr_size_t bytes = 0;
109 gnutls_handle_t *ctxt = (gnutls_handle_t *) f->ctx;
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 }
125
126 if (ret < 0) {
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 }
146 }
147
148 if (ctxt->status < 0) {
149 return ap_pass_brigade(f->next, bb);
150 }
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;
160 }
161 else if(AP_BUCKET_IS_EOC(bucket)) {
162 gnutls_bye(ctxt->session, GNUTLS_SHUT_WR);
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
207 }
208 }
209
210 return status;
211}
212
213static apr_status_t gnutls_cleanup_pre_config(void *data) 24static apr_status_t gnutls_cleanup_pre_config(void *data)
214{ 25{
215 gnutls_global_deinit(); 26 gnutls_global_deinit();
@@ -253,7 +64,7 @@ static int gnutls_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
253 64
254 for (s = base_server; s; s = s->next) { 65 for (s = base_server; s; s = s->next) {
255 sc = (gnutls_srvconf_rec *) ap_get_module_config(s->module_config, 66 sc = (gnutls_srvconf_rec *) ap_get_module_config(s->module_config,
256 &gnutls_module); 67 &gnutls_module);
257 if (sc->cert_file != NULL && sc->key_file != NULL) { 68 if (sc->cert_file != NULL && sc->key_file != NULL) {
258 gnutls_certificate_set_x509_key_file(sc->certs, sc->cert_file, 69 gnutls_certificate_set_x509_key_file(sc->certs, sc->cert_file,
259 sc->key_file, 70 sc->key_file,
@@ -261,7 +72,7 @@ static int gnutls_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
261// gnutls_certificate_set_rsa_export_params(sc->certs, rsa_params); 72// gnutls_certificate_set_rsa_export_params(sc->certs, rsa_params);
262// gnutls_certificate_set_dh_params(sc->certs, dh_params); 73// gnutls_certificate_set_dh_params(sc->certs, dh_params);
263 } 74 }
264 else if(sc->enabled == GNUTLS_ENABLED_TRUE ){ 75 else if (sc->enabled == GNUTLS_ENABLED_TRUE) {
265 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, 76 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
266 "[GnuTLS] - Host '%s:%d' is missing a Cert and Key File!", 77 "[GnuTLS] - Host '%s:%d' is missing a Cert and Key File!",
267 s->server_hostname, s->port); 78 s->server_hostname, s->port);
@@ -277,7 +88,7 @@ static const char *gnutls_hook_http_method(const request_rec * r)
277{ 88{
278 gnutls_srvconf_rec *sc = 89 gnutls_srvconf_rec *sc =
279 (gnutls_srvconf_rec *) ap_get_module_config(r->server->module_config, 90 (gnutls_srvconf_rec *) ap_get_module_config(r->server->module_config,
280 &gnutls_module); 91 &gnutls_module);
281 92
282 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 93 if (sc->enabled == GNUTLS_ENABLED_FALSE) {
283 return NULL; 94 return NULL;
@@ -290,7 +101,7 @@ static apr_port_t gnutls_hook_default_port(const request_rec * r)
290{ 101{
291 gnutls_srvconf_rec *sc = 102 gnutls_srvconf_rec *sc =
292 (gnutls_srvconf_rec *) ap_get_module_config(r->server->module_config, 103 (gnutls_srvconf_rec *) ap_get_module_config(r->server->module_config,
293 &gnutls_module); 104 &gnutls_module);
294 105
295 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 106 if (sc->enabled == GNUTLS_ENABLED_FALSE) {
296 return 0; 107 return 0;
@@ -299,152 +110,13 @@ static apr_port_t gnutls_hook_default_port(const request_rec * r)
299 return 443; 110 return 443;
300} 111}
301 112
302/**
303 * From mod_ssl / ssl_engine_io.c
304 * This function will read from a brigade and discard the read buckets as it
305 * proceeds. It will read at most *len bytes.
306 */
307static apr_status_t brigade_consume(apr_bucket_brigade * bb,
308 apr_read_type_e block,
309 char *c, apr_size_t * len)
310{
311 apr_size_t actual = 0;
312 apr_status_t status = APR_SUCCESS;
313
314 while (!APR_BRIGADE_EMPTY(bb)) {
315 apr_bucket *b = APR_BRIGADE_FIRST(bb);
316 const char *str;
317 apr_size_t str_len;
318 apr_size_t consume;
319
320 /* Justin points out this is an http-ism that might
321 * not fit if brigade_consume is added to APR. Perhaps
322 * apr_bucket_read(eos_bucket) should return APR_EOF?
323 * Then this becomes mainline instead of a one-off.
324 */
325 if (APR_BUCKET_IS_EOS(b)) {
326 status = APR_EOF;
327 break;
328 }
329
330 /* The reason I'm not offering brigade_consume yet
331 * across to apr-util is that the following call
332 * illustrates how borked that API really is. For
333 * this sort of case (caller provided buffer) it
334 * would be much more trivial for apr_bucket_consume
335 * to do all the work that follows, based on the
336 * particular characteristics of the bucket we are
337 * consuming here.
338 */
339 status = apr_bucket_read(b, &str, &str_len, block);
340
341 if (status != APR_SUCCESS) {
342 if (APR_STATUS_IS_EOF(status)) {
343 /* This stream bucket was consumed */
344 apr_bucket_delete(b);
345 continue;
346 }
347 break;
348 }
349
350 if (str_len > 0) {
351 /* Do not block once some data has been consumed */
352 block = APR_NONBLOCK_READ;
353
354 /* Assure we don't overflow. */
355 consume = (str_len + actual > *len) ? *len - actual : str_len;
356
357 memcpy(c, str, consume);
358
359 c += consume;
360 actual += consume;
361
362 if (consume >= b->length) {
363 /* This physical bucket was consumed */
364 apr_bucket_delete(b);
365 }
366 else {
367 /* Only part of this physical bucket was consumed */
368 b->start += consume;
369 b->length -= consume;
370 }
371 }
372 else if (b->length == 0) {
373 apr_bucket_delete(b);
374 }
375
376 /* This could probably be actual == *len, but be safe from stray
377 * photons. */
378 if (actual >= *len) {
379 break;
380 }
381 }
382
383 *len = actual;
384 return status;
385}
386
387
388static ssize_t gnutls_transport_read(gnutls_transport_ptr_t ptr,
389 void *buffer, size_t len)
390{
391 gnutls_handle_t *ctxt = ptr;
392 apr_status_t rc;
393 apr_size_t in = len;
394 /* If Len = 0, we don't do anything. */
395 if (!len)
396 return 0;
397
398 if (APR_BRIGADE_EMPTY(ctxt->input_bb)) {
399
400 rc = ap_get_brigade(ctxt->input_filter->next, ctxt->input_bb,
401 AP_MODE_READBYTES, ctxt->input_block, in);
402
403 /* Not a problem, there was simply no data ready yet.
404 */
405 if (APR_STATUS_IS_EAGAIN(rc) || APR_STATUS_IS_EINTR(rc)
406 || (rc == APR_SUCCESS && APR_BRIGADE_EMPTY(ctxt->input_bb))) {
407 return 0;
408 }
409
410 if (rc != APR_SUCCESS) {
411 /* Unexpected errors discard the brigade */
412 apr_brigade_cleanup(ctxt->input_bb);
413 ctxt->input_bb = NULL;
414 return -1;
415 }
416 }
417
418// brigade_consume(ctxt->input_bb, ctxt->input_block, buffer, &len);
419
420
421 ap_get_brigade(ctxt->input_filter->next, ctxt->input_bb,
422 AP_MODE_READBYTES, ctxt->input_block, len);
423
424 return len;
425}
426
427static ssize_t gnutls_transport_write(gnutls_transport_ptr_t ptr,
428 const void *buffer, size_t len)
429{
430 gnutls_handle_t *ctxt = ptr;
431
432// apr_bucket *bucket = apr_bucket_transient_create(in, inl,
433// outctx->bb->
434// bucket_alloc);
435
436 // outctx->length += inl;
437 //APR_BRIGADE_INSERT_TAIL(outctx->bb, bucket);
438 return 0;
439}
440
441static int gnutls_hook_pre_connection(conn_rec * c, void *csd) 113static int gnutls_hook_pre_connection(conn_rec * c, void *csd)
442{ 114{
443 gnutls_handle_t *ctxt; 115 gnutls_handle_t *ctxt;
444 gnutls_srvconf_rec *sc = 116 gnutls_srvconf_rec *sc =
445 (gnutls_srvconf_rec *) ap_get_module_config(c->base_server-> 117 (gnutls_srvconf_rec *) ap_get_module_config(c->base_server->
446 module_config, 118 module_config,
447 &gnutls_module); 119 &gnutls_module);
448 120
449 if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) { 121 if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) {
450 return DECLINED; 122 return DECLINED;
@@ -470,12 +142,14 @@ static int gnutls_hook_pre_connection(conn_rec * c, void *csd)
470 gnutls_certificate_server_set_request(ctxt->session, GNUTLS_CERT_IGNORE); 142 gnutls_certificate_server_set_request(ctxt->session, GNUTLS_CERT_IGNORE);
471 143
472// gnutls_dh_set_prime_bits(ctxt->session, DH_BITS); 144// gnutls_dh_set_prime_bits(ctxt->session, DH_BITS);
473 145
474 146
475 ap_set_module_config(c->conn_config, &gnutls_module, ctxt); 147 ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
476 148
477 gnutls_transport_set_pull_function(ctxt->session, gnutls_transport_read); 149 gnutls_transport_set_pull_function(ctxt->session,
478 gnutls_transport_set_push_function(ctxt->session, gnutls_transport_write); 150 mod_gnutls_transport_read);
151 gnutls_transport_set_push_function(ctxt->session,
152 mod_gnutls_transport_write);
479 gnutls_transport_set_ptr(ctxt->session, ctxt); 153 gnutls_transport_set_ptr(ctxt->session, ctxt);
480 ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c); 154 ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c);
481 ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c); 155 ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c);
@@ -484,24 +158,24 @@ static int gnutls_hook_pre_connection(conn_rec * c, void *csd)
484} 158}
485 159
486static const char *gnutls_set_cert_file(cmd_parms * parms, void *dummy, 160static const char *gnutls_set_cert_file(cmd_parms * parms, void *dummy,
487 const char *arg) 161 const char *arg)
488{ 162{
489 gnutls_srvconf_rec *sc = 163 gnutls_srvconf_rec *sc =
490 (gnutls_srvconf_rec *) ap_get_module_config(parms->server-> 164 (gnutls_srvconf_rec *) ap_get_module_config(parms->server->
491 module_config, 165 module_config,
492 &gnutls_module); 166 &gnutls_module);
493 sc->cert_file = apr_pstrdup(parms->pool, arg); 167 sc->cert_file = apr_pstrdup(parms->pool, arg);
494 return NULL; 168 return NULL;
495} 169}
496 170
497static const char *gnutls_set_key_file(cmd_parms * parms, void *dummy, 171static const char *gnutls_set_key_file(cmd_parms * parms, void *dummy,
498 const char *arg) 172 const char *arg)
499{ 173{
500 gnutls_srvconf_rec *sc = 174 gnutls_srvconf_rec *sc =
501 (gnutls_srvconf_rec *) ap_get_module_config(parms->server-> 175 (gnutls_srvconf_rec *) ap_get_module_config(parms->server->
502 module_config, 176 module_config,
503 &gnutls_module); 177 &gnutls_module);
504 sc->key_file = apr_pstrdup(parms->pool, arg); 178 sc->key_file = apr_pstrdup(parms->pool, arg);
505 return NULL; 179 return NULL;
506} 180}
507 181
@@ -510,8 +184,8 @@ static const char *gnutls_set_enabled(cmd_parms * parms, void *dummy,
510{ 184{
511 gnutls_srvconf_rec *sc = 185 gnutls_srvconf_rec *sc =
512 (gnutls_srvconf_rec *) ap_get_module_config(parms->server-> 186 (gnutls_srvconf_rec *) ap_get_module_config(parms->server->
513 module_config, 187 module_config,
514 &gnutls_module); 188 &gnutls_module);
515 if (!strcasecmp(arg, "On")) { 189 if (!strcasecmp(arg, "On")) {
516 sc->enabled = GNUTLS_ENABLED_TRUE; 190 sc->enabled = GNUTLS_ENABLED_TRUE;
517 } 191 }
@@ -535,8 +209,8 @@ static const command_rec gnutls_cmds[] = {
535 RSRC_CONF, 209 RSRC_CONF,
536 "SSL Server Certificate file"), 210 "SSL Server Certificate file"),
537 AP_INIT_TAKE1("GnuTLSEnable", gnutls_set_enabled, 211 AP_INIT_TAKE1("GnuTLSEnable", gnutls_set_enabled,
538 NULL, RSRC_CONF, 212 NULL, RSRC_CONF,
539 "Whether this server has GnuTLS Enabled. Default: Off"), 213 "Whether this server has GnuTLS Enabled. Default: Off"),
540 214
541 {NULL} 215 {NULL}
542}; 216};
@@ -562,10 +236,12 @@ static void gnutls_hooks(apr_pool_t * p)
562 /* ap_register_output_filter ("UPGRADE_FILTER", 236 /* ap_register_output_filter ("UPGRADE_FILTER",
563 * ssl_io_filter_Upgrade, NULL, AP_FTYPE_PROTOCOL + 5); 237 * ssl_io_filter_Upgrade, NULL, AP_FTYPE_PROTOCOL + 5);
564 */ 238 */
565 ap_register_input_filter(GNUTLS_INPUT_FILTER_NAME, gnutls_filter_input, 239 ap_register_input_filter(GNUTLS_INPUT_FILTER_NAME,
566 NULL, AP_FTYPE_CONNECTION + 5); 240 mod_gnutls_filter_input, NULL,
567 ap_register_output_filter(GNUTLS_OUTPUT_FILTER_NAME, gnutls_filter_output, 241 AP_FTYPE_CONNECTION + 5);
568 NULL, AP_FTYPE_CONNECTION + 5); 242 ap_register_output_filter(GNUTLS_OUTPUT_FILTER_NAME,
243 mod_gnutls_filter_output, NULL,
244 AP_FTYPE_CONNECTION + 5);
569} 245}
570 246
571static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s) 247static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s)
@@ -574,7 +250,6 @@ static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s)
574 gnutls_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc)); 250 gnutls_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc));
575 251
576 sc->enabled = GNUTLS_ENABLED_FALSE; 252 sc->enabled = GNUTLS_ENABLED_FALSE;
577 sc->non_https = 0;
578 253
579 gnutls_certificate_allocate_credentials(&sc->certs); 254 gnutls_certificate_allocate_credentials(&sc->certs);
580 gnutls_anon_allocate_server_credentials(&sc->anoncred); 255 gnutls_anon_allocate_server_credentials(&sc->anoncred);
@@ -586,7 +261,7 @@ static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s)
586 sc->ciphers[i++] = GNUTLS_CIPHER_ARCFOUR_128; 261 sc->ciphers[i++] = GNUTLS_CIPHER_ARCFOUR_128;
587 sc->ciphers[i++] = GNUTLS_CIPHER_3DES_CBC; 262 sc->ciphers[i++] = GNUTLS_CIPHER_3DES_CBC;
588 sc->ciphers[i++] = GNUTLS_CIPHER_ARCFOUR_40; 263 sc->ciphers[i++] = GNUTLS_CIPHER_ARCFOUR_40;
589 sc->ciphers[i] = 0; 264 sc->ciphers[i] = 0;
590 265
591 i = 0; 266 i = 0;
592 sc->key_exchange[i++] = GNUTLS_KX_RSA; 267 sc->key_exchange[i++] = GNUTLS_KX_RSA;