source: mod_gnutls/src/mod_gnutls.c @ 31645b2

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

working SNI. Not so working Client Cert support.

  • Property mode set to 100644
File size: 29.4 KB
Line 
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
20extern server_rec *ap_server_conf;
21
22#if APR_HAS_THREADS
23GCRY_THREAD_OPTION_PTHREAD_IMPL;
24#endif
25
26#if MOD_GNUTLS_DEBUG
27static apr_file_t* debug_log_fp;
28#endif
29
30static apr_status_t mod_gnutls_cleanup_pre_config(void *data)
31{
32    gnutls_global_deinit();
33    return APR_SUCCESS;
34}
35
36#if MOD_GNUTLS_DEBUG
37static void gnutls_debug_log_all( int level, const char* str)
38{
39    apr_file_printf(debug_log_fp, "<%d> %s\n", level, str);
40}
41#endif
42
43static int mod_gnutls_hook_pre_config(apr_pool_t * pconf,
44                                      apr_pool_t * plog, apr_pool_t * ptemp)
45{
46
47#if APR_HAS_THREADS
48    /* TODO: Check MPM Type here */
49    gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
50#endif
51
52    gnutls_global_init();
53
54    apr_pool_cleanup_register(pconf, NULL, mod_gnutls_cleanup_pre_config,
55                              apr_pool_cleanup_null);
56
57#if MOD_GNUTLS_DEBUG
58    apr_file_open(&debug_log_fp, "/tmp/gnutls_debug",
59                  APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, pconf);
60
61    gnutls_global_set_log_level(9);
62    gnutls_global_set_log_function(gnutls_debug_log_all);
63#endif
64
65    return OK;
66}
67
68
69static gnutls_datum load_params(const char* file, server_rec* s, 
70                                apr_pool_t* pool) 
71{
72    gnutls_datum ret = { NULL, 0 };
73    apr_file_t* fp;
74    apr_finfo_t finfo;
75    apr_status_t rv;
76    apr_size_t br = 0;
77
78    rv = apr_file_open(&fp, file, APR_READ|APR_BINARY, APR_OS_DEFAULT, 
79                       pool);
80    if (rv != APR_SUCCESS) {
81        ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, 
82                     "GnuTLS failed to load params file at: %s", file);
83        return ret;
84    }
85
86    rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
87
88    if (rv != APR_SUCCESS) {
89        ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, 
90                     "GnuTLS failed to stat params file at: %s", file);
91        return ret;
92    }
93
94    ret.data = apr_palloc(pool, finfo.size+1);
95    rv = apr_file_read_full(fp, ret.data, finfo.size, &br);
96
97    if (rv != APR_SUCCESS) {
98        ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, 
99                     "GnuTLS failed to read params file at: %s", file);
100        return ret;
101    }
102    apr_file_close(fp);
103    ret.data[br] = '\0';
104    ret.size = br;
105
106    return ret;
107}
108
109static int mod_gnutls_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
110                                       apr_pool_t * ptemp,
111                                       server_rec * base_server)
112{
113    int rv;
114    server_rec *s;
115    gnutls_dh_params_t dh_params;
116    gnutls_rsa_params_t rsa_params;
117    mod_gnutls_srvconf_rec *sc;
118    mod_gnutls_srvconf_rec *sc_base;
119    void *data = NULL;
120    int first_run = 0;
121    const char *userdata_key = "mod_gnutls_init";
122         
123    apr_pool_userdata_get(&data, userdata_key, base_server->process->pool);
124    if (data == NULL) {
125        first_run = 1;
126        apr_pool_userdata_set((const void *)1, userdata_key, 
127                              apr_pool_cleanup_null, 
128                              base_server->process->pool);
129    }
130
131
132    {
133        gnutls_datum pdata;
134        apr_pool_t* tpool;
135        s = base_server;
136        sc_base = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config,
137                                                             &gnutls_module);
138
139        apr_pool_create(&tpool, p);
140
141        gnutls_dh_params_init(&dh_params);
142
143        pdata = load_params(sc_base->dh_params_file, s, tpool);
144
145        if (pdata.size != 0) {
146            rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata, 
147                                               GNUTLS_X509_FMT_PEM);
148            if (rv != 0) {
149                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 
150                             "GnuTLS: Unable to load DH Params: (%d) %s",
151                             rv, gnutls_strerror(rv));
152                exit(rv);
153            }
154        }
155        else {
156            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 
157                         "GnuTLS: Unable to load DH Params."
158                         " Shutting Down.");
159            exit(-1);
160        }
161        apr_pool_clear(tpool);
162
163        gnutls_rsa_params_init(&rsa_params);
164
165        pdata = load_params(sc_base->rsa_params_file, s, tpool);
166
167        if (pdata.size != 0) {
168            rv = gnutls_rsa_params_import_pkcs1(rsa_params, &pdata, 
169                                                GNUTLS_X509_FMT_PEM);
170            if (rv != 0) {
171                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 
172                             "GnuTLS: Unable to load RSA Params: (%d) %s",
173                             rv, gnutls_strerror(rv));
174                exit(rv);
175            }
176        }
177        else {
178            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 
179                         "GnuTLS: Unable to load RSA Params."
180                         " Shutting Down.");
181            exit(-1);
182        }
183
184        apr_pool_destroy(tpool);
185        rv = mod_gnutls_cache_post_config(p, s, sc_base);
186        if (rv != 0) {
187            ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, 
188                         "GnuTLS: Post Config for GnuTLSCache Failed."
189                         " Shutting Down.");
190            exit(-1);
191        }
192         
193        for (s = base_server; s; s = s->next) {
194            sc = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config,
195                                                                 &gnutls_module);
196            sc->cache_type = sc_base->cache_type;
197            sc->cache_config = sc_base->cache_config;
198
199            gnutls_certificate_set_rsa_export_params(sc->certs, 
200                                                     rsa_params);
201            gnutls_certificate_set_dh_params(sc->certs, dh_params);
202
203            if (sc->cert_x509 == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
204                ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
205                             "[GnuTLS] - Host '%s:%d' is missing a "
206                             "Certificate File!",
207                         s->server_hostname, s->port);
208                exit(-1);
209            }
210           
211            if (sc->privkey_x509 == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
212                ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
213                             "[GnuTLS] - Host '%s:%d' is missing a "
214                             "Private Key File!",
215                             s->server_hostname, s->port);
216                exit(-1);
217            }
218            {
219                int rv;
220                int data_len = 255;
221                char crt_name[255];
222                for (rv = 0; rv < data_len; rv++) {
223                    crt_name[rv] = '\0';
224                }
225                rv = gnutls_x509_crt_get_dn_by_oid(sc->cert_x509, 
226                                                   GNUTLS_OID_X520_COMMON_NAME, 0, 0,
227                                                   crt_name, &data_len);
228               
229            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
230                         s,
231                         "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X sc: 0x%08X", crt_name, rv,
232                         gnutls_pk_algorithm_get_name(gnutls_x509_privkey_get_pk_algorithm(sc->privkey_x509)),
233                         (unsigned int)s, (unsigned int)sc);
234            }
235        }
236    }
237
238    ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION);
239
240    return OK;
241}
242
243static void mod_gnutls_hook_child_init(apr_pool_t *p, server_rec *s)
244{
245    apr_status_t rv = APR_SUCCESS;
246    mod_gnutls_srvconf_rec *sc = ap_get_module_config(s->module_config,
247                                                      &gnutls_module);
248
249    if (sc->cache_type != mod_gnutls_cache_none) {
250        rv = mod_gnutls_cache_child_init(p, s, sc);
251        if(rv != APR_SUCCESS) {
252            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
253                             "[GnuTLS] - Failed to run Cache Init");
254        }
255    }
256    else {
257        ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s,
258                     "[GnuTLS] - No Cache Configured. Hint: GnuTLSCache");
259    }
260}
261
262static const char *mod_gnutls_hook_http_scheme(const request_rec * r)
263{
264    mod_gnutls_srvconf_rec *sc =
265        (mod_gnutls_srvconf_rec *) ap_get_module_config(r->server->
266                                                        module_config,
267                                                        &gnutls_module);
268
269    if (sc->enabled == GNUTLS_ENABLED_FALSE) {
270        return NULL;
271    }
272
273    return "https";
274}
275
276static apr_port_t mod_gnutls_hook_default_port(const request_rec * r)
277{
278    mod_gnutls_srvconf_rec *sc =
279        (mod_gnutls_srvconf_rec *) ap_get_module_config(r->server->
280                                                        module_config,
281                                                        &gnutls_module);
282
283    if (sc->enabled == GNUTLS_ENABLED_FALSE) {
284        return 0;
285    }
286
287    return 443;
288}
289
290#define MAX_HOST_LEN 255
291static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st* ret) 
292{
293    int rv;
294    int sni_type;
295    int data_len = MAX_HOST_LEN;
296    char sni_name[MAX_HOST_LEN];
297    char crt_name[MAX_HOST_LEN];
298    mod_gnutls_handle_t *ctxt;
299    mod_gnutls_srvconf_rec *tsc;
300    server_rec* s;
301   
302    ctxt = gnutls_transport_get_ptr(session);
303   
304    sni_type = gnutls_certificate_type_get(session);
305    if (sni_type != GNUTLS_CRT_X509) {
306        /* In theory, we could support OpenPGP Certificates. Theory != code. */
307        ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
308                     ctxt->c->base_server,
309                     "GnuTLS: Only x509 Certificates are currently supported.");
310        return -1;
311    }
312
313    ret->type = GNUTLS_CRT_X509;
314    ret->ncerts = 1;
315    ret->deinit_all = 0;
316   
317    rv = gnutls_server_name_get(ctxt->session, sni_name, 
318                                &data_len, &sni_type, 0);
319
320    if (rv != 0) {
321        goto use_default_crt;
322    }
323
324    if (sni_type != GNUTLS_NAME_DNS) {
325        ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
326                     ctxt->c->base_server,
327                     "GnuTLS: Unknown type '%d' for SNI: "
328                     "'%s'", sni_type, sni_name);       
329        goto use_default_crt;
330    }
331   
332    /**
333     * Code in the Core already sets up the c->base_server as the base
334     * for this IP/Port combo.  Trust that the core did the 'right' thing.
335     */
336    for (s = ap_server_conf; s; s = s->next) {
337       
338        tsc = (mod_gnutls_srvconf_rec *) ap_get_module_config(s->module_config,
339                                                             &gnutls_module);
340        if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
341            continue;
342        }
343       
344        data_len = MAX_HOST_LEN;
345        rv = gnutls_x509_crt_get_dn_by_oid(tsc->cert_x509, 
346                                           GNUTLS_OID_X520_COMMON_NAME, 0, 0,
347                                           crt_name, &data_len);
348        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
349                     ctxt->c->base_server,
350                     "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X  sc: 0x%08X", crt_name, rv,
351                     gnutls_pk_algorithm_get_name(gnutls_x509_privkey_get_pk_algorithm(ctxt->sc->privkey_x509)),
352                     (unsigned int)s, (unsigned int)s->next, (unsigned int)tsc);
353
354        if (rv != 0) {
355            continue;
356        }
357           
358        /* The CN can contain a * -- this will match those too. */
359        if (ap_strcasecmp_match(sni_name, crt_name) == 0) {
360            /* found a match */
361            ret->cert.x509 = &tsc->cert_x509;
362            ret->key.x509 = tsc->privkey_x509;
363#if MOD_GNUTLS_DEBUG
364            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
365                         ctxt->c->base_server,
366                         "GnuTLS: Virtual Host: "
367                         "'%s' == '%s'", crt_name, sni_name);
368#endif
369            return 0;
370        }
371    }
372
373   
374    /**
375     * If the client does not support the Server Name Indication, give the default
376     * certificate for this server.
377     */
378use_default_crt:
379    data_len = MAX_HOST_LEN;
380    rv = gnutls_x509_crt_get_dn_by_oid(ctxt->sc->cert_x509, 
381                                  GNUTLS_OID_X520_COMMON_NAME, 0, 0,
382                                  crt_name, &data_len);
383       
384    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
385                     ctxt->c->base_server,
386                     "GnuTLS: x509 cn: %s/%d pk: %s", crt_name, rv,
387                 gnutls_pk_algorithm_get_name(gnutls_x509_privkey_get_pk_algorithm(ctxt->sc->privkey_x509)));
388   
389    ret->cert.x509 = &ctxt->sc->cert_x509;
390    ret->key.x509 = ctxt->sc->privkey_x509;
391#if MOD_GNUTLS_DEBUG
392    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
393                 ctxt->c->base_server,
394                 "GnuTLS: Using Default Certificate.");
395#endif
396    return 0;
397}
398
399static mod_gnutls_handle_t* create_gnutls_handle(apr_pool_t* pool, conn_rec * c)
400{
401    mod_gnutls_handle_t *ctxt;
402    mod_gnutls_srvconf_rec *sc =
403        (mod_gnutls_srvconf_rec *) ap_get_module_config(c->base_server->
404                                                        module_config,
405                                                        &gnutls_module);
406
407    ctxt = apr_pcalloc(pool, sizeof(*ctxt));
408    ctxt->c = c;
409    ctxt->sc = sc;
410    ctxt->status = 0;
411
412    ctxt->input_rc = APR_SUCCESS;
413    ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc);
414    ctxt->input_cbuf.length = 0;
415
416    ctxt->output_rc = APR_SUCCESS;
417    ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc);
418    ctxt->output_blen = 0;
419    ctxt->output_length = 0;
420
421    gnutls_init(&ctxt->session, GNUTLS_SERVER);
422
423    gnutls_protocol_set_priority(ctxt->session, sc->protocol);
424    gnutls_cipher_set_priority(ctxt->session, sc->ciphers);
425    gnutls_compression_set_priority(ctxt->session, sc->compression);
426    gnutls_kx_set_priority(ctxt->session, sc->key_exchange);
427    gnutls_mac_set_priority(ctxt->session, sc->macs);
428    gnutls_certificate_type_set_priority(ctxt->session, sc->cert_types);
429
430    gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE, sc->certs);
431
432    gnutls_certificate_server_set_request(ctxt->session, sc->client_verify_mode);
433
434    mod_gnutls_cache_session_init(ctxt);
435
436    /* TODO: Finish Support for Server Name Indication */
437    gnutls_certificate_server_set_retrieve_function(sc->certs, cert_retrieve_fn);
438    return ctxt;
439}
440
441static int mod_gnutls_hook_pre_connection(conn_rec * c, void *csd)
442{
443    mod_gnutls_handle_t *ctxt;
444    mod_gnutls_srvconf_rec *sc =
445        (mod_gnutls_srvconf_rec *) ap_get_module_config(c->base_server->
446                                                        module_config,
447                                                        &gnutls_module);
448
449    if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) {
450        return DECLINED;
451    }
452
453    ctxt = create_gnutls_handle(c->pool, c);
454
455    ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
456
457    gnutls_transport_set_pull_function(ctxt->session,
458                                       mod_gnutls_transport_read);
459    gnutls_transport_set_push_function(ctxt->session,
460                                       mod_gnutls_transport_write);
461    gnutls_transport_set_ptr(ctxt->session, ctxt);
462   
463    ctxt->input_filter = ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, 
464                                             NULL, c);
465    ctxt->output_filter = ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt,
466                                               NULL, c);
467
468    return OK;
469}
470
471static int mod_gnutls_hook_fixups(request_rec *r)
472{
473    unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
474    char buf[GNUTLS_SESSION_ID_STRING_LEN];
475    const char* tmp;
476    int len;
477    mod_gnutls_handle_t *ctxt;
478    apr_table_t *env = r->subprocess_env;
479
480    ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module);
481
482    if(!ctxt) {
483        return DECLINED;
484    }
485
486    apr_table_setn(env, "HTTPS", "on");
487
488    apr_table_setn(env, "GNUTLS_VERSION_INTERFACE", MOD_GNUTLS_VERSION);
489    apr_table_setn(env, "GNUTLS_VERSION_LIBRARY", LIBGNUTLS_VERSION);
490
491    apr_table_setn(env, "SSL_PROTOCOL",
492                   gnutls_protocol_get_name(gnutls_protocol_get_version(ctxt->session)));
493
494    apr_table_setn(env, "SSL_CIPHER",
495                   gnutls_cipher_get_name(gnutls_cipher_get(ctxt->session)));
496
497    apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE");
498
499    tmp = apr_psprintf(r->pool, "%d",
500              8 * gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session)));
501
502    apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp);
503
504    apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp);
505
506    len = sizeof(sbuf);
507    gnutls_session_get_id(ctxt->session, sbuf, &len);
508    tmp = mod_gnutls_session_id2sz(sbuf, len, buf, sizeof(buf));
509    apr_table_setn(env, "SSL_SESSION_ID", tmp);
510   
511    return OK;
512}
513
514static int load_datum_from_file(apr_pool_t* pool, 
515                                const char* file,
516                                gnutls_datum_t* data)
517{
518    apr_file_t* fp;
519    apr_finfo_t finfo;
520    apr_status_t rv;
521    apr_size_t br = 0;
522   
523    rv = apr_file_open(&fp, file, APR_READ|APR_BINARY, APR_OS_DEFAULT, 
524                       pool);
525    if (rv != APR_SUCCESS) {
526        return rv;
527    }
528   
529    rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
530   
531    if (rv != APR_SUCCESS) {
532        return rv;
533    }
534   
535    data->data = apr_palloc(pool, finfo.size+1);
536    rv = apr_file_read_full(fp, data->data, finfo.size, &br);
537   
538    if (rv != APR_SUCCESS) {
539        return rv;
540    }
541    apr_file_close(fp);
542   
543    data->data[br] = '\0';
544    data->size = br;
545   
546    return 0;
547}
548
549static const char *gnutls_set_cert_file(cmd_parms * parms, void *dummy,
550                                        const char *arg)
551{
552    int ret;
553    gnutls_datum_t data;
554    const char* file;
555    apr_pool_t* spool;
556    mod_gnutls_srvconf_rec *sc =
557        (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server->
558                                                        module_config,
559                                                        &gnutls_module);
560    apr_pool_create(&spool, parms->pool);
561   
562    file = ap_server_root_relative(spool, arg);
563
564    if (load_datum_from_file(spool, file, &data) != 0) {
565        return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
566                            "Certificate '%s'", file);
567    }
568   
569    gnutls_x509_crt_init(&sc->cert_x509);
570    ret = gnutls_x509_crt_import(sc->cert_x509, &data, GNUTLS_X509_FMT_PEM);
571    if (ret != 0) {
572        return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
573                            "Certificate'%s': (%d) %s", file, ret, 
574                            gnutls_strerror(ret));
575    }
576   
577    //apr_pool_destroy(spool);
578    return NULL;
579}
580
581static const char *gnutls_set_key_file(cmd_parms * parms, void *dummy,
582                                       const char *arg)
583{
584    int ret;
585    gnutls_datum_t data;
586    const char* file;
587    apr_pool_t* spool;
588    mod_gnutls_srvconf_rec *sc =
589        (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server->
590                                                        module_config,
591                                                        &gnutls_module);
592    apr_pool_create(&spool, parms->pool);
593   
594    file = ap_server_root_relative(spool, arg);
595   
596    if (load_datum_from_file(spool, file, &data) != 0) {
597        return apr_psprintf(parms->pool, "GnuTLS: Error Reading "
598                            "Private Key '%s'", file);
599    }
600   
601    gnutls_x509_privkey_init(&sc->privkey_x509);
602    ret = gnutls_x509_privkey_import(sc->privkey_x509, &data, GNUTLS_X509_FMT_PEM);
603    if (ret != 0) {
604        return apr_psprintf(parms->pool, "GnuTLS: Failed to Import "
605                            "Private Key '%s': (%d) %s", file, ret, 
606                            gnutls_strerror(ret));
607    }
608    //apr_pool_destroy(spool);
609    return NULL;
610}
611
612static const char *gnutls_set_cache(cmd_parms * parms, void *dummy,
613                                       const char *type, const char* arg)
614{
615    const char* err;
616    mod_gnutls_srvconf_rec *sc = ap_get_module_config(parms->server->
617                                                        module_config,
618                                                        &gnutls_module);
619    if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
620        return err;
621    }
622
623    if (strcasecmp("none", type) == 0) {
624        sc->cache_type = mod_gnutls_cache_none;
625    }
626    else if (strcasecmp("dbm", type) == 0) {
627        sc->cache_type = mod_gnutls_cache_dbm;
628    }
629#if HAVE_APR_MEMCACHE
630    else if (strcasecmp("memcache", type) == 0) {
631        sc->cache_type = mod_gnutls_cache_memcache;
632    }
633#endif
634    else {
635        return "Invalid Type for GnuTLSCache!";
636    }
637
638    if (sc->cache_type == mod_gnutls_cache_dbm) {
639        sc->cache_config = ap_server_root_relative(parms->pool, arg);
640    }
641    else {
642        sc->cache_config = apr_pstrdup(parms->pool, arg);
643    }
644
645    return NULL;
646}
647
648static const char *gnutls_set_cache_timeout(cmd_parms * parms, void *dummy,
649                                            const char *arg)
650{
651    int argint;
652    mod_gnutls_srvconf_rec *sc =
653    (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server->
654                                                    module_config,
655                                                    &gnutls_module);
656   
657    argint = atoi(arg);
658   
659    if (argint < 0) {
660        return "GnuTLSCacheTimeout: Invalid argument";
661    }
662    else if (argint == 0) {
663        sc->cache_timeout = 0;
664    }
665    else {
666        sc->cache_timeout = apr_time_from_sec(argint);
667    }
668   
669    return NULL;
670}
671
672
673static const char *gnutls_set_client_verify(cmd_parms * parms, void *dummy,
674                                            const char *arg)
675{
676    gnutls_certificate_request_t mode;
677
678    if (strcasecmp("none", arg) == 0  || strcasecmp("ignore", arg) == 0) {
679        mode = GNUTLS_CERT_IGNORE;
680    }
681    else if (strcasecmp("optional", arg) == 0 || strcasecmp("request", arg) == 0) {
682        mode = GNUTLS_CERT_REQUEST;
683    }
684    else if (strcasecmp("optional", arg) == 0) {
685        mode = GNUTLS_CERT_REQUIRE;
686    }
687    else {
688        return "GnuTLSClientVerify: Invalid argument";
689    }
690   
691    /* This was set from a directory context */
692    if (parms->path) {
693        mod_gnutls_dirconf_rec *dc = (mod_gnutls_dirconf_rec *)dummy;
694        dc->client_verify_mode = mode;
695    }
696    else {
697        mod_gnutls_srvconf_rec *sc =
698        (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server->
699                                                        module_config,
700                                                        &gnutls_module);       
701        sc->client_verify_mode = mode;
702    }
703
704    return NULL;
705}
706static const char *gnutls_set_enabled(cmd_parms * parms, void *dummy,
707                                      const char *arg)
708{
709    mod_gnutls_srvconf_rec *sc =
710        (mod_gnutls_srvconf_rec *) ap_get_module_config(parms->server->
711                                                        module_config,
712                                                        &gnutls_module);
713    if (!strcasecmp(arg, "On")) {
714        sc->enabled = GNUTLS_ENABLED_TRUE;
715    }
716    else if (!strcasecmp(arg, "Off")) {
717        sc->enabled = GNUTLS_ENABLED_FALSE;
718    }
719    else {
720        return "GnuTLSEnable must be set to 'On' or 'Off'";
721    }
722
723    return NULL;
724}
725
726static const command_rec gnutls_cmds[] = {
727    AP_INIT_TAKE1("GnuTLSClientVerify", gnutls_set_client_verify,
728                  NULL,
729                  RSRC_CONF|OR_AUTHCFG,
730                  "Set Verification Requirements of the Client Certificate"),
731    AP_INIT_TAKE1("GnuTLSCertificateFile", gnutls_set_cert_file,
732                  NULL,
733                  RSRC_CONF,
734                  "SSL Server Key file"),
735    AP_INIT_TAKE1("GnuTLSKeyFile", gnutls_set_key_file,
736                  NULL,
737                  RSRC_CONF,
738                  "SSL Server Certificate file"),
739    AP_INIT_TAKE1("GnuTLSCacheTimeout", gnutls_set_cache_timeout,
740                  NULL,
741                  RSRC_CONF,
742                  "Cache Timeout"),
743    AP_INIT_TAKE2("GnuTLSCache", gnutls_set_cache,
744                  NULL,
745                  RSRC_CONF,
746                  "Cache Configuration"),
747    AP_INIT_TAKE1("GnuTLSEnable", gnutls_set_enabled,
748                  NULL, RSRC_CONF,
749                  "Whether this server has GnuTLS Enabled. Default: Off"),
750
751    {NULL}
752};
753
754/* TODO: CACertificateFile & Client Authentication
755 *    AP_INIT_TAKE1("GnuTLSCACertificateFile", ap_set_server_string_slot,
756 *                 (void *) APR_OFFSETOF(gnutls_srvconf_rec, key_file), NULL,
757 *                 RSRC_CONF,
758 *                 "CA"),
759 */
760
761int mod_gnutls_hook_authz(request_rec *r)
762{
763    return OK;
764#if 0
765    mod_gnutls_handle_t *ctxt;
766    mod_gnutls_dirconf_rec *dc = ap_get_module_config(r->per_dir_config,
767                                                      &gnutls_module);
768   
769    ctxt = ap_get_module_config(r->connection->conn_config, &gnutls_module);
770
771    if (dc->client_verify_mode == -1 ||
772        dc->client_verify_mode == GNUTLS_CERT_IGNORE ||
773        ctxt->sc->client_verify_mode > dc->client_verify_mode) {
774        return DECLINED;
775    }
776
777    gnutls_certificate_server_set_request(ctxt->session, dc->client_verify_mode);
778    if (mod_gnutls_rehandshake(ctxt) != 0) {
779        return HTTP_FORBIDDEN;
780    }
781#endif   
782}
783
784static void gnutls_hooks(apr_pool_t * p)
785{
786    ap_hook_pre_connection(mod_gnutls_hook_pre_connection, NULL, NULL,
787                           APR_HOOK_MIDDLE);
788    ap_hook_post_config(mod_gnutls_hook_post_config, NULL, NULL,
789                        APR_HOOK_MIDDLE);
790    ap_hook_child_init(mod_gnutls_hook_child_init, NULL, NULL,
791                        APR_HOOK_MIDDLE);
792#if USING_2_1_RECENT
793    ap_hook_http_scheme(mod_gnutls_hook_http_scheme, NULL, NULL,
794                        APR_HOOK_MIDDLE);
795#else
796    ap_hook_http_method(mod_gnutls_hook_http_scheme, NULL, NULL,
797                        APR_HOOK_MIDDLE);
798#endif
799    ap_hook_default_port(mod_gnutls_hook_default_port, NULL, NULL,
800                         APR_HOOK_MIDDLE);
801    ap_hook_pre_config(mod_gnutls_hook_pre_config, NULL, NULL,
802                       APR_HOOK_MIDDLE);
803   
804    ap_hook_auth_checker(mod_gnutls_hook_authz, NULL, NULL, APR_HOOK_MIDDLE);
805   
806    ap_hook_fixups(mod_gnutls_hook_fixups, NULL, NULL, APR_HOOK_REALLY_FIRST);
807
808    /* TODO: HTTP Upgrade Filter */
809    /* ap_register_output_filter ("UPGRADE_FILTER",
810     *          ssl_io_filter_Upgrade, NULL, AP_FTYPE_PROTOCOL + 5);
811     */
812    ap_register_input_filter(GNUTLS_INPUT_FILTER_NAME,
813                             mod_gnutls_filter_input, NULL,
814                             AP_FTYPE_CONNECTION + 5);
815    ap_register_output_filter(GNUTLS_OUTPUT_FILTER_NAME,
816                              mod_gnutls_filter_output, NULL,
817                              AP_FTYPE_CONNECTION + 5);
818}
819
820static void *gnutls_config_server_create(apr_pool_t * p, server_rec * s)
821{
822    int i;
823    mod_gnutls_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc));
824
825    sc->enabled = GNUTLS_ENABLED_FALSE;
826
827    gnutls_certificate_allocate_credentials(&sc->certs);
828    sc->privkey_x509 = NULL;
829    sc->cert_x509 = NULL;
830    sc->cache_timeout = apr_time_from_sec(300);
831    sc->cache_type = mod_gnutls_cache_dbm;
832    sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache");
833
834    /* TODO: Make this Configurable. But it isn't configurable in mod_ssl? */
835    sc->dh_params_file = ap_server_root_relative(p, "conf/dhfile");
836    sc->rsa_params_file = ap_server_root_relative(p, "conf/rsafile");
837
838    /* Finish SSL Client Certificate Support */
839    sc->client_verify_mode = GNUTLS_CERT_IGNORE;
840
841    /* TODO: Make this Configurable ! */
842    /* mod_ssl uses a flex based parser for this part.. sigh */
843    i = 0;
844    sc->ciphers[i++] = GNUTLS_CIPHER_AES_256_CBC;
845    sc->ciphers[i++] = GNUTLS_CIPHER_AES_128_CBC;
846    sc->ciphers[i++] = GNUTLS_CIPHER_ARCFOUR_128;
847    sc->ciphers[i++] = GNUTLS_CIPHER_3DES_CBC;
848    sc->ciphers[i++] = GNUTLS_CIPHER_ARCFOUR_40;
849    sc->ciphers[i] = 0;
850
851    i = 0;
852    sc->key_exchange[i++] = GNUTLS_KX_RSA;
853    sc->key_exchange[i++] = GNUTLS_KX_RSA_EXPORT;
854    sc->key_exchange[i++] = GNUTLS_KX_DHE_DSS;
855    sc->key_exchange[i++] = GNUTLS_KX_DHE_RSA;
856    sc->key_exchange[i++] = GNUTLS_KX_ANON_DH;
857    sc->key_exchange[i++] = GNUTLS_KX_SRP;
858    sc->key_exchange[i++] = GNUTLS_KX_SRP_RSA;
859    sc->key_exchange[i++] = GNUTLS_KX_SRP_DSS;
860    sc->key_exchange[i] = 0;
861
862    i = 0;
863    sc->macs[i++] = GNUTLS_MAC_SHA;
864    sc->macs[i++] = GNUTLS_MAC_MD5;
865    sc->macs[i++] = GNUTLS_MAC_RMD160;
866    sc->macs[i] = 0;
867
868    i = 0;
869    sc->protocol[i++] = GNUTLS_TLS1_1;
870    sc->protocol[i++] = GNUTLS_TLS1;
871    sc->protocol[i++] = GNUTLS_SSL3;
872    sc->protocol[i] = 0;
873
874    i = 0;
875    sc->compression[i++] = GNUTLS_COMP_NULL;
876    sc->compression[i++] = GNUTLS_COMP_ZLIB;
877    sc->compression[i++] = GNUTLS_COMP_LZO;
878    sc->compression[i] = 0;
879
880    i = 0;
881    sc->cert_types[i++] = GNUTLS_CRT_X509;
882    sc->cert_types[i] = 0;
883 
884    return sc;
885}
886
887void *gnutls_config_dir_create(apr_pool_t *p, char *dir)
888{
889    mod_gnutls_dirconf_rec *dc = apr_palloc(p, sizeof(*dc));
890
891    dc->client_verify_mode = -1;
892   
893    return dc;
894}
895
896module AP_MODULE_DECLARE_DATA gnutls_module = {
897    STANDARD20_MODULE_STUFF,
898    gnutls_config_dir_create,
899    NULL,
900    gnutls_config_server_create,
901    NULL,
902/*    gnutls_config_server_merge, */
903    gnutls_cmds,
904    gnutls_hooks
905};
Note: See TracBrowser for help on using the repository browser.