source: mod_gnutls/src/mod_gnutls.c @ 32f2e60

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

fixes and stuff that i should of already committed.

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