source: mod_gnutls/src/gnutls_config.c @ 2cde026d

debian/masterdebian/stretch-backportsjessie-backportsupstream
Last change on this file since 2cde026d was 2cde026d, checked in by Thomas Klute <thomas2.klute@…>, 4 years ago

Merge branch 'new-gnutls-api'

Merge my TLS proxy implementation with Nikos Mavrogiannopoulos' changes
to use the new GnuTLS key handling API. Some conflicts had to be
resolved.

In Nikos' branch, structures for credentials and priorities are
allocated in mgs_load_files (gnutls_config.c), rather than during server
config structure creation as before. This makes sense, but his patch
doesn't consider the proxy credentials because they didn't exist at the
time.

To minimize additional changes during the merge, proxy credentials are
now allocated in load_proxy_x509_credentials (gnutls_hooks.c), and
mgs_set_priorities (gnutls_config.c) treats proxy and front end
credentials differently (value of GnuTLSPriorities is stored for
mgs_load_files, GnuTLSProxyPriorities is parsed immediately).

Unified handling of priority strings in mgs_set_priorities should be
restored later (towards parsing in post config), handling front end and
proxy credentials separately makes sense because the latter need only be
loaded when TLS proxy operation is enabled and there are some
differences between client (proxy back end) and server (front end)
operation.

  • Property mode set to 100644
