source: mod_gnutls/src/gnutls_hooks.c @ d4c1a4e

debian/masterproxy-ticket
Last change on this file since d4c1a4e was d4c1a4e, checked in by Fiona Klute <fiona.klute@…>, 2 years ago

Add a reference from mod_gnutls server settings back to the server_rec

During the TLS handshake conn_rec.base_server isn't set to the right
virtual host yet because the HTTP request hasn't been received and
parsed. After selecting the virtual host based on SNI we can use the
new reference instead.

  • Property mode set to 100644
File size: 80.3 KB
Line 
1/*
2 *  Copyright 2004-2005 Paul Querna
3 *  Copyright 2008, 2014 Nikos Mavrogiannopoulos
4 *  Copyright 2011 Dash Shendy
5 *  Copyright 2013-2014 Daniel Kahn Gillmor
6 *  Copyright 2015-2018 Fiona Klute
7 *
8 *  Licensed under the Apache License, Version 2.0 (the "License");
9 *  you may not use this file except in compliance with the License.
10 *  You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 *  Unless required by applicable law or agreed to in writing, software
15 *  distributed under the License is distributed on an "AS IS" BASIS,
16 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 *  See the License for the specific language governing permissions and
18 *  limitations under the License.
19 */
20
21#include "mod_gnutls.h"
22#include "gnutls_cache.h"
23#include "gnutls_config.h"
24#include "gnutls_ocsp.h"
25#include "gnutls_sni.h"
26#include "gnutls_util.h"
27#include "gnutls_watchdog.h"
28
29#include "http_vhost.h"
30#include "ap_mpm.h"
31#include <mod_status.h>
32#include <util_mutex.h>
33#include <apr_escape.h>
34/* This provides strcmp and related functions */
35#define APR_WANT_STRFUNC
36#include <apr_want.h>
37
38#ifdef ENABLE_MSVA
39#include <msv/msv.h>
40#endif
41
42#ifdef APLOG_USE_MODULE
43APLOG_USE_MODULE(gnutls);
44#endif
45
46#if MOD_GNUTLS_DEBUG
47static apr_file_t *debug_log_fp;
48#endif
49
50#define IS_PROXY_STR(c) \
51    ((c->is_proxy == GNUTLS_ENABLED_TRUE) ? "proxy " : "")
52
53/** Key to encrypt session tickets. Must be kept secret. This key is
54 * generated in the `pre_config` hook and thus constant across
55 * forks. The problem with this approach is that it does not support
56 * regular key rotation. */
57static gnutls_datum_t session_ticket_key = {NULL, 0};
58
59
60/** Default GnuTLS priority string for mod_gnutls */
61#define MGS_DEFAULT_PRIORITY "NORMAL"
62/** Compiled version of MGS_DEFAULT_PRIORITY (initialized in the
63 * pre_config hook) */
64static gnutls_priority_t default_prio;
65
66
67static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
68/** use side==0 for server and side==1 for client */
69static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, size_t export_cert_size);
70mgs_srvconf_rec* mgs_find_sni_server(mgs_handle_t *ctxt);
71static int mgs_status_hook(request_rec *r, int flags);
72#ifdef ENABLE_MSVA
73static const char* mgs_x509_construct_uid(request_rec * pool, gnutls_x509_crt_t cert);
74#endif
75static int load_proxy_x509_credentials(apr_pool_t *pconf, apr_pool_t *ptemp, server_rec *s)
76    __attribute__((nonnull));
77
78/* Pool Cleanup Function */
79apr_status_t mgs_cleanup_pre_config(void *data __attribute__((unused)))
80{
81    /* Free session ticket master key */
82#if GNUTLS_VERSION_NUMBER >= 0x030400
83    gnutls_memset(session_ticket_key.data, 0, session_ticket_key.size);
84#endif
85    gnutls_free(session_ticket_key.data);
86    session_ticket_key.data = NULL;
87    session_ticket_key.size = 0;
88
89    /* Deinit default priority setting */
90    gnutls_priority_deinit(default_prio);
91    return APR_SUCCESS;
92}
93
94/* Logging Function for Maintainers */
95#if MOD_GNUTLS_DEBUG
96static void gnutls_debug_log_all(int level, const char *str) {
97    apr_file_printf(debug_log_fp, "<%d> %s", level, str);
98}
99#define _gnutls_log apr_file_printf
100#else
101#define _gnutls_log(...)
102#endif
103
104static const char* mgs_readable_cvm(mgs_client_verification_method_e m) {
105    switch(m) {
106    case mgs_cvm_unset:
107        return "unset";
108    case mgs_cvm_cartel:
109        return "cartel";
110    case mgs_cvm_msva:
111        return "msva";
112    }
113    return "unknown";
114}
115
116/* Pre-Configuration HOOK: Runs First */
117int mgs_hook_pre_config(apr_pool_t * pconf, apr_pool_t * plog, apr_pool_t * ptemp __attribute__((unused))) {
118
119/* Maintainer Logging */
120#if MOD_GNUTLS_DEBUG
121    apr_file_open(&debug_log_fp, "/tmp/gnutls_debug", APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT, pconf);
122    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
123    gnutls_global_set_log_level(9);
124    gnutls_global_set_log_function(gnutls_debug_log_all);
125    _gnutls_log(debug_log_fp, "gnutls: %s\n", gnutls_check_version(NULL));
126#endif
127
128    int ret;
129
130        /* Check for required GnuTLS Library Version */
131    if (gnutls_check_version(LIBGNUTLS_VERSION) == NULL) {
132                ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, plog, "gnutls_check_version() failed. Required: "
133                                        "gnutls-%s Found: gnutls-%s", LIBGNUTLS_VERSION, gnutls_check_version(NULL));
134        return DONE;
135    }
136
137        /* Generate a Session Key */
138    ret = gnutls_session_ticket_key_generate(&session_ticket_key);
139    if (ret < 0) {
140                ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, plog, "gnutls_session_ticket_key_generate: %s", gnutls_strerror(ret));
141                return DONE;
142    }
143
144    /* Initialize default priority setting */
145    ret = gnutls_priority_init(&default_prio, MGS_DEFAULT_PRIORITY, NULL);
146    if (ret < 0)
147    {
148        ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, plog,
149                      "gnutls_priority_init failed for default '%s': %s (%d)",
150                      MGS_DEFAULT_PRIORITY, gnutls_strerror(ret), ret);
151        return DONE;
152    }
153
154    AP_OPTIONAL_HOOK(status_hook, mgs_status_hook, NULL, NULL, APR_HOOK_MIDDLE);
155
156    ap_mutex_register(pconf, MGS_CACHE_MUTEX_NAME, NULL, APR_LOCK_DEFAULT, 0);
157    ap_mutex_register(pconf, MGS_OCSP_MUTEX_NAME, NULL, APR_LOCK_DEFAULT, 0);
158    ap_mutex_register(pconf, MGS_OCSP_CACHE_MUTEX_NAME, NULL,
159                      APR_LOCK_DEFAULT, 0);
160
161    /* Register a pool clean-up function */
162    apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, apr_pool_cleanup_null);
163
164    return OK;
165}
166
167
168
169/**
170 * Get the list of available protocols for this connection and add it
171 * to the GnuTLS session. Must run before the client hello function.
172 */
173static void prepare_alpn_proposals(mgs_handle_t *ctxt)
174{
175    /* Check if any protocol upgrades are available
176     *
177     * The "report_all" parameter to ap_get_protocol_upgrades() is 0
178     * (report only more preferable protocols) because setting it to 1
179     * doesn't actually report ALL protocols, but only all except the
180     * current one. This way we can at least list the current one as
181     * available by appending it without potentially negotiating a
182     * less preferred protocol. */
183    const apr_array_header_t *pupgrades = NULL;
184    apr_status_t ret =
185        ap_get_protocol_upgrades(ctxt->c, NULL, ctxt->c->base_server,
186                                 /*report_all*/ 0, &pupgrades);
187    if (ret != APR_SUCCESS)
188    {
189        ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, ctxt->c,
190                      "%s: ap_get_protocol_upgrades() failed, "
191                      "cannot configure ALPN!", __func__);
192        return;
193    }
194
195    if (pupgrades == NULL || pupgrades->nelts == 0)
196    {
197        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctxt->c,
198                      "%s: No protocol upgrades available.", __func__);
199        return;
200    }
201
202    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctxt->c,
203                  "%s: Found %d protocol upgrade(s) for ALPN: %s",
204                  __func__, pupgrades->nelts,
205                  apr_array_pstrcat(ctxt->c->pool, pupgrades, ','));
206    gnutls_datum_t *alpn_protos =
207        apr_palloc(ctxt->c->pool,
208                   (pupgrades->nelts + 1) * sizeof(gnutls_datum_t));
209    for (int i = 0; i < pupgrades->nelts; i++)
210    {
211        alpn_protos[i].data = (void *) APR_ARRAY_IDX(pupgrades, i, char *);
212        alpn_protos[i].size =
213            strnlen(APR_ARRAY_IDX(pupgrades, i, char *),
214                    pupgrades->elt_size);
215    }
216
217    /* Add the current (default) protocol at the end of the list */
218    alpn_protos[pupgrades->nelts].data =
219        (void*) apr_pstrdup(ctxt->c->pool, ap_get_protocol(ctxt->c));
220    alpn_protos[pupgrades->nelts].size =
221        strlen((char*) alpn_protos[pupgrades->nelts].data);
222    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctxt->c,
223                  "%s: Adding current protocol %s to ALPN set.",
224                  __func__, alpn_protos[pupgrades->nelts].data);
225
226    gnutls_alpn_set_protocols(ctxt->session,
227                              alpn_protos,
228                              pupgrades->nelts,
229                              GNUTLS_ALPN_SERVER_PRECEDENCE);
230}
231
232
233
234/**
235 * Check if ALPN selected any protocol upgrade, try to switch if so.
236 */
237static int process_alpn_result(mgs_handle_t *ctxt)
238{
239    int ret = 0;
240    gnutls_datum_t alpn_proto;
241    ret = gnutls_alpn_get_selected_protocol(ctxt->session, &alpn_proto);
242    if (ret != GNUTLS_E_SUCCESS)
243    {
244        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
245                      "%s: No ALPN result: %s (%d)",
246                      __func__, gnutls_strerror(ret), ret);
247        return GNUTLS_E_SUCCESS;
248    }
249
250    apr_array_header_t *client_protos =
251        apr_array_make(ctxt->c->pool, 1, sizeof(char *));
252    /* apr_pstrndup to ensure that the protocol is null terminated */
253    APR_ARRAY_PUSH(client_protos, char *) =
254        apr_pstrndup(ctxt->c->pool, (char*) alpn_proto.data, alpn_proto.size);
255    const char *selected =
256        ap_select_protocol(ctxt->c, NULL, ctxt->c->base_server,
257                           client_protos);
258
259    /* ap_select_protocol() will return NULL if none of the ALPN
260     * proposals matched. GnuTLS negotiated alpn_proto based on the
261     * list provided by the server, but the vhost might have changed
262     * based on SNI. Apache seems to adjust the proposal list to avoid
263     * such issues though.
264     *
265     * GnuTLS will return a fatal "no_application_protocol" alert as
266     * required by RFC 7301 if the post client hello function returns
267     * GNUTLS_E_NO_APPLICATION_PROTOCOL. */
268    if (!selected)
269    {
270        ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, ctxt->c,
271                      "%s: ap_select_protocol() returned NULL! Please "
272                      "make sure any overlapping vhosts have the same "
273                      "protocols available.",
274                      __func__);
275        return GNUTLS_E_NO_APPLICATION_PROTOCOL;
276    }
277
278    if (strcmp(selected, ap_get_protocol(ctxt->c)) == 0)
279    {
280        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
281                      "%s: Already using protocol '%s', nothing to do.",
282                      __func__, selected);
283        return GNUTLS_E_SUCCESS;
284    }
285
286    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ctxt->c,
287                  "%s: Switching protocol to '%s' based on ALPN.",
288                  __func__, selected);
289    apr_status_t status = ap_switch_protocol(ctxt->c, NULL,
290                                             ctxt->c->base_server,
291                                             selected);
292    if (status != APR_SUCCESS)
293    {
294        ap_log_cerror(APLOG_MARK, APLOG_ERR, status, ctxt->c,
295                      "%s: Protocol switch to '%s' failed!",
296                      __func__, selected);
297        return GNUTLS_E_NO_APPLICATION_PROTOCOL;
298    }
299    /* ALPN done! */
300    return GNUTLS_E_SUCCESS;
301}
302
303
304
305/**
306 * (Re-)Load credentials and priorities for the connection. This is
307 * meant to be called after virtual host selection in the pre or post
308 * client hello hook.
309 */
310static int reload_session_credentials(mgs_handle_t *ctxt)
311{
312    int ret = 0;
313
314    gnutls_certificate_server_set_request(ctxt->session,
315                                          ctxt->sc->client_verify_mode);
316
317    /* Set x509 credentials */
318    gnutls_credentials_set(ctxt->session,
319                           GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
320    /* Set Anon credentials */
321    gnutls_credentials_set(ctxt->session, GNUTLS_CRD_ANON,
322                           ctxt->sc->anon_creds);
323
324#ifdef ENABLE_SRP
325        /* Set SRP credentials */
326    if (ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) {
327        gnutls_credentials_set(ctxt->session, GNUTLS_CRD_SRP,
328                               ctxt->sc->srp_creds);
329    }
330#endif
331
332    /* Enable session tickets */
333    if (session_ticket_key.data != NULL &&
334        ctxt->sc->tickets == GNUTLS_ENABLED_TRUE)
335    {
336        ret = gnutls_session_ticket_enable_server(ctxt->session, &session_ticket_key);
337        if (ret != GNUTLS_E_SUCCESS)
338            ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, ctxt->c,
339                          "gnutls_session_ticket_enable_server failed: %s (%d)",
340                          gnutls_strerror(ret), ret);
341    }
342
343    /* Update the priorities - to avoid negotiating a ciphersuite that is not
344     * enabled on this virtual server. Note that here we ignore the version
345     * negotiation. */
346    ret = gnutls_priority_set(ctxt->session, ctxt->sc->priorities);
347
348    return ret;
349}
350
351
352
353/**
354 * Post client hello function for GnuTLS, used to configure the TLS
355 * server based on virtual host configuration. Uses SNI to select the
356 * virtual host if available.
357 *
358 * @param session the TLS session
359 *
360 * @return zero or a GnuTLS error code, as required by GnuTLS hook
361 * definition
362 */
363static int mgs_select_virtual_server_cb(gnutls_session_t session)
364{
365    int ret = 0;
366    mgs_handle_t *ctxt = gnutls_session_get_ptr(session);
367
368    /* try to find a virtual host */
369    mgs_srvconf_rec *tsc = mgs_find_sni_server(ctxt);
370    if (tsc != NULL)
371    {
372        /* Found a TLS vhost based on the SNI, configure the
373         * connection context. */
374        ctxt->sc = tsc;
375        }
376
377    reload_session_credentials(ctxt);
378
379    ret = process_alpn_result(ctxt);
380    if (ret != GNUTLS_E_SUCCESS)
381        return ret;
382
383    /* actually it shouldn't fail since we have checked at startup */
384    return ret;
385}
386
387static int cert_retrieve_fn(gnutls_session_t session,
388                            const gnutls_datum_t * req_ca_rdn __attribute__((unused)),
389                            int nreqs __attribute__((unused)),
390                            const gnutls_pk_algorithm_t * pk_algos __attribute__((unused)),
391                            int pk_algos_length __attribute__((unused)),
392                            gnutls_pcert_st **pcerts,
393                            unsigned int *pcert_length,
394                            gnutls_privkey_t *privkey)
395{
396    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
397
398    mgs_handle_t *ctxt;
399
400    if (session == NULL) {
401                // ERROR INVALID SESSION
402        return -1;
403    }
404
405    ctxt = gnutls_transport_get_ptr(session);
406
407    if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) {
408                // X509 CERTIFICATE
409        *pcerts = ctxt->sc->certs_x509_chain;
410        *pcert_length = ctxt->sc->certs_x509_chain_num;
411        *privkey = ctxt->sc->privkey_x509;
412        return 0;
413    } else {
414                // UNKNOWN CERTIFICATE
415            return -1;
416        }
417}
418
419
420
421#if GNUTLS_VERSION_NUMBER >= 0x030506
422#define HAVE_KNOWN_DH_GROUPS 1
423#endif
424#ifdef HAVE_KNOWN_DH_GROUPS
425/**
426 * Try to estimate a GnuTLS security parameter based on the given
427 * private key. Any errors are logged.
428 *
429 * @param s The `server_rec` to use for logging
430 *
431 * @param key The private key to use
432 *
433 * @return `gnutls_sec_param_t` as returned by
434 * `gnutls_pk_bits_to_sec_param` for the key properties, or
435 * GNUTLS_SEC_PARAM_UNKNOWN in case of error
436 */
437static gnutls_sec_param_t sec_param_from_privkey(server_rec *server,
438                                                 gnutls_privkey_t key)
439{
440    unsigned int bits = 0;
441    int pk_algo = gnutls_privkey_get_pk_algorithm(key, &bits);
442    if (pk_algo < 0)
443    {
444        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server,
445                     "%s: Could not get private key parameters: %s (%d)",
446                     __func__, gnutls_strerror(pk_algo), pk_algo);
447        return GNUTLS_SEC_PARAM_UNKNOWN;
448    }
449    return gnutls_pk_bits_to_sec_param(pk_algo, bits);
450}
451#else
452/** ffdhe2048 DH group as defined in RFC 7919, Appendix A.1. This is
453 * the default DH group if mod_gnutls is compiled agains a GnuTLS
454 * version that does not provide known DH groups based on security
455 * parameters (before 3.5.6). */
456static const char FFDHE2048_PKCS3[] =
457    "-----BEGIN DH PARAMETERS-----\n"
458    "MIIBDAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n"
459    "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n"
460    "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n"
461    "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n"
462    "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n"
463    "ssbzSibBsu/6iGtCOGEoXJf//////////wIBAgICAQA=\n"
464    "-----END DH PARAMETERS-----\n";
465const gnutls_datum_t default_dh_params = {
466    (void *) FFDHE2048_PKCS3,
467    sizeof(FFDHE2048_PKCS3)
468};
469#endif
470
471
472
473/**
474 * Configure the default DH groups to use for the given server. When
475 * compiled against GnuTLS version 3.5.6 or newer the known DH group
476 * matching the GnuTLS security parameter estimated from the private
477 * key is used. Otherwise the ffdhe2048 DH group as defined in RFC
478 * 7919, Appendix A.1 is the default.
479 *
480 * @param server the host to configure
481 *
482 * @return `OK` on success, `HTTP_UNAUTHORIZED` otherwise
483 */
484static int set_default_dh_param(server_rec *server)
485{
486    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
487        ap_get_module_config(server->module_config, &gnutls_module);
488
489#ifdef HAVE_KNOWN_DH_GROUPS
490    gnutls_sec_param_t seclevel = GNUTLS_SEC_PARAM_UNKNOWN;
491    if (sc->privkey_x509)
492    {
493        seclevel = sec_param_from_privkey(server, sc->privkey_x509);
494        ap_log_error(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, server,
495                     "%s: GnuTLS security param estimated based on "
496                     "private key '%s': %s",
497                     __func__, sc->x509_key_file,
498                     gnutls_sec_param_get_name(seclevel));
499    }
500
501    if (seclevel == GNUTLS_SEC_PARAM_UNKNOWN)
502        seclevel = GNUTLS_SEC_PARAM_MEDIUM;
503    ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, server,
504                 "%s: Setting DH params for security level '%s'.",
505                 __func__, gnutls_sec_param_get_name(seclevel));
506
507    int ret = gnutls_certificate_set_known_dh_params(sc->certs, seclevel);
508    if (ret < 0)
509    {
510        ap_log_error(APLOG_MARK, APLOG_EMERG, APR_EGENERAL, server,
511                     "%s: setting known DH params failed: %s (%d)",
512                     __func__, gnutls_strerror(ret), ret);
513        return HTTP_UNAUTHORIZED;
514    }
515    ret = gnutls_anon_set_server_known_dh_params(sc->anon_creds, seclevel);
516    if (ret < 0)
517    {
518        ap_log_error(APLOG_MARK, APLOG_EMERG, APR_EGENERAL, server,
519                     "%s: setting known DH params failed: %s (%d)",
520                     __func__, gnutls_strerror(ret), ret);
521        return HTTP_UNAUTHORIZED;
522    }
523#else
524    int ret = gnutls_dh_params_init(&sc->dh_params);
525    if (ret < 0)
526    {
527        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, server,
528                     "%s: Failed to initialize DH params structure: "
529                     "%s (%d)", __func__, gnutls_strerror(ret), ret);
530        return HTTP_UNAUTHORIZED;
531    }
532    ret = gnutls_dh_params_import_pkcs3(sc->dh_params, &default_dh_params,
533                                        GNUTLS_X509_FMT_PEM);
534    if (ret < 0)
535    {
536        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, server,
537                     "%s: Failed to import default DH params: %s (%d)",
538                     __func__, gnutls_strerror(ret), ret);
539        return HTTP_UNAUTHORIZED;
540    }
541
542    gnutls_certificate_set_dh_params(sc->certs, sc->dh_params);
543    gnutls_anon_set_server_dh_params(sc->anon_creds, sc->dh_params);
544#endif
545
546    return OK;
547}
548
549
550
551/**
552 * Post config hook.
553 *
554 * Must return OK or DECLINED on success, something else on
555 * error. These codes are defined in Apache httpd.h along with the
556 * HTTP status codes, so I'm going to use HTTP error codes both for
557 * fun (and to avoid conflicts).
558 */
559int mgs_hook_post_config(apr_pool_t *pconf,
560                         apr_pool_t *plog __attribute__((unused)),
561                         apr_pool_t *ptemp,
562                         server_rec *base_server)
563{
564    int rv;
565    server_rec *s;
566    mgs_srvconf_rec *sc;
567    mgs_srvconf_rec *sc_base;
568    void *data = NULL;
569    const char *userdata_key = "mgs_init";
570
571    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
572
573    apr_pool_userdata_get(&data, userdata_key, base_server->process->pool);
574    if (data == NULL) {
575        apr_pool_userdata_set((const void *) 1, userdata_key, apr_pool_cleanup_null, base_server->process->pool);
576    }
577
578    s = base_server;
579    sc_base = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
580
581
582    rv = mgs_cache_post_config(pconf, ptemp, s, sc_base);
583    if (rv != APR_SUCCESS)
584    {
585        ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
586                     "Post config for cache failed.");
587        return HTTP_INSUFFICIENT_STORAGE;
588    }
589
590    if (sc_base->ocsp_mutex == NULL)
591    {
592        rv = ap_global_mutex_create(&sc_base->ocsp_mutex, NULL,
593                                    MGS_OCSP_MUTEX_NAME, NULL,
594                                    base_server, pconf, 0);
595        if (rv != APR_SUCCESS)
596            return rv;
597    }
598
599    /* If GnuTLSP11Module is set, load the listed PKCS #11
600     * modules. Otherwise system defaults will be used. */
601    if (sc_base->p11_modules != NULL)
602    {
603        rv = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL);
604        if (rv < 0)
605        {
606            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
607                         "GnuTLS: Initializing PKCS #11 "
608                         "failed: %s (%d).",
609                         gnutls_strerror(rv), rv);
610        }
611        else
612        {
613            for (int i = 0; i < sc_base->p11_modules->nelts; i++)
614            {
615                char *p11_module =
616                    APR_ARRAY_IDX(sc_base->p11_modules, i, char *);
617                rv = gnutls_pkcs11_add_provider(p11_module, NULL);
618                if (rv != GNUTLS_E_SUCCESS)
619                    ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EGENERAL, s,
620                                 "GnuTLS: Loading PKCS #11 provider module %s "
621                                 "failed: %s (%d).",
622                                 p11_module, gnutls_strerror(rv), rv);
623                else
624                    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
625                                 "%s: PKCS #11 provider module %s loaded.",
626                                 __func__, p11_module);
627            }
628        }
629    }
630
631    sc_base->singleton_wd =
632        mgs_new_singleton_watchdog(base_server, MGS_SINGLETON_WATCHDOG, pconf);
633
634    for (s = base_server; s; s = s->next)
635    {
636        sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
637        sc->s = s;
638        sc->cache_enable = sc_base->cache_enable;
639        sc->cache = sc_base->cache;
640        if (sc->cache_timeout == MGS_TIMEOUT_UNSET)
641            sc->cache_timeout = sc_base->cache_timeout;
642        sc->ocsp_cache = sc_base->ocsp_cache;
643
644        sc->singleton_wd = sc_base->singleton_wd;
645
646        /* defaults for unset values: */
647        if (sc->enabled == GNUTLS_ENABLED_UNSET)
648            sc->enabled = GNUTLS_ENABLED_FALSE;
649        if (sc->tickets == GNUTLS_ENABLED_UNSET)
650        {
651            /* GnuTLS 3.6.4 introduced automatic master key rotation */
652            if (gnutls_check_version_numeric(3, 6, 4))
653                sc->tickets = GNUTLS_ENABLED_TRUE;
654            else
655                sc->tickets = GNUTLS_ENABLED_FALSE;
656        }
657        if (sc->export_certificates_size < 0)
658            sc->export_certificates_size = 0;
659        if (sc->client_verify_mode == -1)
660            sc->client_verify_mode = GNUTLS_CERT_IGNORE;
661        if (sc->client_verify_method == mgs_cvm_unset)
662            sc->client_verify_method = mgs_cvm_cartel;
663
664        // TODO: None of the stuff below needs to be done if
665        // sc->enabled == GNUTLS_ENABLED_FALSE, we could just continue
666        // to the next host.
667
668        /* Load certificates and stuff (includes parsing priority) */
669        rv = mgs_load_files(pconf, ptemp, s);
670        if (rv != 0) {
671            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
672                         "%s: Loading credentials failed!", __func__);
673            return HTTP_NOT_FOUND;
674        }
675
676        sc->ocsp_mutex = sc_base->ocsp_mutex;
677        /* init OCSP configuration unless explicitly disabled */
678        if (sc->enabled && sc->ocsp_staple != GNUTLS_ENABLED_FALSE)
679        {
680            const char *err = mgs_ocsp_configure_stapling(pconf, ptemp, s);
681            if (err != NULL)
682            {
683                /* If OCSP stapling is enabled only by default ignore
684                 * error and disable stapling */
685                if (sc->ocsp_staple == GNUTLS_ENABLED_UNSET)
686                {
687                    ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, s,
688                                 "Cannnot enable OCSP stapling for "
689                                 "host '%s:%d': %s",
690                                 s->server_hostname, s->addrs->host_port, err);
691                    sc->ocsp_staple = GNUTLS_ENABLED_FALSE;
692                }
693                /* If OCSP stapling is explicitly enabled this is a
694                 * critical error. */
695                else
696                {
697                    ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EINVAL, s,
698                                 "OCSP stapling configuration failed for "
699                                 "host '%s:%d': %s",
700                                 s->server_hostname, s->addrs->host_port, err);
701                    return HTTP_INTERNAL_SERVER_ERROR;
702                }
703            }
704            else
705            {
706                /* Might already be set */
707                sc->ocsp_staple = GNUTLS_ENABLED_TRUE;
708                /* Set up stapling */
709                rv = mgs_ocsp_enable_stapling(pconf, ptemp, s);
710                if (rv != OK && rv != DECLINED)
711                    return rv;
712            }
713        }
714
715        /* Check if the priorities have been set */
716        if (sc->priorities == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
717            ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
718                         "No GnuTLSPriorities directive for host '%s:%d', "
719                         "using default '%s'.",
720                         s->server_hostname, s->addrs->host_port,
721                         MGS_DEFAULT_PRIORITY);
722            sc->priorities = default_prio;
723        }
724
725        /* Set host DH params from user configuration or defaults */
726        if (sc->dh_params != NULL) {
727            gnutls_certificate_set_dh_params(sc->certs, sc->dh_params);
728            gnutls_anon_set_server_dh_params(sc->anon_creds, sc->dh_params);
729        } else {
730            rv = set_default_dh_param(s);
731            if (rv != OK)
732                return rv;
733        }
734
735        /* The call after this comment is a workaround for bug in
736         * gnutls_certificate_set_retrieve_function2 that ignores
737         * supported certificate types. Should be fixed in GnuTLS
738         * 3.3.12.
739         *
740         * Details:
741         * https://lists.gnupg.org/pipermail/gnutls-devel/2015-January/007377.html
742         * Workaround from:
743         * https://github.com/vanrein/tlspool/commit/4938102d3d1b086491d147e6c8e4e2a02825fc12 */
744#if GNUTLS_VERSION_NUMBER < 0x030312
745        gnutls_certificate_set_retrieve_function(sc->certs, (void *) exit);
746#endif
747
748        gnutls_certificate_set_retrieve_function2(sc->certs, cert_retrieve_fn);
749
750        if ((sc->certs_x509_chain == NULL || sc->certs_x509_chain_num < 1) &&
751            sc->enabled == GNUTLS_ENABLED_TRUE) {
752                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
753                                                "GnuTLS: Host '%s:%d' is missing a Certificate File!",
754                                                s->server_hostname, s->addrs->host_port);
755            return HTTP_UNAUTHORIZED;
756        }
757        if (sc->enabled == GNUTLS_ENABLED_TRUE &&
758            (sc->certs_x509_chain_num > 0 && sc->privkey_x509 == NULL))
759        {
760                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
761                                                "GnuTLS: Host '%s:%d' is missing a Private Key File!",
762                                                s->server_hostname, s->addrs->host_port);
763            return HTTP_UNAUTHORIZED;
764        }
765
766        if (sc->enabled == GNUTLS_ENABLED_TRUE
767            && sc->proxy_enabled == GNUTLS_ENABLED_TRUE
768            && load_proxy_x509_credentials(pconf, ptemp, s) != APR_SUCCESS)
769        {
770            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
771                         "%s: loading proxy credentials for host "
772                         "'%s:%d' failed, exiting!",
773                         __func__, s->server_hostname, s->addrs->host_port);
774            return HTTP_PROXY_AUTHENTICATION_REQUIRED;
775        }
776    }
777
778
779    ap_add_version_component(pconf, "mod_gnutls/" MOD_GNUTLS_VERSION);
780
781    {
782        const char* libvers = gnutls_check_version(NULL);
783        char* gnutls_version = NULL;
784        if(libvers && (gnutls_version = apr_psprintf(pconf, "GnuTLS/%s", libvers))) {
785            ap_add_version_component(pconf, gnutls_version);
786        } else {
787            // In case we could not create the above string go for the static version instead
788            ap_add_version_component(pconf, "GnuTLS/" GNUTLS_VERSION "-static");
789        }
790    }
791
792    return OK;
793}
794
795void mgs_hook_child_init(apr_pool_t *p, server_rec *s)
796{
797    apr_status_t rv = APR_SUCCESS;
798    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
799        ap_get_module_config(s->module_config, &gnutls_module);
800
801    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
802
803    /* if we use PKCS #11 reinitialize it */
804    if (mgs_pkcs11_reinit(s) < 0) {
805            ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
806                    "GnuTLS: Failed to reinitialize PKCS #11");
807            exit(-1);
808    }
809
810    if (sc->cache_enable == GNUTLS_ENABLED_TRUE)
811    {
812        rv = mgs_cache_child_init(p, s, sc->cache, MGS_CACHE_MUTEX_NAME);
813        if (rv != APR_SUCCESS)
814            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
815                    "Child init for session cache failed!");
816    }
817
818    if (sc->ocsp_cache != NULL)
819    {
820        rv = mgs_cache_child_init(p, s, sc->ocsp_cache,
821                                  MGS_OCSP_CACHE_MUTEX_NAME);
822        if (rv != APR_SUCCESS)
823            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
824                    "Child init for OCSP cache failed!");
825    }
826
827    /* reinit OCSP request mutex */
828    const char *lockfile = apr_global_mutex_lockfile(sc->ocsp_mutex);
829    rv = apr_global_mutex_child_init(&sc->ocsp_mutex, lockfile, p);
830    if (rv != APR_SUCCESS)
831        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
832                     "Failed to reinit mutex '" MGS_OCSP_MUTEX_NAME "'.");
833
834    /* Block SIGPIPE Signals */
835    rv = apr_signal_block(SIGPIPE);
836    if(rv != APR_SUCCESS) {
837        /* error sending output */
838        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
839                "GnuTLS: Error Blocking SIGPIPE Signal!");
840    }
841}
842
843const char *mgs_hook_http_scheme(const request_rec * r) {
844    mgs_srvconf_rec *sc;
845
846    if (r == NULL)
847        return NULL;
848
849    sc = (mgs_srvconf_rec *) ap_get_module_config(r->
850            server->module_config,
851            &gnutls_module);
852
853    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
854    if (sc->enabled == GNUTLS_ENABLED_FALSE) {
855        return NULL;
856    }
857
858    return "https";
859}
860
861apr_port_t mgs_hook_default_port(const request_rec * r) {
862    mgs_srvconf_rec *sc;
863
864    if (r == NULL)
865        return 0;
866
867    sc = (mgs_srvconf_rec *) ap_get_module_config(r->
868            server->module_config,
869            &gnutls_module);
870
871    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
872    if (sc->enabled == GNUTLS_ENABLED_FALSE) {
873        return 0;
874    }
875
876    return 443;
877}
878
879
880
881typedef struct {
882    mgs_handle_t *ctxt;
883    mgs_srvconf_rec *sc;
884    const char *sni_name;
885} vhost_cb_rec;
886
887/**
888 * Matches the current vhost's ServerAlias directives
889 *
890 * @param x vhost callback record
891 * @param s server record
892 * @param tsc mod_gnutls server data for `s`
893 *
894 * @return true if a match, false otherwise
895 *
896 */
897int check_server_aliases(vhost_cb_rec *x, server_rec * s, mgs_srvconf_rec *tsc)
898{
899    apr_array_header_t *names;
900    int rv = 0;
901    char ** name;
902
903    /* Check ServerName First! */
904    if (strcasecmp(x->sni_name, s->server_hostname) == 0) {
905        // We have a match, save this server configuration
906        x->sc = tsc;
907        rv = 1;
908        /* Check any ServerAlias directives */
909    } else if(s->names->nelts) {
910        names = s->names;
911        name = (char **) names->elts;
912        for (int i = 0; i < names->nelts; ++i)
913        {
914            if (!name[i])
915                continue;
916            if (strcasecmp(x->sni_name, name[i]) == 0)
917            {
918                // We have a match, save this server configuration
919                x->sc = tsc;
920                rv = 1;
921            }
922        }
923        /* ServerAlias directives may contain wildcards, check those last. */
924    } else if(s->wild_names->nelts) {
925        names = s->wild_names;
926        name = (char **) names->elts;
927        for (int i = 0; i < names->nelts; ++i)
928        {
929            if (!name[i])
930                continue;
931            if (ap_strcasecmp_match(x->sni_name, name[i]) == 0)
932            {
933                x->sc = tsc;
934                rv = 1;
935            }
936        }
937    }
938    return rv;
939}
940
941static int vhost_cb(void *baton, conn_rec *conn, server_rec * s)
942{
943    mgs_srvconf_rec *tsc;
944    vhost_cb_rec *x = baton;
945    int ret;
946
947    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
948    tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
949            &gnutls_module);
950
951    if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
952        return 0;
953    }
954
955    if (tsc->certs_x509_chain_num > 0) {
956        /* this check is there to warn administrator of any missing hostname
957         * in the certificate. */
958        ret = gnutls_x509_crt_check_hostname(tsc->certs_x509_crt_chain[0], s->server_hostname);
959        if (0 == ret)
960            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, conn,
961                          "GnuTLS: the certificate doesn't match requested "
962                          "hostname '%s'", s->server_hostname);
963    } else {
964        ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, conn,
965                      "GnuTLS: SNI request for '%s' but no X.509 certs "
966                      "available at all",
967                      s->server_hostname);
968    }
969        return check_server_aliases(x, s, tsc);
970}
971
972/**
973 * Get SNI data from GnuTLS (if any) and search for a matching virtual
974 * host configuration. This method is called from the post client
975 * hello function.
976 *
977 * @param ctxt the mod_gnutls connection handle
978 *
979 * @return either the matching mod_gnutls server config, or `NULL`
980 */
981mgs_srvconf_rec *mgs_find_sni_server(mgs_handle_t *ctxt)
982{
983    if (ctxt->sni_name == NULL)
984    {
985        const char *sni_name = mgs_server_name_get(ctxt);
986        if (sni_name != NULL)
987            ctxt->sni_name = sni_name;
988        return NULL;
989    }
990
991    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
992                  "%s: client requested server '%s'.",
993                  __func__, ctxt->sni_name);
994
995    /* Search for vhosts matching connection parameters and the
996     * SNI. If a match is found, cbx.sc will contain the mod_gnutls
997     * server config for the vhost. */
998    vhost_cb_rec cbx = {
999        .ctxt = ctxt,
1000        .sc = NULL,
1001        .sni_name = ctxt->sni_name
1002    };
1003    int rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
1004    if (rv == 1) {
1005        return cbx.sc;
1006    }
1007    return NULL;
1008}
1009
1010
1011
1012#ifdef ENABLE_EARLY_SNI
1013static int early_sni_hook(gnutls_session_t session,
1014                          unsigned int htype __attribute__((unused)),
1015                          unsigned when __attribute__((unused)),
1016                          unsigned int incoming,
1017                          const gnutls_datum_t *msg)
1018{
1019    //assert(htype == GNUTLS_HANDSHAKE_CLIENT_HELLO);
1020    //assert(when == GNUTLS_HOOK_PRE);
1021    if (!incoming)
1022        return 0;
1023
1024    mgs_handle_t *ctxt = (mgs_handle_t *) gnutls_session_get_ptr(session);
1025    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ctxt->c,
1026                  "%s: Trying early SNI.",
1027                  __func__);
1028
1029    int ret = gnutls_ext_raw_parse(session, mgs_sni_ext_hook, msg,
1030                                   GNUTLS_EXT_RAW_FLAG_TLS_CLIENT_HELLO);
1031    if (ret == 0 && ctxt->sni_name != NULL)
1032        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ctxt->c,
1033                      "%s: Early SNI result: %s",
1034                      __func__, ctxt->sni_name);
1035    return ret;
1036}
1037#endif
1038
1039
1040
1041/**
1042 * This function is intended as a cleanup handler for connections
1043 * using GnuTLS. If attached to the connection pool, it ensures that
1044 * session resources are released with the connection pool even if the
1045 * session wasn't terminated properly.
1046 *
1047 * @param data must point to the mgs_handle_t associated with the
1048 * connection
1049 */
1050static apr_status_t cleanup_gnutls_session(void *data)
1051{
1052    /* nothing to do */
1053    if (data == NULL)
1054        return APR_SUCCESS;
1055
1056    /* check if session needs closing */
1057    mgs_handle_t *ctxt = (mgs_handle_t *) data;
1058    if (ctxt->session != NULL)
1059    {
1060        ap_log_cerror(APLOG_MARK, APLOG_WARNING, APR_ECONNABORTED, ctxt->c,
1061                      "%s: connection pool cleanup in progress but %sTLS "
1062                      "session hasn't been terminated, trying to close",
1063                      __func__, IS_PROXY_STR(ctxt));
1064        int ret;
1065        /* Try A Clean Shutdown */
1066        do
1067            ret = gnutls_bye(ctxt->session, GNUTLS_SHUT_WR);
1068        while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
1069        if (ret != GNUTLS_E_SUCCESS)
1070            ap_log_cerror(APLOG_MARK, APLOG_INFO, APR_EGENERAL, ctxt->c,
1071                          "%s: error while closing TLS %sconnection: %s (%d)",
1072                          __func__, IS_PROXY_STR(ctxt),
1073                          gnutls_strerror(ret), ret);
1074        else
1075            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ctxt->c,
1076                          "%s: TLS %sconnection closed.",
1077                          __func__, IS_PROXY_STR(ctxt));
1078        /* De-Initialize Session */
1079        gnutls_deinit(ctxt->session);
1080        ctxt->session = NULL;
1081    }
1082    return APR_SUCCESS;
1083}
1084
1085static void create_gnutls_handle(conn_rec * c)
1086{
1087    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
1088
1089    /* Get connection specific configuration */
1090    mgs_handle_t *ctxt = init_gnutls_ctxt(c);
1091    ctxt->enabled = GNUTLS_ENABLED_TRUE;
1092    ctxt->status = 0;
1093    ctxt->input_rc = APR_SUCCESS;
1094    ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc);
1095    ctxt->input_cbuf.length = 0;
1096    ctxt->output_rc = APR_SUCCESS;
1097    ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc);
1098    ctxt->output_blen = 0;
1099    ctxt->output_length = 0;
1100
1101    /* Initialize GnuTLS Library */
1102    int err = 0;
1103    if (ctxt->is_proxy == GNUTLS_ENABLED_TRUE)
1104    {
1105        /* this is an outgoing proxy connection, client mode */
1106        err = gnutls_init(&ctxt->session, GNUTLS_CLIENT);
1107        if (err != GNUTLS_E_SUCCESS)
1108            ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
1109                          "gnutls_init for proxy connection failed: %s (%d)",
1110                          gnutls_strerror(err), err);
1111    }
1112    else
1113    {
1114        /* incoming connection, server mode */
1115        err = gnutls_init(&ctxt->session, GNUTLS_SERVER);
1116        if (err != GNUTLS_E_SUCCESS)
1117            ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
1118                          "gnutls_init for server side failed: %s (%d)",
1119                          gnutls_strerror(err), err);
1120    }
1121
1122    /* Ensure TLS session resources are released when the connection
1123     * pool is cleared, if the filters haven't done that already. */
1124    apr_pool_pre_cleanup_register(c->pool, ctxt, cleanup_gnutls_session);
1125
1126    /* Set Default Priority */
1127        err = gnutls_priority_set(ctxt->session, default_prio);
1128    if (err != GNUTLS_E_SUCCESS)
1129        ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
1130                      "gnutls_priority_set failed!");
1131#ifdef ENABLE_EARLY_SNI
1132    /* Pre-handshake hook, EXPERIMENTAL */
1133    gnutls_handshake_set_hook_function(ctxt->session,
1134                                       GNUTLS_HANDSHAKE_CLIENT_HELLO,
1135                                       GNUTLS_HOOK_PRE, early_sni_hook);
1136#endif
1137    /* Set Handshake function */
1138    gnutls_handshake_set_post_client_hello_function(ctxt->session,
1139            mgs_select_virtual_server_cb);
1140
1141    /* Set GnuTLS user pointer, so we can access the module session
1142     * context in GnuTLS callbacks */
1143    gnutls_session_set_ptr(ctxt->session, ctxt);
1144
1145    /* If mod_gnutls is the TLS server, mgs_select_virtual_server_cb
1146     * will load appropriate credentials during handshake. However,
1147     * when handling a proxy backend connection, mod_gnutls acts as
1148     * TLS client and credentials must be loaded here. */
1149    if (ctxt->is_proxy == GNUTLS_ENABLED_TRUE)
1150    {
1151        /* Set anonymous client credentials for proxy connections */
1152        gnutls_credentials_set(ctxt->session, GNUTLS_CRD_ANON,
1153                               ctxt->sc->anon_client_creds);
1154        /* Set x509 credentials */
1155        gnutls_credentials_set(ctxt->session, GNUTLS_CRD_CERTIFICATE,
1156                               ctxt->sc->proxy_x509_creds);
1157        /* Load priorities from the server configuration */
1158        err = gnutls_priority_set(ctxt->session, ctxt->sc->proxy_priorities);
1159        if (err != GNUTLS_E_SUCCESS)
1160            ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
1161                          "%s: setting priorities for proxy connection "
1162                          "failed: %s (%d)",
1163                          __func__, gnutls_strerror(err), err);
1164    }
1165
1166    prepare_alpn_proposals(ctxt);
1167
1168    /* Initialize Session Cache */
1169    mgs_cache_session_init(ctxt);
1170
1171    /* Set pull, push & ptr functions */
1172    gnutls_transport_set_pull_function(ctxt->session,
1173            mgs_transport_read);
1174    gnutls_transport_set_push_function(ctxt->session,
1175            mgs_transport_write);
1176    gnutls_transport_set_ptr(ctxt->session, ctxt);
1177    /* Add IO filters */
1178    ctxt->input_filter = ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME,
1179            ctxt, NULL, c);
1180    ctxt->output_filter = ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME,
1181            ctxt, NULL, c);
1182}
1183
1184int mgs_hook_pre_connection(conn_rec * c, void *csd __attribute__((unused)))
1185{
1186    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
1187
1188    if (c->master)
1189    {
1190        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
1191                      "%s declined secondary connection", __func__);
1192        return DECLINED;
1193    }
1194
1195    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
1196        ap_get_module_config(c->base_server->module_config, &gnutls_module);
1197    mgs_handle_t *ctxt = (mgs_handle_t *)
1198        ap_get_module_config(c->conn_config, &gnutls_module);
1199
1200    if ((sc && (!sc->enabled))
1201        || (ctxt && ctxt->enabled == GNUTLS_ENABLED_FALSE))
1202    {
1203        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "%s declined connection",
1204                      __func__);
1205        return DECLINED;
1206    }
1207
1208    create_gnutls_handle(c);
1209    return OK;
1210}
1211
1212
1213
1214/**
1215 * process_connection hook: Do a zero byte read to trigger the
1216 * handshake. Doesn't change anything for traditional protocols that
1217 * just do reads, but HTTP/2 needs the TLS handshake and ALPN to
1218 * happen before its process_connection hook runs.
1219 */
1220int mgs_hook_process_connection(conn_rec* c)
1221{
1222    mgs_handle_t *ctxt = (mgs_handle_t *)
1223        ap_get_module_config(c->conn_config, &gnutls_module);
1224
1225    if ((ctxt != NULL) && (ctxt->enabled == GNUTLS_ENABLED_TRUE))
1226    {
1227        /* This connection is supposed to use TLS. Give the filters a
1228         * kick with a zero byte read to trigger the handshake. */
1229        apr_bucket_brigade* temp =
1230            apr_brigade_create(c->pool, c->bucket_alloc);
1231        ap_get_brigade(c->input_filters, temp,
1232                       AP_MODE_INIT, APR_BLOCK_READ, 0);
1233        apr_brigade_destroy(temp);
1234    }
1235    return DECLINED;
1236}
1237
1238
1239
1240/* Post request hook, checks if TLS connection and vhost match */
1241int mgs_req_vhost_check(request_rec *r)
1242{
1243    /* mod_gnutls server record for the request vhost */
1244    mgs_srvconf_rec *r_sc = (mgs_srvconf_rec *)
1245        ap_get_module_config(r->server->module_config, &gnutls_module);
1246    mgs_handle_t *ctxt = get_effective_gnutls_ctxt(r->connection);
1247
1248    /* Nothing to check for non-TLS and outgoing proxy connections */
1249    if (ctxt == NULL || !ctxt->enabled || ctxt->is_proxy)
1250        return DECLINED;
1251
1252    if (ctxt->sc != r_sc)
1253    {
1254        ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, ctxt->c,
1255                      "%s: Mismatch between handshake and request servers!",
1256                      __func__);
1257        return HTTP_MISDIRECTED_REQUEST;
1258    }
1259
1260    if (!ctxt->sni_name)
1261        return DECLINED;
1262
1263    /* Got an SNI name, so verify it matches. */
1264    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
1265                  "%s: Checking request hostname against SNI name '%s'.",
1266                  __func__, ctxt->sni_name);
1267
1268    if (!r->hostname)
1269    {
1270        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, r->connection,
1271                      "Client requested '%s' via SNI, but provided "
1272                      "no hostname in HTTP request!", ctxt->sni_name);
1273        return HTTP_MISDIRECTED_REQUEST;
1274    }
1275
1276    if (strcasecmp(r->hostname, ctxt->sni_name) != 0)
1277    {
1278        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, r->connection,
1279                      "Client requested '%s' via SNI, but '%s' in "
1280                      "the HTTP request!", ctxt->sni_name, r->hostname);
1281        return HTTP_MISDIRECTED_REQUEST;
1282    }
1283
1284    return DECLINED;
1285}
1286
1287
1288
1289int mgs_hook_fixups(request_rec * r) {
1290    unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
1291    const char *tmp;
1292    size_t len;
1293    mgs_handle_t *ctxt;
1294    int rv = OK;
1295
1296    if (r == NULL)
1297        return DECLINED;
1298
1299    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
1300    apr_table_t *env = r->subprocess_env;
1301
1302    ctxt = get_effective_gnutls_ctxt(r->connection);
1303
1304    if (!ctxt || ctxt->enabled != GNUTLS_ENABLED_TRUE || ctxt->session == NULL)
1305    {
1306        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "request declined in %s", __func__);
1307        return DECLINED;
1308    }
1309
1310    apr_table_setn(env, "HTTPS", "on");
1311
1312    apr_table_setn(env, "SSL_VERSION_LIBRARY",
1313            "GnuTLS/" LIBGNUTLS_VERSION);
1314    apr_table_setn(env, "SSL_VERSION_INTERFACE",
1315            "mod_gnutls/" MOD_GNUTLS_VERSION);
1316
1317    apr_table_setn(env, "SSL_PROTOCOL",
1318            gnutls_protocol_get_name(gnutls_protocol_get_version(ctxt->session)));
1319
1320    /* should have been called SSL_CIPHERSUITE instead */
1321    apr_table_setn(env, "SSL_CIPHER",
1322            gnutls_cipher_suite_get_name(gnutls_kx_get(ctxt->session),
1323                                         gnutls_cipher_get(ctxt->session),
1324                                         gnutls_mac_get(ctxt->session)));
1325
1326#if GNUTLS_VERSION_NUMBER >= 0x030600
1327    /* Compression support has been removed since GnuTLS 3.6.0 */
1328    apr_table_setn(env, "SSL_COMPRESS_METHOD", "NULL");
1329#else
1330    apr_table_setn(env, "SSL_COMPRESS_METHOD",
1331            gnutls_compression_get_name(gnutls_compression_get(ctxt->session)));
1332#endif
1333
1334#ifdef ENABLE_SRP
1335    if (ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) {
1336        tmp = gnutls_srp_server_get_username(ctxt->session);
1337        apr_table_setn(env, "SSL_SRP_USER", (tmp != NULL) ? tmp : "");
1338    } else {
1339        apr_table_unset(env, "SSL_SRP_USER");
1340    }
1341#endif
1342
1343    if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL)
1344        apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE");
1345
1346    unsigned int key_size = 8 * gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session));
1347    tmp = apr_psprintf(r->pool, "%u", key_size);
1348
1349    apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp);
1350
1351    apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp);
1352
1353    apr_table_setn(env, "SSL_CIPHER_EXPORT",
1354            (key_size <= 40) ? "true" : "false");
1355
1356    int dhsize = gnutls_dh_get_prime_bits(ctxt->session);
1357    if (dhsize > 0) {
1358        tmp = apr_psprintf(r->pool, "%d", dhsize);
1359        apr_table_setn(env, "SSL_DH_PRIME_BITS", tmp);
1360    }
1361
1362    len = sizeof (sbuf);
1363    gnutls_session_get_id(ctxt->session, sbuf, &len);
1364    apr_table_setn(env, "SSL_SESSION_ID",
1365                   apr_pescape_hex(r->pool, sbuf, len, 0));
1366
1367    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
1368        mgs_add_common_cert_vars(r, ctxt->sc->certs_x509_crt_chain[0], 0,
1369                                 ctxt->sc->export_certificates_size);
1370    }
1371
1372    return rv;
1373}
1374
1375int mgs_hook_authz(request_rec * r) {
1376    int rv;
1377    mgs_handle_t *ctxt;
1378    mgs_dirconf_rec *dc;
1379
1380    if (r == NULL)
1381        return DECLINED;
1382
1383    dc = ap_get_module_config(r->per_dir_config, &gnutls_module);
1384
1385    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
1386    ctxt = get_effective_gnutls_ctxt(r->connection);
1387
1388    if (!ctxt || ctxt->session == NULL) {
1389        return DECLINED;
1390    }
1391
1392    if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) {
1393        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1394                "GnuTLS: Directory set to Ignore Client Certificate!");
1395    } else {
1396        if (ctxt->sc->client_verify_mode < dc->client_verify_mode) {
1397            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1398                    "GnuTLS: Attempting to rehandshake with peer. %d %d",
1399                    ctxt->sc->client_verify_mode,
1400                    dc->client_verify_mode);
1401
1402            /* If we already have a client certificate, there's no point in
1403             * re-handshaking... */
1404            rv = mgs_cert_verify(r, ctxt);
1405            if (rv != DECLINED && rv != HTTP_FORBIDDEN)
1406                return rv;
1407
1408            gnutls_certificate_server_set_request
1409                    (ctxt->session, dc->client_verify_mode);
1410
1411            if (mgs_rehandshake(ctxt) != 0) {
1412                return HTTP_FORBIDDEN;
1413            }
1414        } else if (ctxt->sc->client_verify_mode ==
1415                GNUTLS_CERT_IGNORE) {
1416#if MOD_GNUTLS_DEBUG
1417            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1418                    "GnuTLS: Peer is set to IGNORE");
1419#endif
1420            return DECLINED;
1421        }
1422        rv = mgs_cert_verify(r, ctxt);
1423        if (rv != DECLINED
1424            && (rv != HTTP_FORBIDDEN
1425                || dc->client_verify_mode == GNUTLS_CERT_REQUIRE
1426                || (dc->client_verify_mode == -1
1427                    && ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUIRE)))
1428        {
1429            return rv;
1430        }
1431    }
1432
1433    return DECLINED;
1434}
1435
1436/* variables that are not sent by default:
1437 *
1438 * SSL_CLIENT_CERT      string  PEM-encoded client certificate
1439 * SSL_SERVER_CERT      string  PEM-encoded client certificate
1440 */
1441
1442/* @param side is either 0 for SERVER or 1 for CLIENT
1443 *
1444 * @param export_cert_size (int) maximum size for environment variable
1445 * to use for the PEM-encoded certificate (0 means do not export)
1446 */
1447#define MGS_SIDE(suffix) ((side==0) ? "SSL_SERVER" suffix : "SSL_CLIENT" suffix)
1448
1449static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, size_t export_cert_size) {
1450    unsigned char sbuf[64]; /* buffer to hold serials */
1451    char buf[AP_IOBUFSIZE];
1452    const char *tmp;
1453    char *tmp2;
1454    size_t len;
1455    int ret;
1456
1457    if (r == NULL)
1458        return;
1459
1460    apr_table_t *env = r->subprocess_env;
1461
1462    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
1463    if (export_cert_size > 0) {
1464        len = 0;
1465        ret = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_PEM, NULL, &len);
1466        if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
1467            if (len >= export_cert_size) {
1468                apr_table_setn(env, MGS_SIDE("_CERT"), "GNUTLS_CERTIFICATE_SIZE_LIMIT_EXCEEDED");
1469                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1470                              "GnuTLS: Failed to export too-large X.509 certificate to environment");
1471            } else {
1472                char* cert_buf = apr_palloc(r->pool, len + 1);
1473                if (cert_buf != NULL && gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0) {
1474                    cert_buf[len] = 0;
1475                    apr_table_setn(env, MGS_SIDE("_CERT"), cert_buf);
1476                } else {
1477                    ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
1478                                  "GnuTLS: failed to export X.509 certificate");
1479                }
1480            }
1481        } else {
1482            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
1483                          "GnuTLS: dazed and confused about X.509 certificate size");
1484        }
1485    }
1486
1487    len = sizeof (buf);
1488    gnutls_x509_crt_get_dn(cert, buf, &len);
1489    apr_table_setn(env, MGS_SIDE("_S_DN"), apr_pstrmemdup(r->pool, buf, len));
1490
1491    len = sizeof (buf);
1492    gnutls_x509_crt_get_issuer_dn(cert, buf, &len);
1493    apr_table_setn(env, MGS_SIDE("_I_DN"), apr_pstrmemdup(r->pool, buf, len));
1494
1495    len = sizeof (sbuf);
1496    gnutls_x509_crt_get_serial(cert, sbuf, &len);
1497    apr_table_setn(env, MGS_SIDE("_M_SERIAL"),
1498                   apr_pescape_hex(r->pool, sbuf, len, 0));
1499
1500    ret = gnutls_x509_crt_get_version(cert);
1501    if (ret > 0)
1502        apr_table_setn(env, MGS_SIDE("_M_VERSION"),
1503                       apr_psprintf(r->pool, "%u", ret));
1504
1505    apr_table_setn(env, MGS_SIDE("_CERT_TYPE"), "X.509");
1506
1507    tmp =
1508            mgs_time2sz(gnutls_x509_crt_get_expiration_time
1509            (cert), buf, sizeof (buf));
1510    apr_table_setn(env, MGS_SIDE("_V_END"), apr_pstrdup(r->pool, tmp));
1511
1512    tmp =
1513            mgs_time2sz(gnutls_x509_crt_get_activation_time
1514            (cert), buf, sizeof (buf));
1515    apr_table_setn(env, MGS_SIDE("_V_START"), apr_pstrdup(r->pool, tmp));
1516
1517    ret = gnutls_x509_crt_get_signature_algorithm(cert);
1518    if (ret >= 0) {
1519        apr_table_setn(env, MGS_SIDE("_A_SIG"),
1520                gnutls_sign_algorithm_get_name(ret));
1521    }
1522
1523    ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL);
1524    if (ret >= 0) {
1525        apr_table_setn(env, MGS_SIDE("_A_KEY"),
1526                gnutls_pk_algorithm_get_name(ret));
1527    }
1528
1529    /* export all the alternative names (DNS, RFC822 and URI) */
1530    for (int i = 0; !(ret < 0); i++)
1531    {
1532        const char *san, *sanlabel;
1533        len = 0;
1534        ret = gnutls_x509_crt_get_subject_alt_name(cert, i,
1535                NULL, &len,
1536                NULL);
1537
1538        if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && len > 1) {
1539            tmp2 = apr_palloc(r->pool, len + 1);
1540
1541            ret =
1542                    gnutls_x509_crt_get_subject_alt_name(cert, i,
1543                    tmp2,
1544                    &len,
1545                    NULL);
1546            tmp2[len] = 0;
1547
1548            sanlabel = apr_psprintf(r->pool, "%s%u", MGS_SIDE("_S_AN"), i);
1549            if (ret == GNUTLS_SAN_DNSNAME) {
1550                san = apr_psprintf(r->pool, "DNSNAME:%s", tmp2);
1551            } else if (ret == GNUTLS_SAN_RFC822NAME) {
1552                san = apr_psprintf(r->pool, "RFC822NAME:%s", tmp2);
1553            } else if (ret == GNUTLS_SAN_URI) {
1554                san = apr_psprintf(r->pool, "URI:%s", tmp2);
1555            } else {
1556                san = "UNSUPPORTED";
1557            }
1558            apr_table_setn(env, sanlabel, san);
1559        }
1560    }
1561}
1562
1563
1564
1565/* TODO: Allow client sending a X.509 certificate chain */
1566static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) {
1567    const gnutls_datum_t *cert_list;
1568    unsigned int cert_list_size;
1569    /* assume the certificate is invalid unless explicitly set
1570     * otherwise */
1571    unsigned int status = GNUTLS_CERT_INVALID;
1572    int rv = GNUTLS_E_NO_CERTIFICATE_FOUND, ret;
1573    unsigned int ch_size = 0;
1574
1575    // TODO: union no longer needed here after removing its "pgp" component.
1576    union {
1577        gnutls_x509_crt_t x509[MAX_CHAIN_SIZE];
1578    } cert;
1579    apr_time_t expiration_time, cur_time;
1580
1581    if (r == NULL || ctxt == NULL || ctxt->session == NULL)
1582        return HTTP_FORBIDDEN;
1583
1584    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
1585    cert_list =
1586            gnutls_certificate_get_peers(ctxt->session, &cert_list_size);
1587
1588    if (cert_list == NULL || cert_list_size == 0) {
1589        /* It is perfectly OK for a client not to send a certificate if on REQUEST mode
1590         */
1591        if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
1592            return OK;
1593
1594        /* no certificate provided by the client, but one was required. */
1595        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1596                "GnuTLS: Failed to Verify Peer: "
1597                "Client did not submit a certificate");
1598        return HTTP_FORBIDDEN;
1599    }
1600
1601    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
1602        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1603                "GnuTLS: A Chain of %d certificate(s) was provided for validation",
1604                cert_list_size);
1605
1606        for (ch_size = 0; ch_size < cert_list_size; ch_size++) {
1607            gnutls_x509_crt_init(&cert.x509[ch_size]);
1608            rv = gnutls_x509_crt_import(cert.x509[ch_size],
1609                    &cert_list[ch_size],
1610                    GNUTLS_X509_FMT_DER);
1611            // When failure to import, leave the loop
1612            if (rv != GNUTLS_E_SUCCESS) {
1613                if (ch_size < 1) {
1614                    ap_log_rerror(APLOG_MARK,
1615                            APLOG_INFO, 0, r,
1616                            "GnuTLS: Failed to Verify Peer: "
1617                            "Failed to import peer certificates.");
1618                    ret = HTTP_FORBIDDEN;
1619                    goto exit;
1620                }
1621                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1622                        "GnuTLS: Failed to import some peer certificates. Using %d certificates",
1623                        ch_size);
1624                rv = GNUTLS_E_SUCCESS;
1625                break;
1626            }
1627        }
1628    } else
1629        return HTTP_FORBIDDEN;
1630
1631    if (rv < 0) {
1632        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1633                "GnuTLS: Failed to Verify Peer: "
1634                "Failed to import peer certificates.");
1635        ret = HTTP_FORBIDDEN;
1636        goto exit;
1637    }
1638
1639    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
1640        apr_time_ansi_put(&expiration_time,
1641                gnutls_x509_crt_get_expiration_time
1642                (cert.x509[0]));
1643
1644        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1645                      "GnuTLS: Verifying list of %d certificate(s) via method '%s'",
1646                      ch_size, mgs_readable_cvm(ctxt->sc->client_verify_method));
1647        switch(ctxt->sc->client_verify_method) {
1648        case mgs_cvm_cartel:
1649            rv = gnutls_x509_crt_list_verify(cert.x509, ch_size,
1650                                             ctxt->sc->ca_list,
1651                                             ctxt->sc->ca_list_size,
1652                                             NULL, 0, 0, &status);
1653            break;
1654#ifdef ENABLE_MSVA
1655        case mgs_cvm_msva:
1656        {
1657            struct msv_response* resp = NULL;
1658            struct msv_query q = { .context="https", .peertype="client", .pkctype="x509pem" };
1659            msv_ctxt_t ctx = msv_ctxt_init(NULL);
1660            char cert_pem_buf[10 * 1024];
1661            size_t len = sizeof (cert_pem_buf);
1662
1663            rv = 0;
1664            if (gnutls_x509_crt_export(cert.x509[0], GNUTLS_X509_FMT_PEM, cert_pem_buf, &len) >= 0) {
1665                /* FIXME : put together a name from the cert we received, instead of hard-coding this value: */
1666                q.peername = mgs_x509_construct_uid(r, cert.x509[0]);
1667                q.pkcdata = cert_pem_buf;
1668                rv = msv_query_agent(ctx, q, &resp);
1669                if (rv == LIBMSV_ERROR_SUCCESS) {
1670                    status = 0;
1671                } else if (rv == LIBMSV_ERROR_INVALID) {
1672                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1673                                  "GnuTLS: Monkeysphere validation failed: (message: %s)", resp->message);
1674                    status = GNUTLS_CERT_INVALID;
1675                } else {
1676                    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
1677                                  "GnuTLS: Error communicating with the Monkeysphere Validation Agent: (%d) %s", rv, msv_strerror(ctx, rv));
1678                    status = GNUTLS_CERT_INVALID;
1679                    rv = -1;
1680                }
1681            } else {
1682                ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1683                              "GnuTLS: Could not convert the client certificate to PEM format");
1684                status = GNUTLS_CERT_INVALID;
1685                rv = GNUTLS_E_ASN1_ELEMENT_NOT_FOUND;
1686            }
1687            msv_response_destroy(resp);
1688            msv_ctxt_destroy(ctx);
1689        }
1690            break;
1691#endif
1692        default:
1693            /* If this block is reached, that indicates a
1694             * configuration error or bug in mod_gnutls (invalid value
1695             * of ctxt->sc->client_verify_method). */
1696            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1697                          "GnuTLS: Failed to Verify X.509 Peer: method '%s' is not supported",
1698                          mgs_readable_cvm(ctxt->sc->client_verify_method));
1699            rv = GNUTLS_E_UNIMPLEMENTED_FEATURE;
1700        }
1701
1702    } else {
1703        /* Unknown certificate type */
1704        rv = GNUTLS_E_UNIMPLEMENTED_FEATURE;
1705    }
1706
1707    /* "goto exit" at the end of this block skips evaluation of the
1708     * "status" variable */
1709    if (rv < 0) {
1710        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1711                "GnuTLS: Failed to Verify Peer certificate: (%d) %s",
1712                rv, gnutls_strerror(rv));
1713        if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND)
1714            ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r,
1715                "GnuTLS: No certificate was found for verification. Did you set the GnuTLSClientCAFile directive?");
1716        ret = HTTP_FORBIDDEN;
1717        goto exit;
1718    }
1719
1720    /* TODO: X509 CRL Verification. */
1721    /* May add later if anyone needs it.
1722     */
1723    /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */
1724
1725    cur_time = apr_time_now();
1726
1727    if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
1728        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1729                "GnuTLS: Could not find Signer for Peer Certificate");
1730    }
1731
1732    if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
1733        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1734                "GnuTLS: Peer's Certificate signer is not a CA");
1735    }
1736
1737    if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
1738        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1739                "GnuTLS: Peer's Certificate is using insecure algorithms");
1740    }
1741
1742    if (status & GNUTLS_CERT_EXPIRED
1743            || status & GNUTLS_CERT_NOT_ACTIVATED) {
1744        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1745                "GnuTLS: Peer's Certificate signer is expired or not yet activated");
1746    }
1747
1748    if (status & GNUTLS_CERT_INVALID) {
1749        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1750                "GnuTLS: Peer Certificate is invalid.");
1751    } else if (status & GNUTLS_CERT_REVOKED) {
1752        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1753                "GnuTLS: Peer Certificate is revoked.");
1754    }
1755
1756    mgs_add_common_cert_vars(r, cert.x509[0], 1, ctxt->sc->export_certificates_size);
1757
1758    {
1759        /* days remaining */
1760        unsigned long remain =
1761                (apr_time_sec(expiration_time) -
1762                apr_time_sec(cur_time)) / 86400;
1763        apr_table_setn(r->subprocess_env, "SSL_CLIENT_V_REMAIN",
1764                apr_psprintf(r->pool, "%lu", remain));
1765    }
1766
1767    if (status == 0) {
1768        apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY",
1769                "SUCCESS");
1770        ret = OK;
1771    } else {
1772        apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY",
1773                "FAILED");
1774        if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST)
1775            ret = OK;
1776        else
1777            ret = HTTP_FORBIDDEN;
1778    }
1779
1780exit:
1781    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509)
1782        for (unsigned int i = 0; i < ch_size; i++)
1783            gnutls_x509_crt_deinit(cert.x509[i]);
1784
1785    return ret;
1786}
1787
1788
1789
1790#ifdef ENABLE_MSVA
1791/* this section of code is used only when trying to talk to the MSVA */
1792static const char* mgs_x509_leaf_oid_from_dn(apr_pool_t *pool, const char* oid, gnutls_x509_crt_t cert) {
1793    int rv=GNUTLS_E_SUCCESS, i;
1794    size_t sz=0, lastsz=0;
1795    char* data=NULL;
1796
1797    i = -1;
1798    while(rv != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
1799        i++;
1800        lastsz=sz;
1801        sz=0;
1802        rv = gnutls_x509_crt_get_dn_by_oid (cert, oid, i, 0, NULL, &sz);
1803    }
1804    if (i > 0) {
1805        data = apr_palloc(pool, lastsz);
1806        sz=lastsz;
1807        rv = gnutls_x509_crt_get_dn_by_oid (cert, oid, i-1, 0, data, &sz);
1808        if (rv == GNUTLS_E_SUCCESS)
1809            return data;
1810    }
1811    return NULL;
1812}
1813
1814static const char* mgs_x509_first_type_from_san(apr_pool_t *pool, gnutls_x509_subject_alt_name_t target, gnutls_x509_crt_t cert) {
1815    int rv=GNUTLS_E_SUCCESS;
1816    size_t sz;
1817    char* data=NULL;
1818    unsigned int i;
1819    gnutls_x509_subject_alt_name_t thistype;
1820
1821    i = 0;
1822    while(rv != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
1823        sz = 0;
1824        rv = gnutls_x509_crt_get_subject_alt_name2(cert, i, NULL, &sz, &thistype, NULL);
1825        if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && thistype == target) {
1826            data = apr_palloc(pool, sz);
1827            rv = gnutls_x509_crt_get_subject_alt_name2(cert, i, data, &sz, &thistype, NULL);
1828            if (rv >=0 && (thistype == target))
1829                return data;
1830        }
1831        i++;
1832    }
1833    return NULL;
1834}
1835
1836
1837/* Create a string representing a candidate User ID from an X.509
1838 * certificate
1839
1840 * We need this for client certification because a client gives us a
1841 * certificate, but doesn't tell us (in any other way) who they are
1842 * trying to authenticate as.
1843
1844 * one complaint might be "but the user wanted to be another identity,
1845 * which is also in the certificate (e.g. in a SubjectAltName)"
1846 * However, given that any user can regenerate their own X.509
1847 * certificate with their own public key content, they should just do
1848 * so, and not expect us to guess at their identity :)
1849
1850 * This function allocates it's response from the pool given it.  When
1851 * that pool is reclaimed, the response will also be deallocated.
1852
1853 * FIXME: what about extracting a server-style cert
1854 *        (e.g. https://imposter.example) from the DN or any sAN?
1855
1856 * FIXME: what if we want to call this outside the context of a
1857 *        request?  That complicates the logging.
1858 */
1859static const char* mgs_x509_construct_uid(request_rec *r, gnutls_x509_crt_t cert) {
1860    /* basic strategy, assuming humans are the users: we are going to
1861     * try to reconstruct a "conventional" User ID by pulling in a
1862     * name, comment, and e-mail address.
1863     */
1864    apr_pool_t *pool = r->pool;
1865    const char *name=NULL, *comment=NULL, *email=NULL;
1866    const char *ret=NULL;
1867    /* subpool for temporary allocation: */
1868    apr_pool_t *sp=NULL;
1869
1870    if (APR_SUCCESS != apr_pool_create(&sp, pool))
1871        return NULL; /* i'm assuming that libapr would log this kind
1872                      * of error on its own */
1873
1874     /* Name
1875
1876     the name comes from the leaf commonName of the cert's Subject.
1877
1878     (MAYBE: should we look at trying to assemble a candidate from
1879             givenName, surName, suffix, etc?  the "name" field
1880             appears to be case-insensitive, which seems problematic
1881             from what we expect; see:
1882             http://www.itu.int/rec/T-REC-X.520-200102-s/e )
1883
1884     (MAYBE: should we try pulling a commonName or otherName or
1885             something from subjectAltName? see:
1886             https://tools.ietf.org/html/rfc5280#section-4.2.1.6
1887             GnuTLS does not support looking for Common Names in the
1888             SAN yet)
1889     */
1890    name = mgs_x509_leaf_oid_from_dn(sp, GNUTLS_OID_X520_COMMON_NAME, cert);
1891
1892    /* Comment
1893
1894       I am inclined to punt on this for now, as Comment has been so
1895       atrociously misused in OpenPGP.  Perhaps if there is a
1896       pseudonym (OID 2.5.4.65, aka GNUTLS_OID_X520_PSEUDONYM) field
1897       in the subject or sAN?
1898    */
1899    comment = mgs_x509_leaf_oid_from_dn(sp, GNUTLS_OID_X520_PSEUDONYM, cert);
1900
1901    /* E-mail
1902
1903       This should be the the first rfc822Name from the sAN.
1904
1905       failing that, we'll take the leaf email in the certificate's
1906       subject; this is a deprecated use though.
1907     */
1908    email = mgs_x509_first_type_from_san(sp, GNUTLS_SAN_RFC822NAME, cert);
1909    if (email == NULL)
1910        email = mgs_x509_leaf_oid_from_dn(sp, GNUTLS_OID_PKCS9_EMAIL, cert);
1911
1912    /* assemble all the parts: */
1913
1914    /* must have at least a name or an e-mail. */
1915    if (name == NULL && email == NULL) {
1916        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
1917                "GnuTLS: Need either a name or an e-mail address to get a User ID from an X.509 certificate.");
1918        goto end;
1919    }
1920    if (name) {
1921        if (comment) {
1922            if (email) {
1923                ret = apr_psprintf(pool, "%s (%s) <%s>", name, comment, email);
1924            } else {
1925                ret = apr_psprintf(pool, "%s (%s)", name, comment);
1926            }
1927        } else {
1928            if (email) {
1929                ret = apr_psprintf(pool, "%s <%s>", name, email);
1930            } else {
1931                ret = apr_pstrdup(pool, name);
1932            }
1933        }
1934    } else {
1935        if (comment) {
1936            ret = apr_psprintf(pool, "(%s) <%s>", comment, email);
1937        } else {
1938            ret = apr_psprintf(pool, "<%s>", email);
1939        }
1940    }
1941
1942end:
1943    apr_pool_destroy(sp);
1944    return ret;
1945}
1946#endif /* ENABLE_MSVA */
1947
1948
1949
1950/*
1951 * This hook writes the mod_gnutls status message for a mod_status
1952 * report. According to the comments in mod_status.h, the "flags"
1953 * parameter is a bitwise OR of the AP_STATUS_ flags.
1954 *
1955 * Note that this implementation gives flags explicitly requesting a
1956 * simple response priority, e.g. if AP_STATUS_SHORT is set, flags
1957 * requesting an HTML report will be ignored. As of Apache 2.4.10, the
1958 * following flags were defined in mod_status.h:
1959 *
1960 * AP_STATUS_SHORT (short, non-HTML report requested)
1961 * AP_STATUS_NOTABLE (HTML report without tables)
1962 * AP_STATUS_EXTENDED (detailed report)
1963 */
1964static int mgs_status_hook(request_rec *r, int flags)
1965{
1966    if (r == NULL)
1967        return OK;
1968
1969    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
1970        ap_get_module_config(r->server->module_config, &gnutls_module);
1971
1972    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
1973
1974    if (flags & AP_STATUS_SHORT)
1975    {
1976        ap_rprintf(r, "Using GnuTLS version: %s\n", gnutls_check_version(NULL));
1977        ap_rputs("Built against GnuTLS version: " GNUTLS_VERSION "\n", r);
1978    }
1979    else
1980    {
1981        ap_rputs("<hr>\n", r);
1982        ap_rputs("<h2>GnuTLS Information:</h2>\n<dl>\n", r);
1983
1984        ap_rprintf(r, "<dt>Using GnuTLS version:</dt><dd>%s</dd>\n",
1985                   gnutls_check_version(NULL));
1986        ap_rputs("<dt>Built against GnuTLS version:</dt><dd>"
1987                 GNUTLS_VERSION "</dd>\n", r);
1988        ap_rprintf(r, "<dt>Using TLS:</dt><dd>%s</dd>\n",
1989                   (sc->enabled == GNUTLS_ENABLED_FALSE ? "no" : "yes"));
1990    }
1991
1992    if (sc->enabled != GNUTLS_ENABLED_FALSE)
1993    {
1994        mgs_handle_t* ctxt = get_effective_gnutls_ctxt(r->connection);
1995        if (ctxt && ctxt->session != NULL)
1996        {
1997            char* s_info = gnutls_session_get_desc(ctxt->session);
1998            if (s_info)
1999            {
2000                if (flags & AP_STATUS_SHORT)
2001                    ap_rprintf(r, "Current TLS session: %s\n", s_info);
2002                else
2003                    ap_rprintf(r, "<dt>Current TLS session:</dt><dd>%s</dd>\n",
2004                               s_info);
2005                gnutls_free(s_info);
2006            }
2007        }
2008    }
2009
2010    if (!(flags & AP_STATUS_SHORT))
2011        ap_rputs("</dl>\n", r);
2012
2013    if (sc->ocsp_cache)
2014        mgs_cache_status(sc->ocsp_cache, "GnuTLS OCSP Cache", r, flags);
2015    if (sc->cache_enable)
2016        mgs_cache_status(sc->cache, "GnuTLS Session Cache", r, flags);
2017
2018    return OK;
2019}
2020
2021
2022
2023/*
2024 * Callback to check the server certificate for proxy HTTPS
2025 * connections, to be used with
2026 * gnutls_certificate_set_verify_function.
2027
2028 * Returns: 0 if certificate check was successful (certificate
2029 * trusted), non-zero otherwise (error during check or untrusted
2030 * certificate).
2031 */
2032static int gtls_check_server_cert(gnutls_session_t session)
2033{
2034    mgs_handle_t *ctxt = (mgs_handle_t *) gnutls_session_get_ptr(session);
2035    unsigned int status;
2036
2037    /* Get peer hostname from a note left by mod_proxy */
2038    const char *peer_hostname =
2039        apr_table_get(ctxt->c->notes, PROXY_SNI_NOTE);
2040    if (peer_hostname == NULL)
2041        ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, ctxt->c,
2042                      "%s: " PROXY_SNI_NOTE " NULL, cannot check "
2043                      "peer's hostname", __func__);
2044
2045    /* Verify certificate, including hostname match. Should
2046     * peer_hostname be NULL for some reason, the name is not
2047     * checked. */
2048    int err = gnutls_certificate_verify_peers3(session, peer_hostname,
2049                                               &status);
2050    if (err != GNUTLS_E_SUCCESS)
2051    {
2052        ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, ctxt->c,
2053                      "%s: server certificate check failed: %s (%d)",
2054                      __func__, gnutls_strerror(err), err);
2055        return err;
2056    }
2057
2058    if (status == 0)
2059        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctxt->c,
2060                      "%s: server certificate is trusted.",
2061                      __func__);
2062    else
2063    {
2064        gnutls_datum_t out;
2065        /* GNUTLS_CRT_X509: ATM, only X509 is supported for proxy
2066         * certs 0: according to function API, the last argument
2067         * should be 0 */
2068        err = gnutls_certificate_verification_status_print(status,
2069                                                           GNUTLS_CRT_X509,
2070                                                           &out, 0);
2071        if (err != GNUTLS_E_SUCCESS)
2072            ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, ctxt->c,
2073                          "%s: server verify print failed: %s (%d)",
2074                          __func__, gnutls_strerror(err), err);
2075        else
2076            ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, ctxt->c,
2077                          "%s: %s",
2078                          __func__, out.data);
2079        gnutls_free(out.data);
2080    }
2081
2082    return status;
2083}
2084
2085
2086
2087static apr_status_t cleanup_proxy_x509_credentials(void *arg)
2088{
2089    mgs_srvconf_rec *sc = (mgs_srvconf_rec *) arg;
2090
2091    if (sc->proxy_x509_creds)
2092    {
2093        /* This implicitly releases the associated trust list
2094         * sc->proxy_x509_tl, too. */
2095        gnutls_certificate_free_credentials(sc->proxy_x509_creds);
2096        sc->proxy_x509_creds = NULL;
2097        sc->proxy_x509_tl = NULL;
2098    }
2099
2100    if (sc->anon_client_creds)
2101    {
2102        gnutls_anon_free_client_credentials(sc->anon_client_creds);
2103        sc->anon_client_creds = NULL;
2104    }
2105
2106    /* Deinit proxy priorities only if set from
2107     * sc->proxy_priorities_str. Otherwise the server is using the
2108     * default global priority cache, which must not be deinitialized
2109     * here. */
2110    if (sc->proxy_priorities_str && sc->proxy_priorities)
2111    {
2112        gnutls_priority_deinit(sc->proxy_priorities);
2113        sc->proxy_priorities = NULL;
2114    }
2115
2116    return APR_SUCCESS;
2117}
2118
2119
2120
2121static apr_status_t load_proxy_x509_credentials(apr_pool_t *pconf,
2122                                                apr_pool_t *ptemp,
2123                                                server_rec *s)
2124{
2125    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
2126        ap_get_module_config(s->module_config, &gnutls_module);
2127
2128    if (sc == NULL)
2129        return APR_EGENERAL;
2130
2131    apr_status_t ret = APR_EINIT;
2132    int err = GNUTLS_E_SUCCESS;
2133
2134    /* Cleanup function for the GnuTLS structures allocated below */
2135    apr_pool_cleanup_register(pconf, sc, cleanup_proxy_x509_credentials,
2136                              apr_pool_cleanup_null);
2137
2138    /* Function pool, gets destroyed before exit. */
2139    apr_pool_t *pool;
2140    ret = apr_pool_create(&pool, ptemp);
2141    if (ret != APR_SUCCESS)
2142    {
2143        ap_log_error(APLOG_MARK, APLOG_ERR, ret, s,
2144                     "%s: failed to allocate function memory pool.", __func__);
2145        return ret;
2146    }
2147
2148    /* allocate credentials structures */
2149    err = gnutls_certificate_allocate_credentials(&sc->proxy_x509_creds);
2150    if (err != GNUTLS_E_SUCCESS)
2151    {
2152        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
2153                     "%s: Failed to initialize proxy credentials: (%d) %s",
2154                     __func__, err, gnutls_strerror(err));
2155        return APR_EGENERAL;
2156    }
2157    err = gnutls_anon_allocate_client_credentials(&sc->anon_client_creds);
2158    if (err != GNUTLS_E_SUCCESS)
2159    {
2160        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
2161                     "%s: Failed to initialize anon credentials for proxy: "
2162                     "(%d) %s", __func__, err, gnutls_strerror(err));
2163        return APR_EGENERAL;
2164    }
2165
2166    /* Check if the proxy priorities have been set, fail immediately
2167     * if not */
2168    if (sc->proxy_priorities_str == NULL)
2169    {
2170        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
2171                     "No GnuTLSProxyPriorities directive for host '%s:%d', "
2172                     "using default '%s'.",
2173                     s->server_hostname, s->addrs->host_port,
2174                     MGS_DEFAULT_PRIORITY);
2175        sc->proxy_priorities = default_prio;
2176    }
2177    else
2178    {
2179        /* parse proxy priorities */
2180        const char *err_pos = NULL;
2181        err = gnutls_priority_init(&sc->proxy_priorities,
2182                                   sc->proxy_priorities_str, &err_pos);
2183        if (err != GNUTLS_E_SUCCESS)
2184        {
2185            if (ret == GNUTLS_E_INVALID_REQUEST)
2186                ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
2187                             "%s: Syntax error parsing proxy priorities "
2188                             "string at: %s",
2189                             __func__, err_pos);
2190            else
2191                ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
2192                             "Error setting proxy priorities: %s (%d)",
2193                             gnutls_strerror(err), err);
2194            ret = APR_EGENERAL;
2195        }
2196    }
2197
2198    /* load certificate and key for client auth, if configured */
2199    if (sc->proxy_x509_key_file && sc->proxy_x509_cert_file)
2200    {
2201        char* cert_file = ap_server_root_relative(pool,
2202                                                  sc->proxy_x509_cert_file);
2203        char* key_file = ap_server_root_relative(pool,
2204                                                 sc->proxy_x509_key_file);
2205        err = gnutls_certificate_set_x509_key_file(sc->proxy_x509_creds,
2206                                                   cert_file,
2207                                                   key_file,
2208                                                   GNUTLS_X509_FMT_PEM);
2209        if (err != GNUTLS_E_SUCCESS)
2210        {
2211            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
2212                         "%s: loading proxy client credentials failed: %s (%d)",
2213                         __func__, gnutls_strerror(err), err);
2214            ret = APR_EGENERAL;
2215        }
2216    }
2217    else if (!sc->proxy_x509_key_file && sc->proxy_x509_cert_file)
2218    {
2219        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
2220                     "%s: proxy key file not set!", __func__);
2221        ret = APR_EGENERAL;
2222    }
2223    else if (!sc->proxy_x509_cert_file && sc->proxy_x509_key_file)
2224    {
2225        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
2226                     "%s: proxy certificate file not set!", __func__);
2227        ret = APR_EGENERAL;
2228    }
2229    else
2230        /* if both key and cert are NULL, client auth is not used */
2231        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
2232                     "%s: no client credentials for proxy", __func__);
2233
2234    /* must be set if the server certificate is to be checked */
2235    if (sc->proxy_x509_ca_file)
2236    {
2237        /* initialize the trust list */
2238        err = gnutls_x509_trust_list_init(&sc->proxy_x509_tl, 0);
2239        if (err != GNUTLS_E_SUCCESS)
2240        {
2241            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
2242                         "%s: gnutls_x509_trust_list_init failed: %s (%d)",
2243                         __func__, gnutls_strerror(err), err);
2244            ret = APR_EGENERAL;
2245        }
2246
2247        char* ca_file = ap_server_root_relative(pool,
2248                                                sc->proxy_x509_ca_file);
2249        /* if no CRL is used, sc->proxy_x509_crl_file is NULL */
2250        char* crl_file = NULL;
2251        if (sc->proxy_x509_crl_file)
2252            crl_file = ap_server_root_relative(pool,
2253                                               sc->proxy_x509_crl_file);
2254
2255        /* returns number of loaded elements */
2256        err = gnutls_x509_trust_list_add_trust_file(sc->proxy_x509_tl,
2257                                                    ca_file,
2258                                                    crl_file,
2259                                                    GNUTLS_X509_FMT_PEM,
2260                                                    0 /* tl_flags */,
2261                                                    0 /* tl_vflags */);
2262        if (err > 0)
2263            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
2264                         "%s: proxy CA trust list: %d structures loaded",
2265                         __func__, err);
2266        else if (err == 0)
2267            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
2268                         "%s: proxy CA trust list is empty (%d)",
2269                         __func__, err);
2270        else /* err < 0 */
2271        {
2272            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
2273                         "%s: error loading proxy CA trust list: %s (%d)",
2274                         __func__, gnutls_strerror(err), err);
2275            ret = APR_EGENERAL;
2276        }
2277
2278        /* attach trust list to credentials */
2279        gnutls_certificate_set_trust_list(sc->proxy_x509_creds,
2280                                          sc->proxy_x509_tl, 0);
2281    }
2282    else
2283        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
2284                     "%s: no CA trust list for proxy connections, "
2285                     "TLS connections will fail!", __func__);
2286
2287    gnutls_certificate_set_verify_function(sc->proxy_x509_creds,
2288                                           gtls_check_server_cert);
2289    apr_pool_destroy(pool);
2290    return ret;
2291}
Note: See TracBrowser for help on using the repository browser.