source: mod_gnutls/src/gnutls_config.c @ db9ef68

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

Deinit client CA list on config pool cleanup

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