source: mod_gnutls/src/mod_gnutls.c @ a66e147

debian/masterdebian/stretch-backportsjessie-backportsmsvaupstream
Last change on this file since a66e147 was a66e147, checked in by Paul Querna <chip@…>, 15 years ago

working support for a ssl session cache via memcached.

  • Property mode set to 100644
File size: 13.9 KB
Line 
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#if APR_HAS_THREADS
21GCRY_THREAD_OPTION_PTHREAD_IMPL;
22#endif
23
24static apr_status_t mod_gnutls_cleanup_pre_config(void *data)
25{
26    gnutls_global_deinit();
27    return APR_SUCCESS;
28}
29
30static int mod_gnutls_hook_pre_config(apr_pool_t * pconf,
31                                      apr_pool_t * plog, apr_pool_t * ptemp)
32{
33
34#if APR_HAS_THREADS
35    gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
36#endif
37
38    gnutls_global_init();
39
40    apr_pool_cleanup_register(pconf, NULL, mod_gnutls_cleanup_pre_config,
41                              apr_pool_cleanup_null);
42
43    return OK;
44}
45
46#define DH_BITS 1024
47#ifdef USE_RSA
48#define RSA_BITS 512
49#endif
50static int mod_gnutls_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
51                                       apr_pool_t * ptemp,
52                                       server_rec * base_server)
53{
54    mod_gnutls_srvconf_rec *sc;
55    void *data = NULL;
56    int first_run = 0;
57    server_rec *s;
58    gnutls_dh_params_t dh_params;
59#ifdef USE_RSA
60    gnutls_rsa_params_t rsa_params;
61#endif
62    const char *userdata_key = "mod_gnutls_init";
63         
64    apr_pool_userdata_get(&data, userdata_key, base_server->process->pool);
65    if (data == NULL) {
66        first_run = 1;
67        apr_pool_userdata_set((const void *)1, userdata_key, 
68                              apr_pool_cleanup_null, 
69                              base_server->process->pool);
70    }
71
72
73//    if(first_run) {
74        /* TODO: Should we regenerate these after X requests / X time ? */
75        gnutls_dh_params_init(&dh_params);
76        gnutls_dh_params_generate2(dh_params, DH_BITS);
77#ifdef USE_RSA
78        gnutls_rsa_params_init(&rsa_params);
79        gnutls_rsa_params_generate2(rsa_params, RSA_BITS);
80#endif
81//    }
82
83    for (s = base_server; s; s = s->next) {
84        sc = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config,
85                                                             &gnutls_module);
86        if (sc->cert_file != NULL && sc->key_file != NULL) {
87            gnutls_certificate_set_x509_key_file(sc->certs, sc->cert_file,
88                                                 sc->key_file,
89                                                 GNUTLS_X509_FMT_PEM);
90#ifdef USE_RSA
91          gnutls_certificate_set_rsa_export_params(sc->certs, rsa_params);
92#endif
93          gnutls_certificate_set_dh_params(sc->certs, dh_params);
94        }
95        else if (sc->enabled == GNUTLS_ENABLED_TRUE) {
96            ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
97                         "[GnuTLS] - Host '%s:%d' is missing a Cert and Key File!",
98                         s->server_hostname, s->port);
99        }
100    }
101
102
103    ap_add_version_component(p, "GnuTLS/" LIBGNUTLS_VERSION);
104
105    return OK;
106}
107
108static void mod_gnutls_hook_child_init(apr_pool_t *p, server_rec *s)
109{
110    apr_status_t rv = APR_SUCCESS;
111    mod_gnutls_srvconf_rec *sc = ap_get_module_config(s->module_config,
112                                                      &gnutls_module);
113
114    if(sc->cache_config != NULL) {
115        rv = mod_gnutls_cache_child_init(p, s, sc);
116        if(rv != APR_SUCCESS) {
117            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
118                             "[GnuTLS] - Failed to run Cache Init");
119        }
120    }
121    else {
122            ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
123                             "[GnuTLS] - No Cache Configured. Hint: GnuTLSCache");
124    }
125}
126
127static const char *mod_gnutls_hook_http_method(const request_rec * r)
128{
129    mod_gnutls_srvconf_rec *sc =
130        (mod_gnutls_srvconf_rec *) ap_get_module_config(r->server->
131                                                        module_config,
132                                                        &gnutls_module);
133
134    if (sc->enabled == GNUTLS_ENABLED_FALSE) {
135        return NULL;
136    }
137
138    return "https";
139}
140
141static apr_port_t mod_gnutls_hook_default_port(const request_rec * r)
142{
143    mod_gnutls_srvconf_rec *sc =
144        (mod_gnutls_srvconf_rec *) ap_get_module_config(r->server->
145                                                        module_config,
146                                                        &gnutls_module);
147
148    if (sc->enabled == GNUTLS_ENABLED_FALSE) {
149        return 0;
150    }
151
152    return 443;
153}
154
155static mod_gnutls_handle_t* create_gnutls_handle(apr_pool_t* pool, conn_rec * c)
156{
157    mod_gnutls_handle_t *ctxt;
158    mod_gnutls_srvconf_rec *sc =
159        (mod_gnutls_srvconf_rec *) ap_get_module_config(c->base_server->
160                                                        module_config,
161                                                        &gnutls_module);
162
163    ctxt = apr_pcalloc(pool, sizeof(*ctxt));
164    ctxt->c = c;
165    ctxt->sc = sc;
166    ctxt->status = 0;
167
168    ctxt->input_rc = APR_SUCCESS;
169    ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc);
170    ctxt->input_cbuf.length = 0;
171
172    ctxt->output_rc = APR_SUCCESS;
173    ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc);
174    ctxt->output_blen = 0;
175    ctxt->output_length = 0;
176
177    gnutls_init(&ctxt->session, GNUTLS_SERVER);
178
179    gnutls_cipher_set_priority(ctxt->session, sc->ciphers);
180    gnutls_compression_set_priority(ctxt->session, sc->compression);
181    gnutls_kx_set_priority(ctxt->session, sc->key_exchange);
182    gnutls_protocol_set_priority(ctxt->session, sc->protocol);
183    gnutls_mac_set_priority(ctxt->session, sc->macs);
184
185    gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE, sc->certs);
186//  if(anon) {
187//    gnutls_credentials_set(ctxt->session, GNUTLS_CRD_ANON, sc->anoncred);
188//  }
189
190    gnutls_certificate_server_set_request(ctxt->session, GNUTLS_CERT_IGNORE);
191
192    gnutls_dh_set_prime_bits(ctxt->session, DH_BITS);
193
194    mod_gnutls_cache_session_init(ctxt);
195    return ctxt;
196}
197
198static int mod_gnutls_hook_pre_connection(conn_rec * c, void *csd)
199{
200    mod_gnutls_handle_t *ctxt;
201    mod_gnutls_srvconf_rec *sc =
202        (mod_gnutls_srvconf_rec *) ap_get_module_config(c->base_server->
203                                                        module_config,
204                                                        &gnutls_module);
205
206    if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) {
207        return DECLINED;
208    }
209
210    ctxt = create_gnutls_handle(c->pool, c);
211
212    ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
213
214    gnutls_transport_set_pull_function(ctxt->session,
215                                       mod_gnutls_transport_read);
216    gnutls_transport_set_push_function(ctxt->session,
217                                       mod_gnutls_transport_write);
218    gnutls_transport_set_ptr(ctxt->session, ctxt);
219    ctxt->input_filter = ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c);
220    ctxt->output_filter = ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c);
221
222    return OK;
223}
224
225static int mod_gnutls_hook_fixups(request_rec *r)
226{
227    const char* tmp;
228    mod_gnutls_handle_t *ctxt;
229    apr_table_t *env = r->subprocess_env;
230
231    ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module);
232
233    if(!ctxt) {
234        return DECLINED;
235    }
236    apr_table_setn(env, "HTTPS", "on");
237    apr_table_setn(env, "SSL_PROTOCOL",
238                   gnutls_protocol_get_name(gnutls_protocol_get_version(ctxt->session)));
239    apr_table_setn(env, "SSL_CIPHER",
240                   gnutls_cipher_get_name(gnutls_cipher_get(ctxt->session)));
241
242    tmp = apr_psprintf(r->pool, "%d",
243              8 * gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session)));
244
245    apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp);
246    apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp);
247
248    return OK;
249}
250
251static const char *gnutls_set_cert_file(cmd_parms * parms, void *dummy,
252                                        const char *arg)
253{
254    mod_gnutls_srvconf_rec *sc =
255        (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server->
256                                                        module_config,
257                                                        &gnutls_module);
258    sc->cert_file = ap_server_root_relative(parms->pool, arg);
259    return NULL;
260}
261
262static const char *gnutls_set_key_file(cmd_parms * parms, void *dummy,
263                                       const char *arg)
264{
265    mod_gnutls_srvconf_rec *sc =
266        (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server->
267                                                        module_config,
268                                                        &gnutls_module);
269    sc->key_file = ap_server_root_relative(parms->pool, arg);
270    return NULL;
271}
272
273static const char *gnutls_set_cache(cmd_parms * parms, void *dummy,
274                                       const char *arg)
275{
276    const char* err;
277    mod_gnutls_srvconf_rec *sc = ap_get_module_config(parms->server->
278                                                        module_config,
279                                                        &gnutls_module);
280    if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
281        return err;
282    }
283
284    sc->cache_config = apr_pstrdup(parms->pool, arg);
285    return NULL;
286}
287
288static const char *gnutls_set_enabled(cmd_parms * parms, void *dummy,
289                                      const char *arg)
290{
291    mod_gnutls_srvconf_rec *sc =
292        (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server->
293                                                        module_config,
294                                                        &gnutls_module);
295    if (!strcasecmp(arg, "On")) {
296        sc->enabled = GNUTLS_ENABLED_TRUE;
297    }
298    else if (!strcasecmp(arg, "Off")) {
299        sc->enabled = GNUTLS_ENABLED_FALSE;
300    }
301    else {
302        return "GnuTLSEnable must be set to 'On' or 'Off'";
303    }
304
305    return NULL;
306}
307
308static const command_rec gnutls_cmds[] = {
309    AP_INIT_TAKE1("GnuTLSCertificateFile", gnutls_set_cert_file,
310                  NULL,
311                  RSRC_CONF,
312                  "SSL Server Key file"),
313    AP_INIT_TAKE1("GnuTLSKeyFile", gnutls_set_key_file,
314                  NULL,
315                  RSRC_CONF,
316                  "SSL Server Certificate file"),
317    AP_INIT_TAKE1("GnuTLSCache", gnutls_set_cache,
318                  NULL,
319                  RSRC_CONF,
320                  "SSL Server Certificate file"),
321    AP_INIT_TAKE1("GnuTLSEnable", gnutls_set_enabled,
322                  NULL, RSRC_CONF,
323                  "Whether this server has GnuTLS Enabled. Default: Off"),
324
325    {NULL}
326};
327
328/* TODO: CACertificateFile & Client Authentication
329 *    AP_INIT_TAKE1("GnuTLSCACertificateFile", ap_set_server_string_slot,
330 *                 (void *) APR_OFFSETOF(gnutls_srvconf_rec, key_file), NULL,
331 *                 RSRC_CONF,
332 *                 "CA"),
333 */
334
335static void gnutls_hooks(apr_pool_t * p)
336{
337    ap_hook_pre_connection(mod_gnutls_hook_pre_connection, NULL, NULL,
338                           APR_HOOK_MIDDLE);
339    ap_hook_post_config(mod_gnutls_hook_post_config, NULL, NULL,
340                        APR_HOOK_MIDDLE);
341    ap_hook_child_init(mod_gnutls_hook_child_init, NULL, NULL,
342                        APR_HOOK_MIDDLE);
343    ap_hook_http_method(mod_gnutls_hook_http_method, NULL, NULL,
344                        APR_HOOK_MIDDLE);
345    ap_hook_default_port(mod_gnutls_hook_default_port, NULL, NULL,
346                         APR_HOOK_MIDDLE);
347    ap_hook_pre_config(mod_gnutls_hook_pre_config, NULL, NULL,
348                       APR_HOOK_MIDDLE);
349
350    ap_hook_fixups(mod_gnutls_hook_fixups, NULL, NULL, APR_HOOK_MIDDLE);
351
352    /* TODO: HTTP Upgrade Filter */
353    /* ap_register_output_filter ("UPGRADE_FILTER",
354     *          ssl_io_filter_Upgrade, NULL, AP_FTYPE_PROTOCOL + 5);
355     */
356    ap_register_input_filter(GNUTLS_INPUT_FILTER_NAME,
357                             mod_gnutls_filter_input, NULL,
358                             AP_FTYPE_CONNECTION + 5);
359    ap_register_output_filter(GNUTLS_OUTPUT_FILTER_NAME,
360                              mod_gnutls_filter_output, NULL,
361                              AP_FTYPE_CONNECTION + 5);
362}
363
364static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s)
365{
366    int i;
367    mod_gnutls_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc));
368
369    sc->enabled = GNUTLS_ENABLED_FALSE;
370
371    gnutls_certificate_allocate_credentials(&sc->certs);
372    gnutls_anon_allocate_server_credentials(&sc->anoncred);
373    sc->key_file = NULL;
374    sc->cert_file = NULL;
375    sc->cache_config = NULL;
376
377    i = 0;
378    sc->ciphers[i++] = GNUTLS_CIPHER_AES_256_CBC;
379    sc->ciphers[i++] = GNUTLS_CIPHER_AES_128_CBC;
380    sc->ciphers[i++] = GNUTLS_CIPHER_ARCFOUR_128;
381    sc->ciphers[i++] = GNUTLS_CIPHER_3DES_CBC;
382    sc->ciphers[i++] = GNUTLS_CIPHER_ARCFOUR_40;
383    sc->ciphers[i] = 0;
384
385    i = 0;
386    sc->key_exchange[i++] = GNUTLS_KX_DHE_DSS;
387    sc->key_exchange[i++] = GNUTLS_KX_RSA;
388    sc->key_exchange[i++] = GNUTLS_KX_DHE_RSA;
389    sc->key_exchange[i++] = GNUTLS_KX_RSA_EXPORT;
390    sc->key_exchange[i++] = GNUTLS_KX_DHE_DSS;
391    sc->key_exchange[i] = 0;
392
393    i = 0;
394    sc->macs[i++] = GNUTLS_MAC_SHA;
395    sc->macs[i++] = GNUTLS_MAC_MD5;
396    sc->macs[i++] = GNUTLS_MAC_RMD160;
397    sc->macs[i] = 0;
398
399    i = 0;
400    sc->protocol[i++] = GNUTLS_TLS1_1;
401    sc->protocol[i++] = GNUTLS_TLS1;
402    sc->protocol[i++] = GNUTLS_SSL3;
403    sc->protocol[i] = 0;
404
405    i = 0;
406    sc->compression[i++] = GNUTLS_COMP_NULL;
407    sc->compression[i++] = GNUTLS_COMP_ZLIB;
408    sc->compression[i++] = GNUTLS_COMP_LZO;
409    sc->compression[i] = 0;
410
411    return sc;
412}
413
414
415
416module AP_MODULE_DECLARE_DATA gnutls_module = {
417    STANDARD20_MODULE_STUFF,
418    NULL,
419    NULL,
420    gnutls_config_server_create,
421    NULL,
422/*    gnutls_config_server_merge, */
423    gnutls_cmds,
424    gnutls_hooks
425};
Note: See TracBrowser for help on using the repository browser.