Changeset 19e80a5 in mod_gnutls for src/gnutls_hooks.c


Ignore:
Timestamp:
Jan 28, 2019, 2:50:38 PM (16 months ago)
Author:
Fiona Klute <fiona.klute@…>
Branches:
debian/master
Children:
102aa67
Parents:
0931b35 (diff), ea9c699 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Update upstream source from tag 'upstream/0.9.0'

Update to upstream version '0.9.0'
with Debian dir 619b546038886b240d2c8e61ee1a1b13ce0867d7

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/gnutls_hooks.c

    r0931b35 r19e80a5  
    44 *  Copyright 2011 Dash Shendy
    55 *  Copyright 2013-2014 Daniel Kahn Gillmor
    6  *  Copyright 2015-2018 Fiona Klute
     6 *  Copyright 2015-2019 Fiona Klute
    77 *
    88 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2121#include "mod_gnutls.h"
    2222#include "gnutls_cache.h"
     23#include "gnutls_config.h"
    2324#include "gnutls_ocsp.h"
     25#include "gnutls_proxy.h"
     26#include "gnutls_sni.h"
    2427#include "gnutls_util.h"
     28#include "gnutls_watchdog.h"
     29
    2530#include "http_vhost.h"
    2631#include "ap_mpm.h"
    27 #include "mod_status.h"
     32#include <mod_status.h>
    2833#include <util_mutex.h>
    2934#include <apr_escape.h>
     35/* This provides strcmp and related functions */
     36#define APR_WANT_STRFUNC
     37#include <apr_want.h>
    3038
    3139#ifdef ENABLE_MSVA
     
    5058static gnutls_datum_t session_ticket_key = {NULL, 0};
    5159
     60
     61
    5262static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
    53 /* use side==0 for server and side==1 for client */
     63/** use side==0 for server and side==1 for client */
    5464static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, size_t export_cert_size);
    55 static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, size_t export_cert_size);
     65mgs_srvconf_rec* mgs_find_sni_server(mgs_handle_t *ctxt);
    5666static int mgs_status_hook(request_rec *r, int flags);
    5767#ifdef ENABLE_MSVA
    5868static const char* mgs_x509_construct_uid(request_rec * pool, gnutls_x509_crt_t cert);
    5969#endif
    60 static int load_proxy_x509_credentials(apr_pool_t *pconf, apr_pool_t *ptemp, server_rec *s)
    61     __attribute__((nonnull));
    6270
    6371/* Pool Cleanup Function */
     
    7179    session_ticket_key.data = NULL;
    7280    session_ticket_key.size = 0;
     81
     82    /* Deinit default priority setting */
     83    mgs_default_priority_deinit();
    7384    return APR_SUCCESS;
    7485}
     
    124135    }
    125136
     137    /* Initialize default priority setting */
     138    ret = mgs_default_priority_init();
     139    if (ret < 0)
     140    {
     141        ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, plog,
     142                      "gnutls_priority_init failed for default '%s': %s (%d)",
     143                      MGS_DEFAULT_PRIORITY, gnutls_strerror(ret), ret);
     144        return DONE;
     145    }
     146
    126147    AP_OPTIONAL_HOOK(status_hook, mgs_status_hook, NULL, NULL, APR_HOOK_MIDDLE);
    127148
    128149    ap_mutex_register(pconf, MGS_CACHE_MUTEX_NAME, NULL, APR_LOCK_DEFAULT, 0);
    129150    ap_mutex_register(pconf, MGS_OCSP_MUTEX_NAME, NULL, APR_LOCK_DEFAULT, 0);
     151    ap_mutex_register(pconf, MGS_OCSP_CACHE_MUTEX_NAME, NULL,
     152                      APR_LOCK_DEFAULT, 0);
    130153
    131154    /* Register a pool clean-up function */
     
    153176    const apr_array_header_t *pupgrades = NULL;
    154177    apr_status_t ret =
    155         ap_get_protocol_upgrades(ctxt->c, NULL, ctxt->c->base_server,
     178        ap_get_protocol_upgrades(ctxt->c, NULL, ctxt->sc->s,
    156179                                 /*report_all*/ 0, &pupgrades);
    157180    if (ret != APR_SUCCESS)
     
    170193    }
    171194
    172     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctxt->c,
     195    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctxt->c,
    173196                  "%s: Found %d protocol upgrade(s) for ALPN: %s",
    174197                  __func__, pupgrades->nelts,
    175198                  apr_array_pstrcat(ctxt->c->pool, pupgrades, ','));
    176199    gnutls_datum_t *alpn_protos =
    177         apr_palloc(ctxt->c->pool,
    178                    (pupgrades->nelts + 1) * sizeof(gnutls_datum_t));
    179     for (int i = 0; i < pupgrades->nelts; i++)
    180     {
    181         alpn_protos[i].data = (void *) APR_ARRAY_IDX(pupgrades, i, char *);
    182         alpn_protos[i].size =
    183             strnlen(APR_ARRAY_IDX(pupgrades, i, char *),
    184                     pupgrades->elt_size);
    185     }
     200        mgs_str_array_to_datum_array(pupgrades,
     201                                     ctxt->c->pool,
     202                                     pupgrades->nelts + 1);
    186203
    187204    /* Add the current (default) protocol at the end of the list */
     
    224241        apr_pstrndup(ctxt->c->pool, (char*) alpn_proto.data, alpn_proto.size);
    225242    const char *selected =
    226         ap_select_protocol(ctxt->c, NULL, ctxt->c->base_server,
    227                            client_protos);
     243        ap_select_protocol(ctxt->c, NULL, ctxt->sc->s, client_protos);
    228244
    229245    /* ap_select_protocol() will return NULL if none of the ALPN
     
    258274                  __func__, selected);
    259275    apr_status_t status = ap_switch_protocol(ctxt->c, NULL,
    260                                              ctxt->c->base_server,
     276                                             ctxt->sc->s,
    261277                                             selected);
    262278    if (status != APR_SUCCESS)
     
    274290
    275291/**
    276  * Post client hello function for GnuTLS, used to configure the TLS
    277  * server based on virtual host configuration. Uses SNI to select the
    278  * virtual host if available.
     292 * (Re-)Load credentials and priorities for the connection. This is
     293 * meant to be called after virtual host selection in the pre or post
     294 * client hello hook.
     295 */
     296static int reload_session_credentials(mgs_handle_t *ctxt)
     297{
     298    int ret = 0;
     299
     300    gnutls_certificate_server_set_request(ctxt->session,
     301                                          ctxt->sc->client_verify_mode);
     302
     303    /* Set x509 credentials */
     304    gnutls_credentials_set(ctxt->session,
     305                           GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
     306    /* Set Anon credentials */
     307    gnutls_credentials_set(ctxt->session, GNUTLS_CRD_ANON,
     308                           ctxt->sc->anon_creds);
     309
     310#ifdef ENABLE_SRP
     311        /* Set SRP credentials */
     312    if (ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) {
     313        gnutls_credentials_set(ctxt->session, GNUTLS_CRD_SRP,
     314                               ctxt->sc->srp_creds);
     315    }
     316#endif
     317
     318    /* Enable session tickets */
     319    if (session_ticket_key.data != NULL &&
     320        ctxt->sc->tickets == GNUTLS_ENABLED_TRUE)
     321    {
     322        ret = gnutls_session_ticket_enable_server(ctxt->session, &session_ticket_key);
     323        if (ret != GNUTLS_E_SUCCESS)
     324            ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, ctxt->c,
     325                          "gnutls_session_ticket_enable_server failed: %s (%d)",
     326                          gnutls_strerror(ret), ret);
     327    }
     328
     329    /* Update the priorities - to avoid negotiating a ciphersuite that is not
     330     * enabled on this virtual server. Note that here we ignore the version
     331     * negotiation. */
     332    ret = gnutls_priority_set(ctxt->session, ctxt->sc->priorities);
     333
     334    return ret;
     335}
     336
     337
     338
     339/**
     340 * Post client hello hook function for GnuTLS. This function has two
     341 * purposes: Firstly, it acts as a fallback for early_sni_hook(), by
     342 * parsing SNI and selecting a virtual host based on it if
     343 * necessary. Secondly, it calls ALPN processing.
    279344 *
    280345 * @param session the TLS session
     
    283348 * definition
    284349 */
    285 static int mgs_select_virtual_server_cb(gnutls_session_t session)
     350static int post_client_hello_hook(gnutls_session_t session)
    286351{
    287352    int ret = 0;
    288353    mgs_handle_t *ctxt = gnutls_session_get_ptr(session);
    289354
    290     /* try to find a virtual host */
    291     mgs_srvconf_rec *tsc = mgs_find_sni_server(session);
    292     if (tsc != NULL)
    293     {
    294         /* Found a TLS vhost based on the SNI, configure the
    295          * connection context. */
    296         ctxt->sc = tsc;
    297         }
    298 
    299     gnutls_certificate_server_set_request(session, ctxt->sc->client_verify_mode);
    300 
    301     /* Set x509 credentials */
    302     gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
    303     /* Set Anon credentials */
    304     gnutls_credentials_set(session, GNUTLS_CRD_ANON, ctxt->sc->anon_creds);
    305 
    306 #ifdef ENABLE_SRP
    307         /* Set SRP credentials */
    308     if (ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) {
    309         gnutls_credentials_set(session, GNUTLS_CRD_SRP, ctxt->sc->srp_creds);
    310     }
    311 #endif
     355    /* If ctxt->sni_name is set at this point the early_sni_hook()
     356     * function ran, found an SNI server name, selected a virtual
     357     * host, and set up credentials, so we don't need to do that
     358     * again. Otherwise try again, to cover GnuTLS versions < 3.6.3
     359     * and pick up future extensions to gnutls_server_name_get(). */
     360    if (ctxt->sni_name == NULL)
     361    {
     362        /* try to find a virtual host */
     363        mgs_srvconf_rec *tsc = mgs_find_sni_server(ctxt);
     364        if (tsc != NULL)
     365        {
     366            /* Found a TLS vhost based on the SNI, configure the
     367             * connection context. */
     368            ctxt->sc = tsc;
     369        }
     370
     371        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
     372                      "%s: Loading credentials in post client hello hook",
     373                      __func__);
     374        reload_session_credentials(ctxt);
     375    }
    312376
    313377    ret = process_alpn_result(ctxt);
    314378    if (ret != GNUTLS_E_SUCCESS)
    315379        return ret;
    316 
    317     /* Update the priorities - to avoid negotiating a ciphersuite that is not
    318      * enabled on this virtual server. Note that here we ignore the version
    319      * negotiation. */
    320     ret = gnutls_priority_set(session, ctxt->sc->priorities);
    321380
    322381    /* actually it shouldn't fail since we have checked at startup */
     
    350409        *privkey = ctxt->sc->privkey_x509;
    351410        return 0;
    352     } else if (gnutls_certificate_type_get(session) == GNUTLS_CRT_OPENPGP) {
    353                 // OPENPGP CERTIFICATE
    354         *pcerts = ctxt->sc->cert_pgp;
    355         *pcert_length = 1;
    356         *privkey = ctxt->sc->privkey_pgp;
    357         return 0;
    358411    } else {
    359412                // UNKNOWN CERTIFICATE
    360413            return -1;
    361414        }
    362 }
    363 
    364 /* Read the common name or the alternative name of the certificate.
    365  * We only support a single name per certificate.
    366  *
    367  * Returns negative on error.
    368  */
    369 static int read_crt_cn(server_rec * s, apr_pool_t * p, gnutls_x509_crt_t cert, char **cert_cn) {
    370 
    371     int rv = 0;
    372     size_t data_len;
    373 
    374 
    375     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    376     *cert_cn = NULL;
    377 
    378     data_len = 0;
    379     rv = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, NULL, &data_len);
    380 
    381     if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
    382         *cert_cn = apr_palloc(p, data_len);
    383         rv = gnutls_x509_crt_get_dn_by_oid(cert,
    384                 GNUTLS_OID_X520_COMMON_NAME,
    385                 0, 0, *cert_cn,
    386                 &data_len);
    387     } else { /* No CN return subject alternative name */
    388         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
    389                 "No common name found in certificate for '%s:%d'. Looking for subject alternative name...",
    390                 s->server_hostname, s->port);
    391         rv = 0;
    392         /* read subject alternative name */
    393         for (int i = 0; !(rv < 0); i++)
    394         {
    395             data_len = 0;
    396             rv = gnutls_x509_crt_get_subject_alt_name(cert, i,
    397                     NULL,
    398                     &data_len,
    399                     NULL);
    400 
    401             if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER
    402                     && data_len > 1) {
    403                 /* FIXME: not very efficient. What if we have several alt names
    404                  * before DNSName?
    405                  */
    406                 *cert_cn = apr_palloc(p, data_len + 1);
    407 
    408                 rv = gnutls_x509_crt_get_subject_alt_name
    409                         (cert, i, *cert_cn, &data_len, NULL);
    410                 (*cert_cn)[data_len] = 0;
    411 
    412                 if (rv == GNUTLS_SAN_DNSNAME)
    413                     break;
    414             }
    415         }
    416     }
    417 
    418     return rv;
    419 }
    420 
    421 static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p,
    422         gnutls_openpgp_crt_t cert, char **cert_cn) {
    423     int rv = 0;
    424     size_t data_len;
    425 
    426 
    427     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    428     *cert_cn = NULL;
    429 
    430     data_len = 0;
    431     rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len);
    432 
    433     if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
    434         *cert_cn = apr_palloc(p, data_len);
    435         rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn,
    436                 &data_len);
    437     } else { /* No CN return subject alternative name */
    438         ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
    439                 "No name found in PGP certificate for '%s:%d'.",
    440                 s->server_hostname, s->port);
    441     }
    442 
    443     return rv;
    444415}
    445416
     
    607578
    608579
    609     rv = mgs_cache_post_config(pconf, s, sc_base);
     580    rv = mgs_cache_post_config(pconf, ptemp, s, sc_base);
    610581    if (rv != APR_SUCCESS)
    611582    {
     
    644615                rv = gnutls_pkcs11_add_provider(p11_module, NULL);
    645616                if (rv != GNUTLS_E_SUCCESS)
    646                     ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     617                    ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EGENERAL, s,
    647618                                 "GnuTLS: Loading PKCS #11 provider module %s "
    648619                                 "failed: %s (%d).",
    649620                                 p11_module, gnutls_strerror(rv), rv);
     621                else
     622                    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
     623                                 "%s: PKCS #11 provider module %s loaded.",
     624                                 __func__, p11_module);
    650625            }
    651626        }
    652627    }
    653628
     629    sc_base->singleton_wd =
     630        mgs_new_singleton_watchdog(base_server, MGS_SINGLETON_WATCHDOG, pconf);
     631
    654632    for (s = base_server; s; s = s->next)
    655633    {
    656634        sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
    657         sc->cache_type = sc_base->cache_type;
    658         sc->cache_config = sc_base->cache_config;
    659         sc->cache_timeout = sc_base->cache_timeout;
     635        sc->s = s;
     636        sc->cache_enable = sc_base->cache_enable;
    660637        sc->cache = sc_base->cache;
    661 
    662         rv = mgs_load_files(pconf, ptemp, s);
    663         if (rv != 0) {
    664             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    665                 "GnuTLS: Loading required files failed."
    666                 " Shutting Down.");
    667             return HTTP_NOT_FOUND;
    668         }
    669 
    670         if (sc->ocsp_staple == GNUTLS_ENABLED_UNSET)
    671             sc->ocsp_staple = GNUTLS_ENABLED_FALSE;
    672 
    673         sc->ocsp_mutex = sc_base->ocsp_mutex;
    674         /* init OCSP configuration if OCSP is enabled for this host */
    675         if (sc->ocsp_staple)
    676         {
    677             rv = mgs_ocsp_post_config_server(pconf, ptemp, s);
    678             if (rv != OK && rv != DECLINED)
    679                 return rv;
    680         }
     638        if (sc->cache_timeout == MGS_TIMEOUT_UNSET)
     639            sc->cache_timeout = sc_base->cache_timeout;
     640        sc->ocsp_cache = sc_base->ocsp_cache;
     641
     642        sc->singleton_wd = sc_base->singleton_wd;
    681643
    682644        /* defaults for unset values: */
     
    684646            sc->enabled = GNUTLS_ENABLED_FALSE;
    685647        if (sc->tickets == GNUTLS_ENABLED_UNSET)
    686             sc->tickets = GNUTLS_ENABLED_FALSE;
     648        {
     649            /* GnuTLS 3.6.4 introduced automatic master key rotation */
     650            if (gnutls_check_version_numeric(3, 6, 4))
     651                sc->tickets = GNUTLS_ENABLED_TRUE;
     652            else
     653                sc->tickets = GNUTLS_ENABLED_FALSE;
     654        }
    687655        if (sc->export_certificates_size < 0)
    688656            sc->export_certificates_size = 0;
     
    692660            sc->client_verify_method = mgs_cvm_cartel;
    693661
     662        // TODO: None of the stuff below needs to be done if
     663        // sc->enabled == GNUTLS_ENABLED_FALSE, we could just continue
     664        // to the next host.
     665
     666        /* Load certificates and stuff (includes parsing priority) */
     667        rv = mgs_load_files(pconf, ptemp, s);
     668        if (rv != 0) {
     669            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     670                         "%s: Loading credentials failed!", __func__);
     671            return HTTP_NOT_FOUND;
     672        }
     673
     674        sc->ocsp_mutex = sc_base->ocsp_mutex;
     675        /* init OCSP configuration unless explicitly disabled */
     676        if (sc->enabled && sc->ocsp_staple != GNUTLS_ENABLED_FALSE)
     677        {
     678            const char *err = mgs_ocsp_configure_stapling(pconf, ptemp, s);
     679            if (err != NULL)
     680            {
     681                /* If OCSP stapling is enabled only by default ignore
     682                 * error and disable stapling */
     683                if (sc->ocsp_staple == GNUTLS_ENABLED_UNSET)
     684                {
     685                    ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, s,
     686                                 "Cannnot enable OCSP stapling for "
     687                                 "host '%s:%d': %s",
     688                                 s->server_hostname, s->addrs->host_port, err);
     689                    sc->ocsp_staple = GNUTLS_ENABLED_FALSE;
     690                }
     691                /* If OCSP stapling is explicitly enabled this is a
     692                 * critical error. */
     693                else
     694                {
     695                    ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EINVAL, s,
     696                                 "OCSP stapling configuration failed for "
     697                                 "host '%s:%d': %s",
     698                                 s->server_hostname, s->addrs->host_port, err);
     699                    return HTTP_INTERNAL_SERVER_ERROR;
     700                }
     701            }
     702            else
     703            {
     704                /* Might already be set */
     705                sc->ocsp_staple = GNUTLS_ENABLED_TRUE;
     706                /* Set up stapling */
     707                rv = mgs_ocsp_enable_stapling(pconf, ptemp, s);
     708                if (rv != OK && rv != DECLINED)
     709                    return rv;
     710            }
     711        }
     712
    694713        /* Check if the priorities have been set */
    695714        if (sc->priorities == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
    696             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    697                     "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!",
    698                     s->server_hostname, s->port);
    699             return HTTP_NOT_ACCEPTABLE;
     715            ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
     716                         "No GnuTLSPriorities directive for host '%s:%d', "
     717                         "using default '%s'.",
     718                         s->server_hostname, s->addrs->host_port,
     719                         MGS_DEFAULT_PRIORITY);
     720            sc->priorities = mgs_get_default_prio();
    700721        }
    701722
     
    726747
    727748        if ((sc->certs_x509_chain == NULL || sc->certs_x509_chain_num < 1) &&
    728             sc->cert_pgp == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
     749            sc->enabled == GNUTLS_ENABLED_TRUE) {
    729750                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    730751                                                "GnuTLS: Host '%s:%d' is missing a Certificate File!",
    731                                                 s->server_hostname, s->port);
     752                                                s->server_hostname, s->addrs->host_port);
    732753            return HTTP_UNAUTHORIZED;
    733754        }
    734755        if (sc->enabled == GNUTLS_ENABLED_TRUE &&
    735             ((sc->certs_x509_chain_num > 0 && sc->privkey_x509 == NULL) ||
    736              (sc->cert_crt_pgp != NULL && sc->privkey_pgp == NULL)))
     756            (sc->certs_x509_chain_num > 0 && sc->privkey_x509 == NULL))
    737757        {
    738758                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    739759                                                "GnuTLS: Host '%s:%d' is missing a Private Key File!",
    740                                                 s->server_hostname, s->port);
     760                                                s->server_hostname, s->addrs->host_port);
    741761            return HTTP_UNAUTHORIZED;
    742         }
    743 
    744         /* If OpenPGP support is already disabled in the loaded GnuTLS
    745          * library startup will fail if the configuration tries to
    746          * load PGP credentials. Otherwise warn affected users about
    747          * deprecation. */
    748         if (sc->pgp_cert_file || sc->pgp_key_file || sc->pgp_ring_file)
    749             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
    750                          "Host '%s:%d' is configured to use OpenPGP auth. "
    751                          "OpenPGP support has been deprecated in GnuTLS "
    752                          "since version 3.5.9 and will be removed from "
    753                          "mod_gnutls in a future release.",
    754                          s->server_hostname, s->port);
    755 
    756         if (sc->enabled == GNUTLS_ENABLED_TRUE) {
    757             rv = -1;
    758             if (sc->certs_x509_chain_num > 0) {
    759                 rv = read_crt_cn(s, pconf, sc->certs_x509_crt_chain[0], &sc->cert_cn);
    760             }
    761             if (rv < 0 && sc->cert_pgp != NULL) {
    762                 rv = read_pgpcrt_cn(s, pconf, sc->cert_crt_pgp[0], &sc->cert_cn);
    763                         }
    764 
    765             if (rv < 0) {
    766                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    767                                                         "GnuTLS: Cannot find a certificate for host '%s:%d'!",
    768                                                         s->server_hostname, s->port);
    769                 sc->cert_cn = NULL;
    770                 continue;
    771             }
    772762        }
    773763
     
    779769                         "%s: loading proxy credentials for host "
    780770                         "'%s:%d' failed, exiting!",
    781                          __func__, s->server_hostname, s->port);
     771                         __func__, s->server_hostname, s->addrs->host_port);
    782772            return HTTP_PROXY_AUTHENTICATION_REQUIRED;
    783773        }
     
    816806    }
    817807
    818     if (sc->cache_type != mgs_cache_none) {
    819         rv = mgs_cache_child_init(p, s, sc);
    820         if (rv != APR_SUCCESS) {
     808    if (sc->cache_enable == GNUTLS_ENABLED_TRUE)
     809    {
     810        rv = mgs_cache_child_init(p, s, sc->cache, MGS_CACHE_MUTEX_NAME);
     811        if (rv != APR_SUCCESS)
    821812            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
    822                     "GnuTLS: Failed to run Cache Init");
    823         }
    824     }
    825 
    826     /* reinit OCSP mutex */
     813                    "Child init for session cache failed!");
     814    }
     815
     816    if (sc->ocsp_cache != NULL)
     817    {
     818        rv = mgs_cache_child_init(p, s, sc->ocsp_cache,
     819                                  MGS_OCSP_CACHE_MUTEX_NAME);
     820        if (rv != APR_SUCCESS)
     821            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
     822                    "Child init for OCSP cache failed!");
     823    }
     824
     825    /* reinit OCSP request mutex */
    827826    const char *lockfile = apr_global_mutex_lockfile(sc->ocsp_mutex);
    828827    rv = apr_global_mutex_child_init(&sc->ocsp_mutex, lockfile, p);
     
    876875}
    877876
    878 /**
    879  * Default buffer size for SNI data, including the terminating NULL
    880  * byte. The size matches what gnutls-cli uses initially.
    881  */
    882 #define DEFAULT_SNI_HOST_LEN 256
     877
    883878
    884879typedef struct {
     
    900895int check_server_aliases(vhost_cb_rec *x, server_rec * s, mgs_srvconf_rec *tsc)
    901896{
    902         apr_array_header_t *names;
    903         int rv = 0;
    904         char ** name;
    905 
    906         /* Check ServerName First! */
    907         if(apr_strnatcasecmp(x->sni_name, s->server_hostname) == 0) {
    908                 // We have a match, save this server configuration
    909                 x->sc = tsc;
    910                 rv = 1;
    911         /* Check any ServerAlias directives */
    912         } else if(s->names->nelts) {
    913                 names = s->names;
    914                 name = (char **)names->elts;
    915                 for (int i = 0; i < names->nelts; ++i)
     897    apr_array_header_t *names;
     898    int rv = 0;
     899    char ** name;
     900
     901    /* Check ServerName First! */
     902    if (strcasecmp(x->sni_name, s->server_hostname) == 0) {
     903        // We have a match, save this server configuration
     904        x->sc = tsc;
     905        rv = 1;
     906        /* Check any ServerAlias directives */
     907    } else if(s->names->nelts) {
     908        names = s->names;
     909        name = (char **) names->elts;
     910        for (int i = 0; i < names->nelts; ++i)
    916911        {
    917                         if (!name[i]) { continue; }
    918                                 if (apr_strnatcasecmp(x->sni_name, name[i]) == 0) {
    919                                         // We have a match, save this server configuration
    920                                         x->sc = tsc;
    921                                         rv = 1;
    922                         }
    923                 }
    924         /* Wild any ServerAlias Directives */
    925         } else if(s->wild_names->nelts) {
    926                 names = s->wild_names;
    927         name = (char **)names->elts;
    928                 for (int i = 0; i < names->nelts; ++i)
     912            if (!name[i])
     913                continue;
     914            if (strcasecmp(x->sni_name, name[i]) == 0)
     915            {
     916                // We have a match, save this server configuration
     917                x->sc = tsc;
     918                rv = 1;
     919            }
     920        }
     921        /* ServerAlias directives may contain wildcards, check those last. */
     922    } else if(s->wild_names->nelts) {
     923        names = s->wild_names;
     924        name = (char **) names->elts;
     925        for (int i = 0; i < names->nelts; ++i)
    929926        {
    930                         if (!name[i]) { continue; }
    931                                 if(apr_fnmatch(name[i], x->sni_name ,
    932                                                                 APR_FNM_CASE_BLIND|
    933                                                                 APR_FNM_PERIOD|
    934                                                                 APR_FNM_PATHNAME|
    935                                                                 APR_FNM_NOESCAPE) == APR_SUCCESS) {
    936                                 x->sc = tsc;
    937                                 rv = 1;
    938                         }
    939                 }
    940         }
    941         return rv;
     927            if (!name[i])
     928                continue;
     929            if (ap_strcasecmp_match(x->sni_name, name[i]) == 0)
     930            {
     931                x->sc = tsc;
     932                rv = 1;
     933            }
     934        }
     935    }
     936    return rv;
    942937}
    943938
     
    952947            &gnutls_module);
    953948
    954     if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) {
     949    if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
    955950        return 0;
    956951    }
     
    978973 * hello function.
    979974 *
    980  * @param session the GnuTLS session
     975 * @param ctxt the mod_gnutls connection handle
    981976 *
    982977 * @return either the matching mod_gnutls server config, or `NULL`
    983978 */
    984 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
     979mgs_srvconf_rec *mgs_find_sni_server(mgs_handle_t *ctxt)
    985980{
    986     mgs_handle_t *ctxt = gnutls_session_get_ptr(session);
    987 
    988     char *sni_name = apr_palloc(ctxt->c->pool, DEFAULT_SNI_HOST_LEN);
    989     size_t sni_len = DEFAULT_SNI_HOST_LEN;
    990     unsigned int sni_type;
    991 
    992     /* Search for a DNS SNI element. Note that RFC 6066 prohibits more
    993      * than one server name per type. */
    994     int sni_index = -1;
    995     int rv = 0;
    996     do {
    997         /* The sni_index is incremented before each use, so if the
    998          * loop terminates with a type match we will have the right
    999          * one stored. */
    1000         rv = gnutls_server_name_get(session, sni_name,
    1001                                     &sni_len, &sni_type, ++sni_index);
    1002         if (rv == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
    1003         {
    1004             ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_EGENERAL, ctxt->c,
    1005                           "%s: no DNS SNI found (last index: %d).",
    1006                           __func__, sni_index);
     981    if (ctxt->sni_name == NULL)
     982    {
     983        const char *sni_name = mgs_server_name_get(ctxt);
     984        if (sni_name != NULL)
     985            ctxt->sni_name = sni_name;
     986        else
    1007987            return NULL;
    1008         }
    1009     } while (sni_type != GNUTLS_NAME_DNS);
    1010     /* The (rv == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) path inside
    1011      * the loop above returns, so if we reach this point we have a DNS
    1012      * SNI at the current index. */
    1013 
    1014     if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER)
    1015     {
    1016         /* Allocate a new buffer of the right size and retry */
    1017         sni_name = apr_palloc(ctxt->c->pool, sni_len);
    1018         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
    1019                       "%s: reallocated SNI data buffer for %" APR_SIZE_T_FMT
    1020                       " bytes.", __func__, sni_len);
    1021         rv = gnutls_server_name_get(session, sni_name,
    1022                                     &sni_len, &sni_type, sni_index);
    1023     }
    1024 
    1025     /* Unless there's a bug in the GnuTLS API only GNUTLS_E_IDNA_ERROR
    1026      * can occur here, but a catch all is safer and no more
    1027      * complicated. */
    1028     if (rv != GNUTLS_E_SUCCESS)
    1029     {
    1030         ap_log_cerror(APLOG_MARK, APLOG_INFO, APR_EGENERAL, ctxt->c,
    1031                       "%s: error while getting SNI DNS data: '%s' (%d).",
    1032                       __func__, gnutls_strerror(rv), rv);
    1033         return NULL;
    1034988    }
    1035989
    1036990    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
    1037991                  "%s: client requested server '%s'.",
    1038                   __func__, sni_name);
     992                  __func__, ctxt->sni_name);
    1039993
    1040994    /* Search for vhosts matching connection parameters and the
     
    1044998        .ctxt = ctxt,
    1045999        .sc = NULL,
    1046         .sni_name = sni_name
     1000        .sni_name = ctxt->sni_name
    10471001    };
    1048     rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
     1002    int rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
    10491003    if (rv == 1) {
    10501004        return cbx.sc;
     
    10521006    return NULL;
    10531007}
     1008
     1009
     1010
     1011#ifdef ENABLE_EARLY_SNI
     1012/**
     1013 * Pre client hello hook function for GnuTLS that implements early SNI
     1014 * processing using `gnutls_ext_raw_parse()` (available since GnuTLS
     1015 * 3.6.3). Reading the SNI (if any) before GnuTLS processes the client
     1016 * hello allows loading virtual host settings that cannot be changed
     1017 * in the post client hello hook, including ALPN proposals (required
     1018 * for HTTP/2 support using the `Protocols` directive). In addition to
     1019 * ALPN this function configures the server credentials.
     1020 *
     1021 * The function signature is required by the GnuTLS API.
     1022 *
     1023 * @param session the current session
     1024 * @param htype handshake message type
     1025 * @param when hook position relative to GnuTLS processing
     1026 * @param incoming true if the message is incoming, for client hello
     1027 * that means the hook is running on the server
     1028 * @param msg raw message data
     1029 *
     1030 * @return `GNUTLS_E_SUCCESS` or a GnuTLS error code
     1031 */
     1032static int early_sni_hook(gnutls_session_t session,
     1033                          unsigned int htype,
     1034                          unsigned when,
     1035                          unsigned int incoming,
     1036                          const gnutls_datum_t *msg)
     1037{
     1038    if (!incoming)
     1039        return 0;
     1040
     1041    mgs_handle_t *ctxt = (mgs_handle_t *) gnutls_session_get_ptr(session);
     1042
     1043    /* This is a hook for pre client hello ONLY! */
     1044    if (htype != GNUTLS_HANDSHAKE_CLIENT_HELLO || when != GNUTLS_HOOK_PRE)
     1045    {
     1046        ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EINVAL, ctxt->c,
     1047                      "%s called outside pre client hello hook, this "
     1048                      "indicates a programming error!",
     1049                      __func__);
     1050        return GNUTLS_E_SELF_TEST_ERROR;
     1051    }
     1052
     1053    int ret = gnutls_ext_raw_parse(session, mgs_sni_ext_hook, msg,
     1054                                   GNUTLS_EXT_RAW_FLAG_TLS_CLIENT_HELLO);
     1055    if (ret == 0 && ctxt->sni_name != NULL)
     1056    {
     1057        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
     1058                      "%s found SNI name: '%s'",
     1059                      __func__, ctxt->sni_name);
     1060
     1061        /* try to find a virtual host for that name */
     1062        mgs_srvconf_rec *tsc = mgs_find_sni_server(ctxt);
     1063        if (tsc != NULL)
     1064        {
     1065            /* Found a TLS vhost based on the SNI, configure the
     1066             * connection context. */
     1067            ctxt->sc = tsc;
     1068            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ctxt->c,
     1069                          "%s: Selected virtual host %s from early SNI, "
     1070                          "connection server is %s.",
     1071                          __func__, ctxt->sc->s->server_hostname,
     1072                          ctxt->c->base_server->server_hostname);
     1073        }
     1074    }
     1075
     1076    reload_session_credentials(ctxt);
     1077
     1078    prepare_alpn_proposals(ctxt);
     1079
     1080    return ret;
     1081}
     1082#endif
     1083
     1084
    10541085
    10551086/**
     
    11321163                          "gnutls_init for server side failed: %s (%d)",
    11331164                          gnutls_strerror(err), err);
    1134         /* Initialize Session Tickets */
    1135         if (session_ticket_key.data != NULL &&
    1136             ctxt->sc->tickets == GNUTLS_ENABLED_TRUE)
    1137         {
    1138             err = gnutls_session_ticket_enable_server(ctxt->session, &session_ticket_key);
    1139             if (err != GNUTLS_E_SUCCESS)
    1140                 ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
    1141                               "gnutls_session_ticket_enable_server failed: %s (%d)",
    1142                               gnutls_strerror(err), err);
    1143         }
    11441165    }
    11451166
     
    11491170
    11501171    /* Set Default Priority */
    1151         err = gnutls_priority_set_direct(ctxt->session, "NORMAL", NULL);
     1172        err = gnutls_priority_set(ctxt->session, mgs_get_default_prio());
    11521173    if (err != GNUTLS_E_SUCCESS)
    1153         ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c, "gnutls_priority_set_direct failed!");
    1154     /* Set Handshake function */
     1174        ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
     1175                      "gnutls_priority_set failed!");
     1176
     1177#ifdef ENABLE_EARLY_SNI
     1178    /* Pre-handshake hook, EXPERIMENTAL */
     1179    gnutls_handshake_set_hook_function(ctxt->session,
     1180                                       GNUTLS_HANDSHAKE_CLIENT_HELLO,
     1181                                       GNUTLS_HOOK_PRE, early_sni_hook);
     1182#else
     1183    prepare_alpn_proposals(ctxt);
     1184#endif
     1185
     1186    /* Post client hello hook (called after GnuTLS has parsed it) */
    11551187    gnutls_handshake_set_post_client_hello_function(ctxt->session,
    1156             mgs_select_virtual_server_cb);
     1188            post_client_hello_hook);
    11571189
    11581190    /* Set GnuTLS user pointer, so we can access the module session
     
    11601192    gnutls_session_set_ptr(ctxt->session, ctxt);
    11611193
    1162     /* If mod_gnutls is the TLS server, mgs_select_virtual_server_cb
    1163      * will load appropriate credentials during handshake. However,
     1194    /* If mod_gnutls is the TLS server, early_sni_hook (or
     1195     * post_client_hello_hook, if early SNI is not available) will
     1196     * load appropriate credentials during the handshake. However,
    11641197     * when handling a proxy backend connection, mod_gnutls acts as
    11651198     * TLS client and credentials must be loaded here. */
     
    11811214    }
    11821215
    1183     prepare_alpn_proposals(ctxt);
    1184 
    11851216    /* Initialize Session Cache */
    11861217    mgs_cache_session_init(ctxt);
     
    12551286
    12561287
     1288/* Post request hook, checks if TLS connection and vhost match */
     1289int mgs_req_vhost_check(request_rec *r)
     1290{
     1291    /* mod_gnutls server record for the request vhost */
     1292    mgs_srvconf_rec *r_sc = (mgs_srvconf_rec *)
     1293        ap_get_module_config(r->server->module_config, &gnutls_module);
     1294    mgs_handle_t *ctxt = get_effective_gnutls_ctxt(r->connection);
     1295
     1296    /* Nothing to check for non-TLS and outgoing proxy connections */
     1297    if (ctxt == NULL || !ctxt->enabled || ctxt->is_proxy)
     1298        return DECLINED;
     1299
     1300    if (ctxt->sc != r_sc)
     1301    {
     1302        ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, ctxt->c,
     1303                      "%s: Mismatch between handshake and request servers!",
     1304                      __func__);
     1305        return HTTP_MISDIRECTED_REQUEST;
     1306    }
     1307
     1308    if (!ctxt->sni_name)
     1309        return DECLINED;
     1310
     1311    /* Got an SNI name, so verify it matches. */
     1312    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
     1313                  "%s: Checking request hostname against SNI name '%s'.",
     1314                  __func__, ctxt->sni_name);
     1315
     1316    if (!r->hostname)
     1317    {
     1318        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, r->connection,
     1319                      "Client requested '%s' via SNI, but provided "
     1320                      "no hostname in HTTP request!", ctxt->sni_name);
     1321        return HTTP_MISDIRECTED_REQUEST;
     1322    }
     1323
     1324    if (strcasecmp(r->hostname, ctxt->sni_name) != 0)
     1325    {
     1326        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, r->connection,
     1327                      "Client requested '%s' via SNI, but '%s' in "
     1328                      "the HTTP request!", ctxt->sni_name, r->hostname);
     1329        return HTTP_MISDIRECTED_REQUEST;
     1330    }
     1331
     1332    return DECLINED;
     1333}
     1334
     1335
     1336
    12571337int mgs_hook_fixups(request_rec * r) {
    12581338    unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
     
    12921372                                         gnutls_mac_get(ctxt->session)));
    12931373
     1374#if GNUTLS_VERSION_NUMBER >= 0x030600
     1375    /* Compression support has been removed since GnuTLS 3.6.0 */
     1376    apr_table_setn(env, "SSL_COMPRESS_METHOD", "NULL");
     1377#else
    12941378    apr_table_setn(env, "SSL_COMPRESS_METHOD",
    12951379            gnutls_compression_get_name(gnutls_compression_get(ctxt->session)));
     1380#endif
    12961381
    12971382#ifdef ENABLE_SRP
     
    13291414
    13301415    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
    1331         mgs_add_common_cert_vars(r, ctxt->sc->certs_x509_crt_chain[0], 0, ctxt->sc->export_certificates_size);
    1332     } else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP) {
    1333         mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_crt_pgp[0], 0, ctxt->sc->export_certificates_size);
     1416        mgs_add_common_cert_vars(r, ctxt->sc->certs_x509_crt_chain[0], 0,
     1417                                 ctxt->sc->export_certificates_size);
    13341418    }
    13351419
     
    15261610
    15271611
    1528 /* @param side 0: server, 1: client
    1529  *
    1530  * @param export_cert_size (int) maximum size for environment variable
    1531  * to use for the PEM-encoded certificate (0 means do not export)
    1532  */
    1533 static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, size_t export_cert_size) {
    1534 
    1535         unsigned char sbuf[64]; /* buffer to hold serials */
    1536     char buf[AP_IOBUFSIZE];
    1537     const char *tmp;
    1538     size_t len;
    1539     int ret;
    1540 
    1541     if (r == NULL)
    1542         return;
    1543 
    1544     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    1545     apr_table_t *env = r->subprocess_env;
    1546 
    1547     if (export_cert_size > 0) {
    1548         len = 0;
    1549         ret = gnutls_openpgp_crt_export(cert, GNUTLS_OPENPGP_FMT_BASE64, NULL, &len);
    1550         if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
    1551             if (len >= export_cert_size) {
    1552                 apr_table_setn(env, MGS_SIDE("_CERT"),
    1553                                "GNUTLS_CERTIFICATE_SIZE_LIMIT_EXCEEDED");
    1554                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1555                               "GnuTLS: Failed to export too-large OpenPGP certificate to environment");
    1556             } else {
    1557                 char* cert_buf = apr_palloc(r->pool, len + 1);
    1558                 if (cert_buf != NULL && gnutls_openpgp_crt_export(cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0) {
    1559                     cert_buf[len] = 0;
    1560                     apr_table_setn(env, MGS_SIDE("_CERT"), cert_buf);
    1561                 } else {
    1562                     ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
    1563                                   "GnuTLS: failed to export OpenPGP certificate");
    1564                 }
    1565             }
    1566         } else {
    1567             ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
    1568                           "GnuTLS: dazed and confused about OpenPGP certificate size");
    1569         }
    1570     }
    1571 
    1572     len = sizeof (buf);
    1573     gnutls_openpgp_crt_get_name(cert, 0, buf, &len);
    1574     apr_table_setn(env, MGS_SIDE("_NAME"), apr_pstrmemdup(r->pool, buf, len));
    1575 
    1576     len = sizeof (sbuf);
    1577     gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len);
    1578     apr_table_setn(env, MGS_SIDE("_FINGERPRINT"),
    1579                    apr_pescape_hex(r->pool, sbuf, len, 0));
    1580 
    1581     ret = gnutls_openpgp_crt_get_version(cert);
    1582     if (ret > 0)
    1583         apr_table_setn(env, MGS_SIDE("_M_VERSION"),
    1584                        apr_psprintf(r->pool, "%u", ret));
    1585 
    1586     apr_table_setn(env, MGS_SIDE("_CERT_TYPE"), "OPENPGP");
    1587 
    1588     tmp =
    1589             mgs_time2sz(gnutls_openpgp_crt_get_expiration_time
    1590             (cert), buf, sizeof (buf));
    1591     apr_table_setn(env, MGS_SIDE("_V_END"), apr_pstrdup(r->pool, tmp));
    1592 
    1593     tmp =
    1594             mgs_time2sz(gnutls_openpgp_crt_get_creation_time
    1595             (cert), buf, sizeof (buf));
    1596     apr_table_setn(env, MGS_SIDE("_V_START"), apr_pstrdup(r->pool, tmp));
    1597 
    1598     ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL);
    1599     if (ret >= 0) {
    1600         apr_table_setn(env, MGS_SIDE("_A_KEY"), gnutls_pk_algorithm_get_name(ret));
    1601     }
    1602 
    1603 }
    16041612
    16051613/* TODO: Allow client sending a X.509 certificate chain */
     
    16131621    unsigned int ch_size = 0;
    16141622
     1623    // TODO: union no longer needed here after removing its "pgp" component.
    16151624    union {
    16161625        gnutls_x509_crt_t x509[MAX_CHAIN_SIZE];
    1617         gnutls_openpgp_crt_t pgp;
    16181626    } cert;
    16191627    apr_time_t expiration_time, cur_time;
     
    16661674            }
    16671675        }
    1668     } else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP) {
    1669         if (cert_list_size > 1) {
    1670             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1671                     "GnuTLS: Failed to Verify Peer: "
    1672                     "Chained Client Certificates are not supported.");
    1673             return HTTP_FORBIDDEN;
    1674         }
    1675 
    1676         gnutls_openpgp_crt_init(&cert.pgp);
    1677         rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0],
    1678                 GNUTLS_OPENPGP_FMT_RAW);
    1679 
    16801676    } else
    16811677        return HTTP_FORBIDDEN;
     
    17531749
    17541750    } else {
    1755         apr_time_ansi_put(&expiration_time,
    1756                 gnutls_openpgp_crt_get_expiration_time
    1757                 (cert.pgp));
    1758 
    1759         switch(ctxt->sc->client_verify_method) {
    1760         case mgs_cvm_cartel:
    1761             rv = gnutls_openpgp_crt_verify_ring(cert.pgp,
    1762                                                 ctxt->sc->pgp_list, 0,
    1763                                                 &status);
    1764             break;
    1765 #ifdef ENABLE_MSVA
    1766         case mgs_cvm_msva:
    1767             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1768                           "GnuTLS:  OpenPGP verification via MSVA is not yet implemented");
    1769             rv = GNUTLS_E_UNIMPLEMENTED_FEATURE;
    1770             break;
    1771 #endif
    1772         default:
    1773             /* If this block is reached, that indicates a
    1774              * configuration error or bug in mod_gnutls (invalid value
    1775              * of ctxt->sc->client_verify_method). */
    1776             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1777                           "GnuTLS: Failed to Verify OpenPGP Peer: method '%s' is not supported",
    1778                           mgs_readable_cvm(ctxt->sc->client_verify_method));
    1779             rv = GNUTLS_E_UNIMPLEMENTED_FEATURE;
    1780         }
     1751        /* Unknown certificate type */
     1752        rv = GNUTLS_E_UNIMPLEMENTED_FEATURE;
    17811753    }
    17821754
     
    17891761        if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND)
    17901762            ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r,
    1791                 "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?");
     1763                "GnuTLS: No certificate was found for verification. Did you set the GnuTLSClientCAFile directive?");
    17921764        ret = HTTP_FORBIDDEN;
    17931765        goto exit;
     
    18301802    }
    18311803
    1832     if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509)
    1833         mgs_add_common_cert_vars(r, cert.x509[0], 1, ctxt->sc->export_certificates_size);
    1834     else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP)
    1835         mgs_add_common_pgpcert_vars(r, cert.pgp, 1, ctxt->sc->export_certificates_size);
     1804    mgs_add_common_cert_vars(r, cert.x509[0], 1, ctxt->sc->export_certificates_size);
    18361805
    18371806    {
     
    18611830        for (unsigned int i = 0; i < ch_size; i++)
    18621831            gnutls_x509_crt_deinit(cert.x509[i]);
    1863     else if (gnutls_certificate_type_get(ctxt->session) ==
    1864              GNUTLS_CRT_OPENPGP)
    1865         gnutls_openpgp_crt_deinit(cert.pgp);
     1832
    18661833    return ret;
    18671834}
     
    19221889 * certificate, but doesn't tell us (in any other way) who they are
    19231890 * trying to authenticate as.
    1924 
    1925  * TODO: we might need another parallel for OpenPGP, but for that it's
    1926  * much simpler: we can just assume that the first User ID marked as
    1927  * "primary" (or the first User ID, period) is the identity the user
    1928  * is trying to present as.
    19291891
    19301892 * one complaint might be "but the user wanted to be another identity,
     
    20972059        ap_rputs("</dl>\n", r);
    20982060
     2061    if (sc->ocsp_cache)
     2062        mgs_cache_status(sc->ocsp_cache, "GnuTLS OCSP Cache", r, flags);
     2063    if (sc->cache_enable)
     2064        mgs_cache_status(sc->cache, "GnuTLS Session Cache", r, flags);
     2065
    20992066    return OK;
    21002067}
    2101 
    2102 
    2103 
    2104 /*
    2105  * Callback to check the server certificate for proxy HTTPS
    2106  * connections, to be used with
    2107  * gnutls_certificate_set_verify_function.
    2108 
    2109  * Returns: 0 if certificate check was successful (certificate
    2110  * trusted), non-zero otherwise (error during check or untrusted
    2111  * certificate).
    2112  */
    2113 static int gtls_check_server_cert(gnutls_session_t session)
    2114 {
    2115     mgs_handle_t *ctxt = (mgs_handle_t *) gnutls_session_get_ptr(session);
    2116     unsigned int status;
    2117 
    2118     /* Get peer hostname from a note left by mod_proxy */
    2119     const char *peer_hostname =
    2120         apr_table_get(ctxt->c->notes, PROXY_SNI_NOTE);
    2121     if (peer_hostname == NULL)
    2122         ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, ctxt->c,
    2123                       "%s: " PROXY_SNI_NOTE " NULL, cannot check "
    2124                       "peer's hostname", __func__);
    2125 
    2126     /* Verify certificate, including hostname match. Should
    2127      * peer_hostname be NULL for some reason, the name is not
    2128      * checked. */
    2129     int err = gnutls_certificate_verify_peers3(session, peer_hostname,
    2130                                                &status);
    2131     if (err != GNUTLS_E_SUCCESS)
    2132     {
    2133         ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, ctxt->c,
    2134                       "%s: server certificate check failed: %s (%d)",
    2135                       __func__, gnutls_strerror(err), err);
    2136         return err;
    2137     }
    2138 
    2139     if (status == 0)
    2140         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctxt->c,
    2141                       "%s: server certificate is trusted.",
    2142                       __func__);
    2143     else
    2144     {
    2145         gnutls_datum_t out;
    2146         /* GNUTLS_CRT_X509: ATM, only X509 is supported for proxy
    2147          * certs 0: according to function API, the last argument
    2148          * should be 0 */
    2149         err = gnutls_certificate_verification_status_print(status,
    2150                                                            GNUTLS_CRT_X509,
    2151                                                            &out, 0);
    2152         if (err != GNUTLS_E_SUCCESS)
    2153             ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, ctxt->c,
    2154                           "%s: server verify print failed: %s (%d)",
    2155                           __func__, gnutls_strerror(err), err);
    2156         else
    2157             ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, ctxt->c,
    2158                           "%s: %s",
    2159                           __func__, out.data);
    2160         gnutls_free(out.data);
    2161     }
    2162 
    2163     return status;
    2164 }
    2165 
    2166 
    2167 
    2168 static apr_status_t cleanup_proxy_x509_credentials(void *arg)
    2169 {
    2170     mgs_srvconf_rec *sc = (mgs_srvconf_rec *) arg;
    2171 
    2172     if (sc->proxy_x509_creds)
    2173     {
    2174         /* This implicitly releases the associated trust list
    2175          * sc->proxy_x509_tl, too. */
    2176         gnutls_certificate_free_credentials(sc->proxy_x509_creds);
    2177         sc->proxy_x509_creds = NULL;
    2178         sc->proxy_x509_tl = NULL;
    2179     }
    2180 
    2181     if (sc->anon_client_creds)
    2182     {
    2183         gnutls_anon_free_client_credentials(sc->anon_client_creds);
    2184         sc->anon_client_creds = NULL;
    2185     }
    2186 
    2187     if (sc->proxy_priorities)
    2188     {
    2189         gnutls_priority_deinit(sc->proxy_priorities);
    2190         sc->proxy_priorities = NULL;
    2191     }
    2192 
    2193     return APR_SUCCESS;
    2194 }
    2195 
    2196 
    2197 
    2198 static apr_status_t load_proxy_x509_credentials(apr_pool_t *pconf,
    2199                                                 apr_pool_t *ptemp,
    2200                                                 server_rec *s)
    2201 {
    2202     mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
    2203         ap_get_module_config(s->module_config, &gnutls_module);
    2204 
    2205     if (sc == NULL)
    2206         return APR_EGENERAL;
    2207 
    2208     apr_status_t ret = APR_EINIT;
    2209     int err = GNUTLS_E_SUCCESS;
    2210 
    2211     /* Cleanup function for the GnuTLS structures allocated below */
    2212     apr_pool_cleanup_register(pconf, sc, cleanup_proxy_x509_credentials,
    2213                               apr_pool_cleanup_null);
    2214 
    2215     /* Function pool, gets destroyed before exit. */
    2216     apr_pool_t *pool;
    2217     ret = apr_pool_create(&pool, ptemp);
    2218     if (ret != APR_SUCCESS)
    2219     {
    2220         ap_log_error(APLOG_MARK, APLOG_ERR, ret, s,
    2221                      "%s: failed to allocate function memory pool.", __func__);
    2222         return ret;
    2223     }
    2224 
    2225     /* allocate credentials structures */
    2226     err = gnutls_certificate_allocate_credentials(&sc->proxy_x509_creds);
    2227     if (err != GNUTLS_E_SUCCESS)
    2228     {
    2229         ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
    2230                      "%s: Failed to initialize proxy credentials: (%d) %s",
    2231                      __func__, err, gnutls_strerror(err));
    2232         return APR_EGENERAL;
    2233     }
    2234     err = gnutls_anon_allocate_client_credentials(&sc->anon_client_creds);
    2235     if (err != GNUTLS_E_SUCCESS)
    2236     {
    2237         ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
    2238                      "%s: Failed to initialize anon credentials for proxy: "
    2239                      "(%d) %s", __func__, err, gnutls_strerror(err));
    2240         return APR_EGENERAL;
    2241     }
    2242 
    2243     /* Check if the proxy priorities have been set, fail immediately
    2244      * if not */
    2245     if (sc->proxy_priorities_str == NULL)
    2246     {
    2247         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    2248                      "Host '%s:%d' is missing the GnuTLSProxyPriorities "
    2249                      "directive!",
    2250                      s->server_hostname, s->port);
    2251         return APR_EGENERAL;
    2252     }
    2253     /* parse proxy priorities */
    2254     const char *err_pos = NULL;
    2255     err = gnutls_priority_init(&sc->proxy_priorities,
    2256                                sc->proxy_priorities_str, &err_pos);
    2257     if (err != GNUTLS_E_SUCCESS)
    2258     {
    2259         if (ret == GNUTLS_E_INVALID_REQUEST)
    2260             ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
    2261                          "%s: Syntax error parsing proxy priorities "
    2262                          "string at: %s",
    2263                          __func__, err_pos);
    2264         else
    2265             ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
    2266                          "Error setting proxy priorities: %s (%d)",
    2267                          gnutls_strerror(err), err);
    2268         ret = APR_EGENERAL;
    2269     }
    2270 
    2271     /* load certificate and key for client auth, if configured */
    2272     if (sc->proxy_x509_key_file && sc->proxy_x509_cert_file)
    2273     {
    2274         char* cert_file = ap_server_root_relative(pool,
    2275                                                   sc->proxy_x509_cert_file);
    2276         char* key_file = ap_server_root_relative(pool,
    2277                                                  sc->proxy_x509_key_file);
    2278         err = gnutls_certificate_set_x509_key_file(sc->proxy_x509_creds,
    2279                                                    cert_file,
    2280                                                    key_file,
    2281                                                    GNUTLS_X509_FMT_PEM);
    2282         if (err != GNUTLS_E_SUCCESS)
    2283         {
    2284             ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
    2285                          "%s: loading proxy client credentials failed: %s (%d)",
    2286                          __func__, gnutls_strerror(err), err);
    2287             ret = APR_EGENERAL;
    2288         }
    2289     }
    2290     else if (!sc->proxy_x509_key_file && sc->proxy_x509_cert_file)
    2291     {
    2292         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
    2293                      "%s: proxy key file not set!", __func__);
    2294         ret = APR_EGENERAL;
    2295     }
    2296     else if (!sc->proxy_x509_cert_file && sc->proxy_x509_key_file)
    2297     {
    2298         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
    2299                      "%s: proxy certificate file not set!", __func__);
    2300         ret = APR_EGENERAL;
    2301     }
    2302     else
    2303         /* if both key and cert are NULL, client auth is not used */
    2304         ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
    2305                      "%s: no client credentials for proxy", __func__);
    2306 
    2307     /* must be set if the server certificate is to be checked */
    2308     if (sc->proxy_x509_ca_file)
    2309     {
    2310         /* initialize the trust list */
    2311         err = gnutls_x509_trust_list_init(&sc->proxy_x509_tl, 0);
    2312         if (err != GNUTLS_E_SUCCESS)
    2313         {
    2314             ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
    2315                          "%s: gnutls_x509_trust_list_init failed: %s (%d)",
    2316                          __func__, gnutls_strerror(err), err);
    2317             ret = APR_EGENERAL;
    2318         }
    2319 
    2320         char* ca_file = ap_server_root_relative(pool,
    2321                                                 sc->proxy_x509_ca_file);
    2322         /* if no CRL is used, sc->proxy_x509_crl_file is NULL */
    2323         char* crl_file = NULL;
    2324         if (sc->proxy_x509_crl_file)
    2325             crl_file = ap_server_root_relative(pool,
    2326                                                sc->proxy_x509_crl_file);
    2327 
    2328         /* returns number of loaded elements */
    2329         err = gnutls_x509_trust_list_add_trust_file(sc->proxy_x509_tl,
    2330                                                     ca_file,
    2331                                                     crl_file,
    2332                                                     GNUTLS_X509_FMT_PEM,
    2333                                                     0 /* tl_flags */,
    2334                                                     0 /* tl_vflags */);
    2335         if (err > 0)
    2336             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
    2337                          "%s: proxy CA trust list: %d structures loaded",
    2338                          __func__, err);
    2339         else if (err == 0)
    2340             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
    2341                          "%s: proxy CA trust list is empty (%d)",
    2342                          __func__, err);
    2343         else /* err < 0 */
    2344         {
    2345             ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
    2346                          "%s: error loading proxy CA trust list: %s (%d)",
    2347                          __func__, gnutls_strerror(err), err);
    2348             ret = APR_EGENERAL;
    2349         }
    2350 
    2351         /* attach trust list to credentials */
    2352         gnutls_certificate_set_trust_list(sc->proxy_x509_creds,
    2353                                           sc->proxy_x509_tl, 0);
    2354     }
    2355     else
    2356         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
    2357                      "%s: no CA trust list for proxy connections, "
    2358                      "TLS connections will fail!", __func__);
    2359 
    2360     gnutls_certificate_set_verify_function(sc->proxy_x509_creds,
    2361                                            gtls_check_server_cert);
    2362     apr_pool_destroy(pool);
    2363     return ret;
    2364 }
Note: See TracChangeset for help on using the changeset viewer.