File size: 32.6 KB
Line 
1/**
2 *  Copyright 2004-2005 Paul Querna
3 *  Copyright 2008 Nikos Mavrogiannopoulos
4 *  Copyright 2011 Dash Shendy
5 *
6 *  Licensed under the Apache License, Version 2.0 (the "License");
7 *  you may not use this file except in compliance with the License.
8 *  You may obtain a copy of the License at
9 *
10 *      http://www.apache.org/licenses/LICENSE-2.0
11 *
12 *  Unless required by applicable law or agreed to in writing, software
13 *  distributed under the License is distributed on an "AS IS" BASIS,
14 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 *  See the License for the specific language governing permissions and
16 *  limitations under the License.
17 *
18 */
19
20#include "mod_gnutls.h"
21#include "apr_lib.h"
22#include <gnutls/abstract.h>
23
24#define INIT_CA_SIZE 128
25
26#ifdef APLOG_USE_MODULE
27APLOG_USE_MODULE(gnutls);
28#endif
29
30static int pin_callback(void *user, int attempt __attribute__((unused)),
31                        const char *token_url __attribute__((unused)),
32                        const char *token_label, unsigned int flags,
33                        char *pin, size_t pin_max)
34{
35    mgs_srvconf_rec *sc = user;
36
37    if (sc->pin == NULL || flags & GNUTLS_PIN_FINAL_TRY ||
38        flags & GNUTLS_PIN_WRONG) {
39        return -1;
40    }
41
42    if (token_label && strcmp(token_label, "SRK") == 0) {
43         snprintf(pin, pin_max, "%s", sc->srk_pin);
44    } else {
45         snprintf(pin, pin_max, "%s", sc->pin);
46    }
47    return 0;
48}
49
50static int load_datum_from_file(apr_pool_t * pool,
51                                const char *file, gnutls_datum_t * data)
52{
53    apr_file_t *fp;
54    apr_finfo_t finfo;
55    apr_status_t rv;
56    apr_size_t br = 0;
57
58    rv = apr_file_open(&fp, file, APR_READ | APR_BINARY,
59                       APR_OS_DEFAULT, pool);
60    if (rv != APR_SUCCESS) {
61        return rv;
62    }
63
64    rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp);
65
66    if (rv != APR_SUCCESS) {
67        return rv;
68    }
69
70    data->data = apr_palloc(pool, finfo.size + 1);
71    rv = apr_file_read_full(fp, data->data, finfo.size, &br);
72
73    if (rv != APR_SUCCESS) {
74        return rv;
75    }
76    apr_file_close(fp);
77
78    data->data[br] = '\0';
79    data->size = br;
80
81    return 0;
82}
83
84/* 2048-bit group parameters from SRP specification */
85const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n"
86        "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"
87        "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"
88        "KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n"
89        "dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n"
90        "YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n"
91        "Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n"
92        "-----END DH PARAMETERS-----\n";
93
94int mgs_load_files(apr_pool_t * p, server_rec * s)
95{
96    apr_pool_t *spool;
97    const char *file;
98    gnutls_datum_t data;
99    int ret;
100    mgs_srvconf_rec *sc =
101        (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
102                                                 &gnutls_module);
103
104    apr_pool_create(&spool, p);
105
106    sc->cert_pgp = apr_pcalloc(p, sizeof(sc->cert_pgp[0]));
107    sc->cert_crt_pgp = apr_pcalloc(p, sizeof(sc->cert_crt_pgp[0]));
108    sc->certs_x509_chain =
109        apr_pcalloc(p, MAX_CHAIN_SIZE * sizeof(sc->certs_x509_chain[0]));
110    sc->certs_x509_crt_chain =
111        apr_pcalloc(p,
112                    MAX_CHAIN_SIZE * sizeof(sc->certs_x509_crt_chain[0]));
113
114    ret = gnutls_certificate_allocate_credentials(&sc->certs);
115    if (ret < 0) {
116        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
117                     "GnuTLS: Failed to initialize" ": (%d) %s", ret,
118                     gnutls_strerror(ret));
119        ret = -1;
120        goto cleanup;
121    }
122
123    ret = gnutls_anon_allocate_server_credentials(&sc->anon_creds);
124    if (ret < 0) {
125        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
126                     "GnuTLS: Failed to initialize" ": (%d) %s", ret,
127                     gnutls_strerror(ret));
128        ret = -1;
129        goto cleanup;
130    }
131
132    /* Load SRP parameters */
133#ifdef ENABLE_SRP
134    ret = gnutls_srp_allocate_server_credentials(&sc->srp_creds);
135    if (ret < 0) {
136        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
137                     "GnuTLS: Failed to initialize" ": (%d) %s", ret,
138                     gnutls_strerror(ret));
139        ret = -1;
140        goto cleanup;
141    }
142
143    if (sc->srp_tpasswd_conf_file != NULL && sc->srp_tpasswd_file != NULL) {
144        ret = gnutls_srp_set_server_credentials_file
145            (sc->srp_creds, sc->srp_tpasswd_file,
146             sc->srp_tpasswd_conf_file);
147
148        if (ret < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) {
149            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0,
150                         s,
151                         "GnuTLS: Host '%s:%d' is missing a "
152                         "SRP password or conf File!",
153                         s->server_hostname, s->port);
154            ret = -1;
155            goto cleanup;
156        }
157    }
158#endif
159
160    ret = gnutls_dh_params_init(&sc->dh_params);
161    if (ret < 0) {
162            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
163                         "GnuTLS: Failed to initialize"
164                         ": (%d) %s", ret, gnutls_strerror(ret));
165            ret = -1;
166            goto cleanup;
167    }
168
169    /* Load DH parameters */
170    if (sc->dh_file) {
171        if (load_datum_from_file(spool, sc->dh_file, &data) != 0) {
172            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
173                         "GnuTLS: Error Reading " "DH params '%s'", sc->dh_file);
174            ret = -1;
175            goto cleanup;
176        }
177
178        ret =
179            gnutls_dh_params_import_pkcs3(sc->dh_params, &data,
180                                          GNUTLS_X509_FMT_PEM);
181        if (ret < 0) {
182            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
183                         "GnuTLS: Failed to Import "
184                         "DH params '%s': (%d) %s", sc->dh_file, ret,
185                         gnutls_strerror(ret));
186            ret = -1;
187            goto cleanup;
188        }
189    } else {
190        gnutls_datum_t pdata = {
191            (void *) static_dh_params,
192            sizeof(static_dh_params)
193        };
194
195        ret = gnutls_dh_params_import_pkcs3(sc->dh_params, &pdata, GNUTLS_X509_FMT_PEM);
196        if (ret < 0) {
197            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
198                    "GnuTLS: Unable to generate or load DH Params: (%d) %s",
199                    ret, gnutls_strerror(ret));
200            ret = -1;
201            goto cleanup;
202        }
203    }
204
205    if (sc->x509_cert_file != NULL) {
206        unsigned int chain_num, i;
207        unsigned format = GNUTLS_X509_FMT_PEM;
208
209        /* Load X.509 certificate */
210        if (strncmp(sc->x509_cert_file, "pkcs11:", 7) == 0) {
211            gnutls_pkcs11_obj_t obj;
212
213            file = sc->x509_cert_file;
214
215            ret = gnutls_pkcs11_obj_init(&obj);
216            if (ret < 0) {
217                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
218                             "GnuTLS: Error Initializing PKCS #11 object");
219                ret = -1;
220                goto cleanup;
221            }
222
223            gnutls_pkcs11_obj_set_pin_function(obj, pin_callback, sc);
224
225            ret = gnutls_pkcs11_obj_import_url(obj, file, GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
226            if (ret < 0) {
227                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
228                             "GnuTLS: Error Importing PKCS #11 object: '%s': %s",
229                             file, gnutls_strerror(ret));
230                ret = -1;
231                goto cleanup;
232            }
233
234            format = GNUTLS_X509_FMT_DER;
235            ret = gnutls_pkcs11_obj_export2(obj, &data);
236            if (ret < 0) {
237                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
238                             "GnuTLS: Error Exporting a PKCS #11 object: '%s': %s",
239                             file, gnutls_strerror(ret));
240                ret = -1;
241                goto cleanup;
242            }
243
244            gnutls_pkcs11_obj_deinit(obj);
245        } else {
246            file = ap_server_root_relative(spool, sc->x509_cert_file);
247
248            ret = gnutls_load_file(file, &data);
249            if (ret < 0) {
250                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
251                             "GnuTLS: Error Reading Certificate '%s': %s",
252                             file, gnutls_strerror(ret));
253                ret = -1;
254                goto cleanup;
255            }
256        }
257
258        ret =
259            gnutls_x509_crt_list_import2(&sc->certs_x509_crt_chain,
260                                        &chain_num, &data, format,
261                                        GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED);
262        gnutls_free(data.data);
263        sc->certs_x509_chain_num = chain_num;
264
265        if (ret < 0) {
266            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
267                         "GnuTLS: Failed to Import Certificate Chain '%s': (%d) %s",
268                         file, ret, gnutls_strerror(ret));
269            ret = -1;
270            goto cleanup;
271        }
272
273        for (i = 0; i < chain_num; i++) {
274            ret =
275                gnutls_pcert_import_x509(&sc->certs_x509_chain[i],
276                                         sc->certs_x509_crt_chain[i], 0);
277            if (ret < 0) {
278                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
279                             "GnuTLS: Failed to Import pCertificate '%s': (%d) %s",
280                             file, ret, gnutls_strerror(ret));
281                ret = -1;
282                goto cleanup;
283            }
284        }
285        sc->certs_x509_chain_num = chain_num;
286    }
287
288    if (sc->x509_key_file) {
289        ret = gnutls_privkey_init(&sc->privkey_x509);
290        if (ret < 0) {
291            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
292                         "GnuTLS: Failed to initialize: (%d) %s", ret,
293                         gnutls_strerror(ret));
294            ret = -1;
295            goto cleanup;
296        }
297
298        if (gnutls_url_is_supported(sc->x509_key_file) != 0) {
299            file = sc->x509_key_file;
300
301            gnutls_privkey_set_pin_function(sc->privkey_x509, pin_callback,
302                                            sc);
303
304            ret = gnutls_privkey_import_url(sc->privkey_x509, file, 0);
305
306            if (ret < 0) {
307                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
308                             "GnuTLS: Failed to Import Private Key URL '%s': (%d) %s",
309                             file, ret, gnutls_strerror(ret));
310                ret = -1;
311                goto cleanup;
312            }
313        } else {
314            file = ap_server_root_relative(spool, sc->x509_key_file);
315
316            if (load_datum_from_file(spool, file, &data) != 0) {
317                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
318                             "GnuTLS: Error Reading Private Key '%s'",
319                             file);
320                ret = -1;
321                goto cleanup;
322            }
323
324            ret =
325                gnutls_privkey_import_x509_raw(sc->privkey_x509, &data,
326                                               GNUTLS_X509_FMT_PEM, sc->pin,
327                                               0);
328
329            if (ret < 0) {
330                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
331                             "GnuTLS: Failed to Import Private Key '%s': (%d) %s",
332                             file, ret, gnutls_strerror(ret));
333                ret = -1;
334                goto cleanup;
335            }
336        }
337    }
338
339    /* Load the X.509 CA file */
340    if (sc->x509_ca_file) {
341        if (load_datum_from_file(spool, sc->x509_ca_file, &data) != 0) {
342            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
343                         "GnuTLS: Error Reading " "Client CA File '%s'",
344                         sc->x509_ca_file);
345            ret = -1;
346            goto cleanup;
347        }
348
349        ret = gnutls_x509_crt_list_import2(&sc->ca_list, &sc->ca_list_size,
350                                         &data, GNUTLS_X509_FMT_PEM, 0);
351        if (ret < 0) {
352            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
353                         "GnuTLS: Failed to load "
354                         "Client CA File '%s': (%d) %s", sc->x509_ca_file,
355                         ret, gnutls_strerror(ret));
356            ret = -1;
357            goto cleanup;
358        }
359    }
360
361    if (sc->pgp_cert_file) {
362        if (load_datum_from_file(spool, sc->pgp_cert_file, &data) != 0) {
363            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
364                         "GnuTLS: Error Reading " "Certificate '%s'",
365                         sc->pgp_cert_file);
366            ret = -1;
367            goto cleanup;
368        }
369
370        ret = gnutls_openpgp_crt_init(&sc->cert_crt_pgp[0]);
371        if (ret < 0) {
372            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
373                         "GnuTLS: Failed to Init "
374                         "PGP Certificate: (%d) %s", ret,
375                         gnutls_strerror(ret));
376            ret = -1;
377            goto cleanup;
378        }
379
380        ret =
381            gnutls_openpgp_crt_import(sc->cert_crt_pgp[0], &data,
382                                      GNUTLS_OPENPGP_FMT_BASE64);
383        if (ret < 0) {
384            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
385                         "GnuTLS: Failed to Import "
386                         "PGP Certificate: (%d) %s", ret,
387                         gnutls_strerror(ret));
388            ret = -1;
389            goto cleanup;
390        }
391
392        ret =
393            gnutls_pcert_import_openpgp(sc->cert_pgp, sc->cert_crt_pgp[0],
394                                        0);
395        if (ret < 0) {
396            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
397                         "GnuTLS: Failed to Import "
398                         "PGP pCertificate: (%d) %s", ret,
399                         gnutls_strerror(ret));
400            ret = -1;
401            goto cleanup;
402        }
403    }
404
405    /* Load the PGP key file */
406    if (sc->pgp_key_file) {
407        if (load_datum_from_file(spool, sc->pgp_key_file, &data) != 0) {
408            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
409                         "GnuTLS: Error Reading " "Private Key '%s'",
410                         sc->pgp_key_file);
411            ret = -1;
412            goto cleanup;
413        }
414
415        ret = gnutls_privkey_init(&sc->privkey_pgp);
416        if (ret < 0) {
417            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
418                         "GnuTLS: Failed to initialize"
419                         ": (%d) %s", ret, gnutls_strerror(ret));
420            ret = -1;
421            goto cleanup;
422        }
423
424#if GNUTLS_VERSION_NUMBER < 0x030312
425        /* GnuTLS versions before 3.3.12 contain a bug in
426         * gnutls_privkey_import_openpgp_raw which frees data that is
427         * accessed when the key is used, leading to segfault. Loading
428         * the key into a gnutls_openpgp_privkey_t and then assigning
429         * it to the gnutls_privkey_t works around the bug, hence this
430         * chain of gnutls_openpgp_privkey_init,
431         * gnutls_openpgp_privkey_import and
432         * gnutls_privkey_import_openpgp. */
433        ret = gnutls_openpgp_privkey_init(&sc->privkey_pgp_internal);
434        if (ret != 0) {
435            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
436                         "GnuTLS: Failed to initialize "
437                         "PGP Private Key '%s': (%d) %s",
438                         sc->pgp_key_file, ret, gnutls_strerror(ret));
439            ret = -1;
440            goto cleanup;
441        }
442
443        ret = gnutls_openpgp_privkey_import(sc->privkey_pgp_internal, &data,
444                                            GNUTLS_OPENPGP_FMT_BASE64, NULL, 0);
445        if (ret != 0) {
446            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
447                         "GnuTLS: Failed to Import "
448                         "PGP Private Key '%s': (%d) %s",
449                         sc->pgp_key_file, ret, gnutls_strerror(ret));
450            ret = -1;
451            goto cleanup;
452        }
453
454        ret = gnutls_privkey_import_openpgp(sc->privkey_pgp,
455                                            sc->privkey_pgp_internal, 0);
456        if (ret != 0)
457        {
458            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
459                         "GnuTLS: Failed to assign PGP Private Key '%s' "
460                         "to gnutls_privkey_t structure: (%d) %s",
461                         sc->pgp_key_file, ret, gnutls_strerror(ret));
462            ret = -1;
463            goto cleanup;
464        }
465#else
466        ret = gnutls_privkey_import_openpgp_raw(sc->privkey_pgp, &data,
467                                                GNUTLS_OPENPGP_FMT_BASE64,
468                                                NULL, NULL);
469        if (ret != 0)
470        {
471            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
472                         "GnuTLS: Failed to Import "
473                         "PGP Private Key '%s': (%d) %s",
474                         sc->pgp_key_file, ret, gnutls_strerror(ret));
475            ret = -1;
476            goto cleanup;
477        }
478#endif
479    }
480
481    /* Load the keyring file */
482    if (sc->pgp_ring_file) {
483        if (load_datum_from_file(spool, sc->pgp_ring_file, &data) != 0) {
484            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
485                         "GnuTLS: Error Reading " "Keyring File '%s'",
486                         sc->pgp_ring_file);
487            ret = -1;
488            goto cleanup;
489        }
490
491        ret = gnutls_openpgp_keyring_init(&sc->pgp_list);
492        if (ret < 0) {
493            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
494                         "GnuTLS: Failed to initialize"
495                         "keyring: (%d) %s", ret, gnutls_strerror(ret));
496            ret = -1;
497            goto cleanup;
498        }
499
500        ret = gnutls_openpgp_keyring_import(sc->pgp_list, &data,
501                                           GNUTLS_OPENPGP_FMT_BASE64);
502        if (ret < 0) {
503            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
504                         "GnuTLS: Failed to load "
505                         "Keyring File '%s': (%d) %s", sc->pgp_ring_file,
506                         ret, gnutls_strerror(ret));
507            ret = -1;
508            goto cleanup;
509        }
510    }
511
512    if (sc->priorities_str) {
513        const char *err;
514        ret = gnutls_priority_init(&sc->priorities, sc->priorities_str, &err);
515
516        if (ret < 0) {
517            if (ret == GNUTLS_E_INVALID_REQUEST) {
518                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
519                             "GnuTLS: Syntax error parsing priorities string at: %s",
520                             err);
521            } else {
522                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
523                             "GnuTLS: error parsing priorities string");
524
525            }
526            ret = -1;
527            goto cleanup;
528        }
529    }
530
531    ret = 0;
532  cleanup:
533    apr_pool_destroy(spool);
534
535    return ret;
536}
537
538int mgs_pkcs11_reinit(server_rec * base_server)
539{
540    int ret;
541    server_rec *s;
542    mgs_srvconf_rec *sc;
543
544    gnutls_pkcs11_reinit();
545
546    for (s = base_server; s; s = s->next) {
547        sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
548
549            /* gnutls caches the session in a private key, so we need to open
550             * a new one */
551            if (sc->x509_key_file && gnutls_url_is_supported(sc->x509_key_file) != 0) {
552                gnutls_privkey_deinit(sc->privkey_x509);
553
554                ret = gnutls_privkey_init(&sc->privkey_x509);
555                if (ret < 0) {
556                    ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
557                                 "GnuTLS: Failed to initialize: (%d) %s", ret,
558                                 gnutls_strerror(ret));
559                    goto fail;
560                }
561
562                gnutls_privkey_set_pin_function(sc->privkey_x509, pin_callback, sc);
563
564                ret = gnutls_privkey_import_url(sc->privkey_x509, sc->x509_key_file, 0);
565                if (ret < 0) {
566                    ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
567                             "GnuTLS: Failed to Re-Import Private Key URL '%s': (%d) %s",
568                             sc->x509_key_file, ret, gnutls_strerror(ret));
569                    goto fail;
570                }
571            }
572    }
573
574    return 0;
575
576 fail:
577    gnutls_privkey_deinit(sc->privkey_x509);
578    return -1;
579}
580
581const char *mgs_set_dh_file(cmd_parms * parms, void *dummy __attribute__((unused)),
582        const char *arg) {
583    mgs_srvconf_rec *sc =
584        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
585                                                 module_config,
586                                                 &gnutls_module);
587
588    sc->dh_file = ap_server_root_relative(parms->pool, arg);
589
590    return NULL;
591}
592
593const char *mgs_set_cert_file(cmd_parms * parms, void *dummy __attribute__((unused)), const char *arg) {
594
595    mgs_srvconf_rec *sc =
596        (mgs_srvconf_rec *) ap_get_module_config(parms->
597                                                 server->module_config,
598                                                 &gnutls_module);
599
600    sc->x509_cert_file = apr_pstrdup(parms->pool, arg);
601
602    return NULL;
603
604}
605
606const char *mgs_set_key_file(cmd_parms * parms, void *dummy __attribute__((unused)), const char *arg) {
607
608    mgs_srvconf_rec *sc =
609        (mgs_srvconf_rec *) ap_get_module_config(parms->
610                                                 server->module_config,
611                                                 &gnutls_module);
612
613    sc->x509_key_file = apr_pstrdup(parms->pool, arg);
614
615    return NULL;
616}
617
618const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy __attribute__((unused)),
619        const char *arg)
620{
621    mgs_srvconf_rec *sc =
622        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
623                                                 module_config,
624                                                 &gnutls_module);
625
626    sc->pgp_cert_file = ap_server_root_relative(parms->pool, arg);
627
628    return NULL;
629}
630
631const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy __attribute__((unused)),
632        const char *arg) {
633    mgs_srvconf_rec *sc =
634        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
635                                                 module_config,
636                                                 &gnutls_module);
637
638    sc->pgp_key_file = ap_server_root_relative(parms->pool, arg);
639
640    return NULL;
641}
642
643const char *mgs_set_tickets(cmd_parms * parms, void *dummy __attribute__((unused)),
644        const char *arg) {
645    mgs_srvconf_rec *sc =
646        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
647                                                 module_config,
648                                                 &gnutls_module);
649
650    sc->tickets = 0;
651    if (strcasecmp("on", arg) == 0) {
652        sc->tickets = 1;
653    }
654
655    return NULL;
656}
657
658
659#ifdef ENABLE_SRP
660
661const char *mgs_set_srp_tpasswd_file(cmd_parms * parms, void *dummy __attribute__((unused)),
662        const char *arg) {
663    mgs_srvconf_rec *sc =
664        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
665                                                 module_config,
666                                                 &gnutls_module);
667
668    sc->srp_tpasswd_file = ap_server_root_relative(parms->pool, arg);
669
670    return NULL;
671}
672
673const char *mgs_set_srp_tpasswd_conf_file(cmd_parms * parms, void *dummy __attribute__((unused)),
674        const char *arg) {
675    mgs_srvconf_rec *sc =
676        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
677                                                 module_config,
678                                                 &gnutls_module);
679
680    sc->srp_tpasswd_conf_file = ap_server_root_relative(parms->pool, arg);
681
682    return NULL;
683}
684
685#endif
686
687const char *mgs_set_cache(cmd_parms * parms, void *dummy __attribute__((unused)),
688        const char *type, const char *arg) {
689    const char *err;
690    mgs_srvconf_rec *sc =
691        ap_get_module_config(parms->server->module_config,
692                             &gnutls_module);
693    if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
694        return err;
695    }
696
697    if (strcasecmp("none", type) == 0) {
698        sc->cache_type = mgs_cache_none;
699        sc->cache_config = NULL;
700        return NULL;
701    } else if (strcasecmp("dbm", type) == 0) {
702        sc->cache_type = mgs_cache_dbm;
703    } else if (strcasecmp("gdbm", type) == 0) {
704        sc->cache_type = mgs_cache_gdbm;
705    }
706#if HAVE_APR_MEMCACHE
707    else if (strcasecmp("memcache", type) == 0) {
708        sc->cache_type = mgs_cache_memcache;
709    }
710#endif
711    else {
712        return "Invalid Type for GnuTLSCache!";
713    }
714
715    if (arg == NULL)
716        return "Invalid argument 2 for GnuTLSCache!";
717
718    if (sc->cache_type == mgs_cache_dbm
719        || sc->cache_type == mgs_cache_gdbm) {
720        sc->cache_config = ap_server_root_relative(parms->pool, arg);
721    } else {
722        sc->cache_config = apr_pstrdup(parms->pool, arg);
723    }
724
725    return NULL;
726}
727
728const char *mgs_set_cache_timeout(cmd_parms * parms, void *dummy __attribute__((unused)),
729        const char *arg) {
730    int argint;
731    const char *err;
732    mgs_srvconf_rec *sc =
733        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
734                                                 module_config,
735                                                 &gnutls_module);
736
737    if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
738        return err;
739    }
740
741    argint = atoi(arg);
742
743    if (argint < 0) {
744        return "GnuTLSCacheTimeout: Invalid argument";
745    } else if (argint == 0) {
746        sc->cache_timeout = 0;
747    } else {
748        sc->cache_timeout = apr_time_from_sec(argint);
749    }
750
751    return NULL;
752}
753
754const char *mgs_set_client_verify_method(cmd_parms * parms, void *dummy __attribute__((unused)),
755        const char *arg) {
756    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)ap_get_module_config(parms->server->module_config, &gnutls_module);
757
758    if (strcasecmp("cartel", arg) == 0) {
759        sc->client_verify_method = mgs_cvm_cartel;
760    } else if (strcasecmp("msva", arg) == 0) {
761#ifdef ENABLE_MSVA
762        sc->client_verify_method = mgs_cvm_msva;
763#else
764        return "GnuTLSClientVerifyMethod: msva is not supported";
765#endif
766    } else {
767        return "GnuTLSClientVerifyMethod: Invalid argument";
768    }
769
770    return NULL;
771}
772
773const char *mgs_set_client_verify(cmd_parms * parms,
774                                  void *dirconf,
775                                  const char *arg) {
776    int mode;
777
778    if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) {
779        mode = GNUTLS_CERT_IGNORE;
780    } else if (strcasecmp("optional", arg) == 0
781               || strcasecmp("request", arg) == 0) {
782        mode = GNUTLS_CERT_REQUEST;
783    } else if (strcasecmp("require", arg) == 0) {
784        mode = GNUTLS_CERT_REQUIRE;
785    } else {
786        return "GnuTLSClientVerify: Invalid argument";
787    }
788
789    /* This was set from a directory context */
790    if (parms->path) {
791        mgs_dirconf_rec *dc = (mgs_dirconf_rec *) dirconf;
792        dc->client_verify_mode = mode;
793    } else {
794        mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
795            ap_get_module_config(parms->server->module_config,
796                                 &gnutls_module);
797        sc->client_verify_mode = mode;
798    }
799
800    return NULL;
801}
802
803const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy __attribute__((unused)),
804        const char *arg) {
805    mgs_srvconf_rec *sc =
806        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
807                                                 module_config,
808                                                 &gnutls_module);
809
810    sc->x509_ca_file = ap_server_root_relative(parms->pool, arg);
811
812    return NULL;
813}
814
815const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy __attribute__((unused)),
816        const char *arg) {
817    mgs_srvconf_rec *sc =
818        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
819                                                 module_config,
820                                                 &gnutls_module);
821
822    sc->pgp_ring_file = ap_server_root_relative(parms->pool, arg);
823
824    return NULL;
825}
826
827const char *mgs_set_proxy_engine(cmd_parms * parms, void *dummy __attribute__((unused)),
828        const char *arg) {
829
830    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
831        ap_get_module_config(parms->server->module_config, &gnutls_module);
832
833    if (!strcasecmp(arg, "On")) {
834        sc->proxy_enabled = GNUTLS_ENABLED_TRUE;
835    } else if (!strcasecmp(arg, "Off")) {
836        sc->proxy_enabled = GNUTLS_ENABLED_FALSE;
837    } else {
838        return "SSLProxyEngine must be set to 'On' or 'Off'";
839    }
840
841    return NULL;
842}
843
844const char *mgs_set_enabled(cmd_parms * parms, void *dummy __attribute__((unused)),
845        const char *arg) {
846    mgs_srvconf_rec *sc =
847        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
848                                                 module_config,
849                                                 &gnutls_module);
850    if (!strcasecmp(arg, "On")) {
851        sc->enabled = GNUTLS_ENABLED_TRUE;
852    } else if (!strcasecmp(arg, "Off")) {
853        sc->enabled = GNUTLS_ENABLED_FALSE;
854    } else {
855        return "GnuTLSEnable must be set to 'On' or 'Off'";
856    }
857
858    return NULL;
859}
860
861const char *mgs_set_export_certificates_size(cmd_parms * parms, void *dummy __attribute__((unused)), const char *arg) {
862    mgs_srvconf_rec *sc = (mgs_srvconf_rec *) ap_get_module_config(parms->server->module_config, &gnutls_module);
863    if (!strcasecmp(arg, "On")) {
864        sc->export_certificates_size = 16 * 1024;
865    } else if (!strcasecmp(arg, "Off")) {
866        sc->export_certificates_size = 0;
867    } else {
868        char *endptr;
869        sc->export_certificates_size = strtol(arg, &endptr, 10);
870        while (apr_isspace(*endptr))
871            endptr++;
872        if (*endptr == '\0' || *endptr == 'b' || *endptr == 'B') {
873            ;
874        } else if (*endptr == 'k' || *endptr == 'K') {
875            sc->export_certificates_size *= 1024;
876        } else {
877            return
878                "GnuTLSExportCertificates must be set to a size (in bytes) or 'On' or 'Off'";
879        }
880    }
881
882    return NULL;
883}
884
885
886
887/*
888 * Initialize a GnuTLS priorities cache from a configuration
889 * string. Used for GnuTLSPriorities and GnuTLSProxyPriorities.
890 */
891const char *mgs_set_priorities(cmd_parms * parms,
892                               void *dummy __attribute__((unused)),
893                               const char *arg)
894{
895    int ret;
896    const char *err;
897
898    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
899        ap_get_module_config(parms->server->module_config, &gnutls_module);
900
901    /* Setting a priority cache works the same no matter for which
902     * option. Just point the pointer at the right one. */
903    gnutls_priority_t *prio = NULL;
904    if (!strcasecmp(parms->directive->directive, "GnuTLSPriorities"))
905    {
906        /* save string to be handled in mgs_load_files
907         *
908         * TODO: return to one wany of handling priorities for front
909         * end and proxy connections */
910        sc->priorities_str = apr_pstrdup(parms->pool, arg);
911        return NULL;
912        /* prio = &sc->priorities; */
913    }
914    else if (!strcasecmp(parms->directive->directive, "GnuTLSProxyPriorities"))
915        prio = &sc->proxy_priorities;
916    else
917        /* Can't happen unless there's a serious bug in mod_gnutls or Apache */
918        return apr_psprintf(parms->pool,
919                            "mod_gnutls: %s called for invalid option '%s'",
920                            __func__, parms->directive->directive);
921
922    ret = gnutls_priority_init(prio, arg, &err);
923    if (ret < 0)
924    {
925        if (ret == GNUTLS_E_INVALID_REQUEST)
926            return apr_psprintf(parms->pool,
927                                "mod_gnutls: Syntax error parsing priorities "
928                                "string for %s at: %s",
929                                parms->directive->directive, err);
930        return  apr_psprintf(parms->pool,
931                             "Error setting priorities: %s (%d)",
932                             gnutls_strerror(ret), ret);
933    }
934
935    return NULL;
936}
937
938
939
940const char *mgs_set_pin(cmd_parms * parms, void *dummy __attribute__((unused)),
941                        const char *arg)
942{
943
944    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
945        ap_get_module_config(parms->server->module_config, &gnutls_module);
946
947    sc->pin = apr_pstrdup(parms->pool, arg);
948
949    return NULL;
950}
951
952const char *mgs_set_srk_pin(cmd_parms * parms,
953                            void *dummy __attribute__((unused)),
954                            const char *arg)
955{
956
957    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
958        ap_get_module_config(parms->server->module_config, &gnutls_module);
959
960    sc->srk_pin = apr_pstrdup(parms->pool, arg);
961
962    return NULL;
963}
964
965
966
967static mgs_srvconf_rec *_mgs_config_server_create(apr_pool_t * p,
968                                                  char **err __attribute__((unused)))
969{
970    mgs_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc));
971
972    sc->enabled = GNUTLS_ENABLED_UNSET;
973
974    sc->privkey_x509 = NULL;
975    sc->privkey_pgp = NULL;
976    sc->certs_x509_chain_num = 0;
977    sc->pin = NULL;
978    sc->priorities_str = NULL;
979    sc->cache_timeout = -1;     /* -1 means "unset" */
980    sc->cache_type = mgs_cache_unset;
981    sc->cache_config = NULL;
982    sc->tickets = GNUTLS_ENABLED_UNSET;
983    sc->priorities = NULL;
984    sc->dh_params = NULL;
985    sc->proxy_enabled = GNUTLS_ENABLED_UNSET;
986    sc->export_certificates_size = -1;
987    sc->client_verify_method = mgs_cvm_unset;
988
989    sc->proxy_x509_key_file = NULL;
990    sc->proxy_x509_cert_file = NULL;
991    sc->proxy_x509_ca_file = NULL;
992    sc->proxy_x509_crl_file = NULL;
993    sc->proxy_priorities = NULL;
994
995/* this relies on GnuTLS never changing the gnutls_certificate_request_t enum to define -1 */
996    sc->client_verify_mode = -1;
997
998    return sc;
999}
1000
1001void *mgs_config_server_create(apr_pool_t * p,
1002                               server_rec * s __attribute__((unused))) {
1003    char *err = NULL;
1004    mgs_srvconf_rec *sc = _mgs_config_server_create(p, &err);
1005    if (sc)
1006        return sc;
1007    else
1008        return err;
1009}
1010
1011#define gnutls_srvconf_merge(t, unset) sc->t = (add->t == unset) ? base->t : add->t
1012#define gnutls_srvconf_assign(t) sc->t = add->t
1013
1014void *mgs_config_server_merge(apr_pool_t * p, void *BASE, void *ADD)
1015{
1016    int i;
1017    char *err = NULL;
1018    mgs_srvconf_rec *base = (mgs_srvconf_rec *) BASE;
1019    mgs_srvconf_rec *add = (mgs_srvconf_rec *) ADD;
1020    mgs_srvconf_rec *sc = _mgs_config_server_create(p, &err);
1021    if (NULL == sc)
1022        return err;
1023
1024    gnutls_srvconf_merge(enabled, GNUTLS_ENABLED_UNSET);
1025    gnutls_srvconf_merge(tickets, GNUTLS_ENABLED_UNSET);
1026    gnutls_srvconf_merge(proxy_enabled, GNUTLS_ENABLED_UNSET);
1027    gnutls_srvconf_merge(export_certificates_size, -1);
1028    gnutls_srvconf_merge(client_verify_method, mgs_cvm_unset);
1029    gnutls_srvconf_merge(client_verify_mode, -1);
1030    gnutls_srvconf_merge(srp_tpasswd_file, NULL);
1031    gnutls_srvconf_merge(srp_tpasswd_conf_file, NULL);
1032    gnutls_srvconf_merge(x509_cert_file, NULL);
1033
1034    gnutls_srvconf_merge(x509_key_file, NULL);
1035    gnutls_srvconf_merge(x509_ca_file, NULL);
1036    gnutls_srvconf_merge(pin, NULL);
1037    gnutls_srvconf_merge(pgp_cert_file, NULL);
1038    gnutls_srvconf_merge(pgp_key_file, NULL);
1039    gnutls_srvconf_merge(pgp_ring_file, NULL);
1040    gnutls_srvconf_merge(dh_file, NULL);
1041    gnutls_srvconf_merge(priorities_str, NULL);
1042
1043    gnutls_srvconf_merge(proxy_x509_key_file, NULL);
1044    gnutls_srvconf_merge(proxy_x509_cert_file, NULL);
1045    gnutls_srvconf_merge(proxy_x509_ca_file, NULL);
1046    gnutls_srvconf_merge(proxy_x509_crl_file, NULL);
1047    gnutls_srvconf_merge(proxy_priorities, NULL);
1048
1049    /* FIXME: the following items are pre-allocated, and should be
1050     * properly disposed of before assigning in order to avoid leaks;
1051     * so at the moment, we can't actually have them in the config.
1052     * what happens during de-allocation? */
1053    /* TODO: mgs_load_files takes care of most of these now, verify
1054     * and clean up the following lines */
1055    gnutls_srvconf_assign(ca_list);
1056    gnutls_srvconf_assign(ca_list_size);
1057    gnutls_srvconf_assign(cert_pgp);
1058    gnutls_srvconf_assign(cert_crt_pgp);
1059    gnutls_srvconf_assign(pgp_list);
1060    gnutls_srvconf_assign(certs);
1061    gnutls_srvconf_assign(anon_creds);
1062    gnutls_srvconf_assign(srp_creds);
1063    gnutls_srvconf_assign(certs_x509_chain);
1064    gnutls_srvconf_assign(certs_x509_crt_chain);
1065    gnutls_srvconf_assign(certs_x509_chain_num);
1066
1067    /* how do these get transferred cleanly before the data from ADD
1068     * goes away? */
1069    gnutls_srvconf_assign(cert_cn);
1070    for (i = 0; i < MAX_CERT_SAN; i++)
1071        gnutls_srvconf_assign(cert_san[i]);
1072
1073    return sc;
1074}
1075
1076#undef gnutls_srvconf_merge
1077#undef gnutls_srvconf_assign
1078
1079void *mgs_config_dir_merge(apr_pool_t * p,
1080                           void *basev __attribute__((unused)),
1081                           void *addv __attribute__((unused))) {
1082    mgs_dirconf_rec *new;
1083    /*    mgs_dirconf_rec *base = (mgs_dirconf_rec *) basev; */
1084    mgs_dirconf_rec *add = (mgs_dirconf_rec *) addv;
1085
1086    new = (mgs_dirconf_rec *) apr_pcalloc(p, sizeof(mgs_dirconf_rec));
1087    new->client_verify_mode = add->client_verify_mode;
1088    return new;
1089}
1090
1091void *mgs_config_dir_create(apr_pool_t * p,
1092                            char *dir __attribute__((unused))) {
1093    mgs_dirconf_rec *dc = apr_palloc(p, sizeof (*dc));
1094    dc->client_verify_mode = -1;
1095    return dc;
1096}
1097
1098
1099
1100/*
1101 * Store paths to proxy credentials
1102 *
1103 * This function copies the paths provided in the configuration file
1104 * into the server configuration. The post configuration hook takes
1105 * care of actually loading the credentials, which means than invalid
1106 * paths or the like will be detected there.
1107 */
1108const char *mgs_store_cred_path(cmd_parms * parms,
1109                                void *dummy __attribute__((unused)),
1110                                const char *arg)
1111{
1112    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
1113        ap_get_module_config(parms->server->module_config, &gnutls_module);
1114
1115    /* parms->directive->directive contains the directive string */
1116    if (!strcasecmp(parms->directive->directive, "GnuTLSProxyKeyFile"))
1117        sc->proxy_x509_key_file = apr_pstrdup(parms->pool, arg);
1118    else if (!strcasecmp(parms->directive->directive,
1119                         "GnuTLSProxyCertificateFile"))
1120        sc->proxy_x509_cert_file = apr_pstrdup(parms->pool, arg);
1121    else if (!strcasecmp(parms->directive->directive, "GnuTLSProxyCAFile"))
1122        sc->proxy_x509_ca_file = apr_pstrdup(parms->pool, arg);
1123    else if (!strcasecmp(parms->directive->directive, "GnuTLSProxyCRLFile"))
1124        sc->proxy_x509_crl_file = apr_pstrdup(parms->pool, arg);
1125    return NULL;
1126}
Note: See TracBrowser for help on using the repository browser.