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

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

Workarounds for OpenPGP key handling

Commit 031acac9c6541034777f8917633164b51f6bd10a 'Use the new (3.1.3+)
GnuTLS APIs to obtain private keys' led to failed handshakes when using
OpenPGP keys for authentication. Debugging revealed two separate issues,
this commit adds workarounds for both.

The first problem was that the supported certificate types for the
session were not set correctly. This is a known bug in
gnutls_certificate_set_retrieve_function2 [1], the workaround comes from
[2]. The bug should be fixed in GnuTLS 3.3.12, hence the version guard.

After this problem was fixed, segfaults occurred during handshake. A
Valgrind trace showed attemts to access memory that had been free'd in
gnutls_privkey_import_openpgp_raw. I could work around the issue by
loading the key into a gnutls_openpgp_privkey_t structure first and then
importing it into the gnutls_privkey_t using
gnutls_privkey_import_openpgp afterwards.

Thank you to Nikos Mavrogiannopoulos for very fast help with debugging!

[1] https://lists.gnupg.org/pipermail/gnutls-devel/2015-January/007377.html
[2] https://github.com/vanrein/tlspool/commit/4938102d3d1b086491d147e6c8e4e2a02825fc12

  • Property mode set to 100644
File size: 28.7 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        /* Theoretically, this chain of gnutls_openpgp_privkey_init,
425         * gnutls_openpgp_privkey_import and
426         * gnutls_privkey_import_openpgp could be replaced with one
427         * call to gnutls_privkey_import_openpgp_raw as shown
428         * below. However, that led to a segfault during handshake
429         * which disappeared with the three step method.
430         *
431         * ret = gnutls_privkey_import_openpgp_raw(sc->privkey_pgp, &data,
432         *                                         GNUTLS_OPENPGP_FMT_BASE64,
433         *                                         NULL, NULL); */
434        ret = gnutls_openpgp_privkey_init(&sc->privkey_pgp_internal);
435        if (ret != 0) {
436            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
437                         "GnuTLS: Failed to initialize "
438                         "PGP Private Key '%s': (%d) %s",
439                         sc->pgp_key_file, ret, gnutls_strerror(ret));
440            ret = -1;
441            goto cleanup;
442        }
443
444        ret = gnutls_openpgp_privkey_import(sc->privkey_pgp_internal, &data,
445                                            GNUTLS_OPENPGP_FMT_BASE64, NULL, 0);
446        if (ret != 0) {
447            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
448                         "GnuTLS: Failed to Import "
449                         "PGP Private Key '%s': (%d) %s",
450                         sc->pgp_key_file, ret, gnutls_strerror(ret));
451            ret = -1;
452            goto cleanup;
453        }
454
455        ret = gnutls_privkey_import_openpgp(sc->privkey_pgp,
456                                            sc->privkey_pgp_internal, 0);
457        if (ret != 0)
458        {
459            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
460                         "GnuTLS: Failed to assign PGP Private Key '%s' "
461                         "to gnutls_privkey_t structure: (%d) %s",
462                         sc->pgp_key_file, ret, gnutls_strerror(ret));
463            ret = -1;
464            goto cleanup;
465        }
466    }
467
468    /* Load the keyring file */
469    if (sc->pgp_ring_file) {
470        if (load_datum_from_file(spool, sc->pgp_ring_file, &data) != 0) {
471            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
472                         "GnuTLS: Error Reading " "Keyring File '%s'",
473                         sc->pgp_ring_file);
474            ret = -1;
475            goto cleanup;
476        }
477
478        ret = gnutls_openpgp_keyring_init(&sc->pgp_list);
479        if (ret < 0) {
480            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
481                         "GnuTLS: Failed to initialize"
482                         "keyring: (%d) %s", ret, gnutls_strerror(ret));
483            ret = -1;
484            goto cleanup;
485        }
486
487        ret = gnutls_openpgp_keyring_import(sc->pgp_list, &data,
488                                           GNUTLS_OPENPGP_FMT_BASE64);
489        if (ret < 0) {
490            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
491                         "GnuTLS: Failed to load "
492                         "Keyring File '%s': (%d) %s", sc->pgp_ring_file,
493                         ret, gnutls_strerror(ret));
494            ret = -1;
495            goto cleanup;
496        }
497    }
498
499    if (sc->priorities_str) {
500        const char *err;
501        ret = gnutls_priority_init(&sc->priorities, sc->priorities_str, &err);
502
503        if (ret < 0) {
504            if (ret == GNUTLS_E_INVALID_REQUEST) {
505                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
506                             "GnuTLS: Syntax error parsing priorities string at: %s",
507                             err);
508            } else {
509                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
510                             "GnuTLS: error parsing priorities string");
511
512            }
513            ret = -1;
514            goto cleanup;
515        }
516    }
517
518    ret = 0;
519  cleanup:
520    apr_pool_destroy(spool);
521
522    return ret;
523}
524
525int mgs_pkcs11_reinit(server_rec * base_server)
526{
527    int ret;
528    server_rec *s;
529    mgs_srvconf_rec *sc;
530
531    gnutls_pkcs11_reinit();
532
533    for (s = base_server; s; s = s->next) {
534        sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
535
536            /* gnutls caches the session in a private key, so we need to open
537             * a new one */
538            if (sc->x509_key_file && gnutls_url_is_supported(sc->x509_key_file) != 0) {
539                gnutls_privkey_deinit(sc->privkey_x509);
540
541                ret = gnutls_privkey_init(&sc->privkey_x509);
542                if (ret < 0) {
543                    ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
544                                 "GnuTLS: Failed to initialize: (%d) %s", ret,
545                                 gnutls_strerror(ret));
546                    goto fail;
547                }
548
549                gnutls_privkey_set_pin_function(sc->privkey_x509, pin_callback, sc);
550
551                ret = gnutls_privkey_import_url(sc->privkey_x509, sc->x509_key_file, 0);
552                if (ret < 0) {
553                    ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
554                             "GnuTLS: Failed to Re-Import Private Key URL '%s': (%d) %s",
555                             sc->x509_key_file, ret, gnutls_strerror(ret));
556                    goto fail;
557                }
558            }
559    }
560
561    return 0;
562
563 fail:
564    gnutls_privkey_deinit(sc->privkey_x509);
565    return -1;
566}
567
568const char *mgs_set_dh_file(cmd_parms * parms, void *dummy __attribute__((unused)),
569        const char *arg) {
570    mgs_srvconf_rec *sc =
571        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
572                                                 module_config,
573                                                 &gnutls_module);
574
575    sc->dh_file = ap_server_root_relative(parms->pool, arg);
576
577    return NULL;
578}
579
580const char *mgs_set_cert_file(cmd_parms * parms, void *dummy __attribute__((unused)), const char *arg) {
581
582    mgs_srvconf_rec *sc =
583        (mgs_srvconf_rec *) ap_get_module_config(parms->
584                                                 server->module_config,
585                                                 &gnutls_module);
586
587    sc->x509_cert_file = apr_pstrdup(parms->pool, arg);
588
589    return NULL;
590
591}
592
593const char *mgs_set_key_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_key_file = apr_pstrdup(parms->pool, arg);
601
602    return NULL;
603}
604
605const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy __attribute__((unused)),
606        const char *arg)
607{
608    mgs_srvconf_rec *sc =
609        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
610                                                 module_config,
611                                                 &gnutls_module);
612
613    sc->pgp_cert_file = ap_server_root_relative(parms->pool, arg);
614
615    return NULL;
616}
617
618const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy __attribute__((unused)),
619        const char *arg) {
620    mgs_srvconf_rec *sc =
621        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
622                                                 module_config,
623                                                 &gnutls_module);
624
625    sc->pgp_key_file = ap_server_root_relative(parms->pool, arg);
626
627    return NULL;
628}
629
630const char *mgs_set_tickets(cmd_parms * parms, void *dummy __attribute__((unused)),
631        const char *arg) {
632    mgs_srvconf_rec *sc =
633        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
634                                                 module_config,
635                                                 &gnutls_module);
636
637    sc->tickets = 0;
638    if (strcasecmp("on", arg) == 0) {
639        sc->tickets = 1;
640    }
641
642    return NULL;
643}
644
645
646#ifdef ENABLE_SRP
647
648const char *mgs_set_srp_tpasswd_file(cmd_parms * parms, void *dummy __attribute__((unused)),
649        const char *arg) {
650    mgs_srvconf_rec *sc =
651        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
652                                                 module_config,
653                                                 &gnutls_module);
654
655    sc->srp_tpasswd_file = ap_server_root_relative(parms->pool, arg);
656
657    return NULL;
658}
659
660const char *mgs_set_srp_tpasswd_conf_file(cmd_parms * parms, void *dummy __attribute__((unused)),
661        const char *arg) {
662    mgs_srvconf_rec *sc =
663        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
664                                                 module_config,
665                                                 &gnutls_module);
666
667    sc->srp_tpasswd_conf_file = ap_server_root_relative(parms->pool, arg);
668
669    return NULL;
670}
671
672#endif
673
674const char *mgs_set_cache(cmd_parms * parms, void *dummy __attribute__((unused)),
675        const char *type, const char *arg) {
676    const char *err;
677    mgs_srvconf_rec *sc =
678        ap_get_module_config(parms->server->module_config,
679                             &gnutls_module);
680    if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
681        return err;
682    }
683
684    if (strcasecmp("none", type) == 0) {
685        sc->cache_type = mgs_cache_none;
686        sc->cache_config = NULL;
687        return NULL;
688    } else if (strcasecmp("dbm", type) == 0) {
689        sc->cache_type = mgs_cache_dbm;
690    } else if (strcasecmp("gdbm", type) == 0) {
691        sc->cache_type = mgs_cache_gdbm;
692    }
693#if HAVE_APR_MEMCACHE
694    else if (strcasecmp("memcache", type) == 0) {
695        sc->cache_type = mgs_cache_memcache;
696    }
697#endif
698    else {
699        return "Invalid Type for GnuTLSCache!";
700    }
701
702    if (arg == NULL)
703        return "Invalid argument 2 for GnuTLSCache!";
704
705    if (sc->cache_type == mgs_cache_dbm
706        || sc->cache_type == mgs_cache_gdbm) {
707        sc->cache_config = ap_server_root_relative(parms->pool, arg);
708    } else {
709        sc->cache_config = apr_pstrdup(parms->pool, arg);
710    }
711
712    return NULL;
713}
714
715const char *mgs_set_cache_timeout(cmd_parms * parms, void *dummy __attribute__((unused)),
716        const char *arg) {
717    int argint;
718    const char *err;
719    mgs_srvconf_rec *sc =
720        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
721                                                 module_config,
722                                                 &gnutls_module);
723
724    if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
725        return err;
726    }
727
728    argint = atoi(arg);
729
730    if (argint < 0) {
731        return "GnuTLSCacheTimeout: Invalid argument";
732    } else if (argint == 0) {
733        sc->cache_timeout = 0;
734    } else {
735        sc->cache_timeout = apr_time_from_sec(argint);
736    }
737
738    return NULL;
739}
740
741const char *mgs_set_client_verify_method(cmd_parms * parms, void *dummy __attribute__((unused)),
742        const char *arg) {
743    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)ap_get_module_config(parms->server->module_config, &gnutls_module);
744
745    if (strcasecmp("cartel", arg) == 0) {
746        sc->client_verify_method = mgs_cvm_cartel;
747    } else if (strcasecmp("msva", arg) == 0) {
748#ifdef ENABLE_MSVA
749        sc->client_verify_method = mgs_cvm_msva;
750#else
751        return "GnuTLSClientVerifyMethod: msva is not supported";
752#endif
753    } else {
754        return "GnuTLSClientVerifyMethod: Invalid argument";
755    }
756
757    return NULL;
758}
759
760const char *mgs_set_client_verify(cmd_parms * parms,
761                                  void *dirconf,
762                                  const char *arg) {
763    int mode;
764
765    if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) {
766        mode = GNUTLS_CERT_IGNORE;
767    } else if (strcasecmp("optional", arg) == 0
768               || strcasecmp("request", arg) == 0) {
769        mode = GNUTLS_CERT_REQUEST;
770    } else if (strcasecmp("require", arg) == 0) {
771        mode = GNUTLS_CERT_REQUIRE;
772    } else {
773        return "GnuTLSClientVerify: Invalid argument";
774    }
775
776    /* This was set from a directory context */
777    if (parms->path) {
778        mgs_dirconf_rec *dc = (mgs_dirconf_rec *) dirconf;
779        dc->client_verify_mode = mode;
780    } else {
781        mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
782            ap_get_module_config(parms->server->module_config,
783                                 &gnutls_module);
784        sc->client_verify_mode = mode;
785    }
786
787    return NULL;
788}
789
790const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy __attribute__((unused)),
791        const char *arg) {
792    mgs_srvconf_rec *sc =
793        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
794                                                 module_config,
795                                                 &gnutls_module);
796
797    sc->x509_ca_file = ap_server_root_relative(parms->pool, arg);
798
799    return NULL;
800}
801
802const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy __attribute__((unused)),
803        const char *arg) {
804    mgs_srvconf_rec *sc =
805        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
806                                                 module_config,
807                                                 &gnutls_module);
808
809    sc->pgp_ring_file = ap_server_root_relative(parms->pool, arg);
810
811    return NULL;
812}
813
814const char *mgs_set_proxy_engine(cmd_parms * parms, void *dummy __attribute__((unused)),
815        const char *arg) {
816
817    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
818        ap_get_module_config(parms->server->module_config, &gnutls_module);
819
820    if (!strcasecmp(arg, "On")) {
821        sc->proxy_enabled = GNUTLS_ENABLED_TRUE;
822    } else if (!strcasecmp(arg, "Off")) {
823        sc->proxy_enabled = GNUTLS_ENABLED_FALSE;
824    } else {
825        return "SSLProxyEngine must be set to 'On' or 'Off'";
826    }
827
828    return NULL;
829}
830
831const char *mgs_set_enabled(cmd_parms * parms, void *dummy __attribute__((unused)),
832        const char *arg) {
833    mgs_srvconf_rec *sc =
834        (mgs_srvconf_rec *) ap_get_module_config(parms->server->
835                                                 module_config,
836                                                 &gnutls_module);
837    if (!strcasecmp(arg, "On")) {
838        sc->enabled = GNUTLS_ENABLED_TRUE;
839    } else if (!strcasecmp(arg, "Off")) {
840        sc->enabled = GNUTLS_ENABLED_FALSE;
841    } else {
842        return "GnuTLSEnable must be set to 'On' or 'Off'";
843    }
844
845    return NULL;
846}
847
848const char *mgs_set_export_certificates_size(cmd_parms * parms, void *dummy __attribute__((unused)), const char *arg) {
849    mgs_srvconf_rec *sc = (mgs_srvconf_rec *) ap_get_module_config(parms->server->module_config, &gnutls_module);
850    if (!strcasecmp(arg, "On")) {
851        sc->export_certificates_size = 16 * 1024;
852    } else if (!strcasecmp(arg, "Off")) {
853        sc->export_certificates_size = 0;
854    } else {
855        char *endptr;
856        sc->export_certificates_size = strtol(arg, &endptr, 10);
857        while (apr_isspace(*endptr))
858            endptr++;
859        if (*endptr == '\0' || *endptr == 'b' || *endptr == 'B') {
860            ;
861        } else if (*endptr == 'k' || *endptr == 'K') {
862            sc->export_certificates_size *= 1024;
863        } else {
864            return
865                "GnuTLSExportCertificates must be set to a size (in bytes) or 'On' or 'Off'";
866        }
867    }
868
869    return NULL;
870}
871
872const char *mgs_set_priorities(cmd_parms * parms, void *dummy __attribute__((unused)), const char *arg)
873{
874    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
875        ap_get_module_config(parms->server->module_config, &gnutls_module);
876
877    sc->priorities_str = apr_pstrdup(parms->pool, arg);
878
879    return NULL;
880}
881
882const char *mgs_set_pin(cmd_parms * parms, void *dummy __attribute__((unused)),
883                        const char *arg)
884{
885
886    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
887        ap_get_module_config(parms->server->module_config, &gnutls_module);
888
889    sc->pin = apr_pstrdup(parms->pool, arg);
890
891    return NULL;
892}
893
894const char *mgs_set_srk_pin(cmd_parms * parms,
895                            void *dummy __attribute__((unused)),
896                            const char *arg)
897{
898
899    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
900        ap_get_module_config(parms->server->module_config, &gnutls_module);
901
902    sc->srk_pin = apr_pstrdup(parms->pool, arg);
903
904    return NULL;
905}
906
907static mgs_srvconf_rec *_mgs_config_server_create(apr_pool_t * p,
908                                                  char **err __attribute__((unused)))
909{
910    mgs_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc));
911
912    sc->enabled = GNUTLS_ENABLED_UNSET;
913
914
915    sc->privkey_x509 = NULL;
916    sc->privkey_pgp = NULL;
917    sc->certs_x509_chain_num = 0;
918    sc->cache_timeout = -1;     /* -1 means "unset" */
919    sc->cache_type = mgs_cache_unset;
920    sc->cache_config = NULL;
921    sc->tickets = GNUTLS_ENABLED_UNSET;
922    sc->priorities = NULL;
923    sc->dh_params = NULL;
924    sc->proxy_enabled = GNUTLS_ENABLED_UNSET;
925    sc->export_certificates_size = -1;
926    sc->client_verify_method = mgs_cvm_unset;
927
928/* this relies on GnuTLS never changing the gnutls_certificate_request_t enum to define -1 */
929    sc->client_verify_mode = -1;
930
931    return sc;
932}
933
934void *mgs_config_server_create(apr_pool_t * p,
935                               server_rec * s __attribute__((unused))) {
936    char *err = NULL;
937    mgs_srvconf_rec *sc = _mgs_config_server_create(p, &err);
938    if (sc)
939        return sc;
940    else
941        return err;
942}
943
944#define gnutls_srvconf_merge(t, unset) sc->t = (add->t == unset) ? base->t : add->t
945#define gnutls_srvconf_assign(t) sc->t = add->t
946
947void *mgs_config_server_merge(apr_pool_t * p, void *BASE, void *ADD)
948{
949    int i;
950    char *err = NULL;
951    mgs_srvconf_rec *base = (mgs_srvconf_rec *) BASE;
952    mgs_srvconf_rec *add = (mgs_srvconf_rec *) ADD;
953    mgs_srvconf_rec *sc = _mgs_config_server_create(p, &err);
954    if (NULL == sc)
955        return err;
956
957    gnutls_srvconf_merge(enabled, GNUTLS_ENABLED_UNSET);
958    gnutls_srvconf_merge(tickets, GNUTLS_ENABLED_UNSET);
959    gnutls_srvconf_merge(proxy_enabled, GNUTLS_ENABLED_UNSET);
960    gnutls_srvconf_merge(export_certificates_size, -1);
961    gnutls_srvconf_merge(client_verify_method, mgs_cvm_unset);
962    gnutls_srvconf_merge(client_verify_mode, -1);
963    gnutls_srvconf_merge(srp_tpasswd_file, NULL);
964    gnutls_srvconf_merge(srp_tpasswd_conf_file, NULL);
965    gnutls_srvconf_merge(x509_cert_file, NULL);
966
967    gnutls_srvconf_merge(x509_key_file, NULL);
968    gnutls_srvconf_merge(x509_ca_file, NULL);
969    gnutls_srvconf_merge(pin, NULL);
970    gnutls_srvconf_merge(pgp_cert_file, NULL);
971    gnutls_srvconf_merge(pgp_key_file, NULL);
972    gnutls_srvconf_merge(pgp_ring_file, NULL);
973    gnutls_srvconf_merge(dh_file, NULL);
974    gnutls_srvconf_merge(priorities_str, NULL);
975
976    /* FIXME: the following items are pre-allocated, and should be
977     * properly disposed of before assigning in order to avoid leaks;
978     * so at the moment, we can't actually have them in the config.
979     * what happens during de-allocation? */
980    gnutls_srvconf_assign(ca_list);
981    gnutls_srvconf_assign(ca_list_size);
982    gnutls_srvconf_assign(cert_pgp);
983    gnutls_srvconf_assign(cert_crt_pgp);
984    gnutls_srvconf_assign(pgp_list);
985    gnutls_srvconf_assign(certs);
986    gnutls_srvconf_assign(anon_creds);
987    gnutls_srvconf_assign(srp_creds);
988    gnutls_srvconf_assign(certs_x509_chain);
989    gnutls_srvconf_assign(certs_x509_crt_chain);
990    gnutls_srvconf_assign(certs_x509_chain_num);
991
992    /* how do these get transferred cleanly before the data from ADD
993     * goes away? */
994    gnutls_srvconf_assign(cert_cn);
995    for (i = 0; i < MAX_CERT_SAN; i++)
996        gnutls_srvconf_assign(cert_san[i]);
997
998    return sc;
999}
1000
1001#undef gnutls_srvconf_merge
1002#undef gnutls_srvconf_assign
1003
1004void *mgs_config_dir_merge(apr_pool_t * p,
1005                           void *basev __attribute__((unused)),
1006                           void *addv __attribute__((unused))) {
1007    mgs_dirconf_rec *new;
1008    /*    mgs_dirconf_rec *base = (mgs_dirconf_rec *) basev; */
1009    mgs_dirconf_rec *add = (mgs_dirconf_rec *) addv;
1010
1011    new = (mgs_dirconf_rec *) apr_pcalloc(p, sizeof(mgs_dirconf_rec));
1012    new->client_verify_mode = add->client_verify_mode;
1013    return new;
1014}
1015
1016void *mgs_config_dir_create(apr_pool_t * p,
1017                            char *dir __attribute__((unused))) {
1018    mgs_dirconf_rec *dc = apr_palloc(p, sizeof (*dc));
1019    dc->client_verify_mode = -1;
1020    return dc;
1021}
Note: See TracBrowser for help on using the repository browser.