Changeset 8982265 in mod_gnutls for src/gnutls_hooks.c


Ignore:
Timestamp:
Apr 16, 2018, 8:43:01 PM (3 years ago)
Author:
Daniel Kahn Gillmor <dkg@…>
Branches:
debian/master, debian/stretch-backports
Children:
85c5a22
Parents:
300ae82 (diff), f4ac9ccd (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:

Merge tag 'upstream/0.8.4' into debian/master

Upstream version 0.8.4

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/gnutls_hooks.c

    r300ae82 r8982265  
    44 *  Copyright 2011 Dash Shendy
    55 *  Copyright 2013-2014 Daniel Kahn Gillmor
    6  *  Copyright 2015-2017 Thomas Klute
     6 *  Copyright 2015-2018 Fiona Klute
    77 *
    88 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2222#include "gnutls_cache.h"
    2323#include "gnutls_ocsp.h"
     24#include "gnutls_util.h"
    2425#include "http_vhost.h"
    2526#include "ap_mpm.h"
     
    133134    return OK;
    134135}
     136
     137
     138
     139/**
     140 * Get the list of available protocols for this connection and add it
     141 * to the GnuTLS session. Must run before the client hello function.
     142 */
     143static void prepare_alpn_proposals(mgs_handle_t *ctxt)
     144{
     145    /* Check if any protocol upgrades are available
     146     *
     147     * The "report_all" parameter to ap_get_protocol_upgrades() is 0
     148     * (report only more preferable protocols) because setting it to 1
     149     * doesn't actually report ALL protocols, but only all except the
     150     * current one. This way we can at least list the current one as
     151     * available by appending it without potentially negotiating a
     152     * less preferred protocol. */
     153    const apr_array_header_t *pupgrades = NULL;
     154    apr_status_t ret =
     155        ap_get_protocol_upgrades(ctxt->c, NULL, ctxt->c->base_server,
     156                                 /*report_all*/ 0, &pupgrades);
     157    if (ret != APR_SUCCESS)
     158    {
     159        ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, ctxt->c,
     160                      "%s: ap_get_protocol_upgrades() failed, "
     161                      "cannot configure ALPN!", __func__);
     162        return;
     163    }
     164
     165    if (pupgrades == NULL || pupgrades->nelts == 0)
     166    {
     167        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctxt->c,
     168                      "%s: No protocol upgrades available.", __func__);
     169        return;
     170    }
     171
     172    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctxt->c,
     173                  "%s: Found %d protocol upgrade(s) for ALPN: %s",
     174                  __func__, pupgrades->nelts,
     175                  apr_array_pstrcat(ctxt->c->pool, pupgrades, ','));
     176    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    }
     186
     187    /* Add the current (default) protocol at the end of the list */
     188    alpn_protos[pupgrades->nelts].data =
     189        (void*) apr_pstrdup(ctxt->c->pool, ap_get_protocol(ctxt->c));
     190    alpn_protos[pupgrades->nelts].size =
     191        strlen((char*) alpn_protos[pupgrades->nelts].data);
     192    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctxt->c,
     193                  "%s: Adding current protocol %s to ALPN set.",
     194                  __func__, alpn_protos[pupgrades->nelts].data);
     195
     196    gnutls_alpn_set_protocols(ctxt->session,
     197                              alpn_protos,
     198                              pupgrades->nelts,
     199                              GNUTLS_ALPN_SERVER_PRECEDENCE);
     200}
     201
     202
     203
     204/**
     205 * Check if ALPN selected any protocol upgrade, try to switch if so.
     206 */
     207static int process_alpn_result(mgs_handle_t *ctxt)
     208{
     209    int ret = 0;
     210    gnutls_datum_t alpn_proto;
     211    ret = gnutls_alpn_get_selected_protocol(ctxt->session, &alpn_proto);
     212    if (ret != GNUTLS_E_SUCCESS)
     213    {
     214        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
     215                      "%s: No ALPN result: %s (%d)",
     216                      __func__, gnutls_strerror(ret), ret);
     217        return GNUTLS_E_SUCCESS;
     218    }
     219
     220    apr_array_header_t *client_protos =
     221        apr_array_make(ctxt->c->pool, 1, sizeof(char *));
     222    /* apr_pstrndup to ensure that the protocol is null terminated */
     223    APR_ARRAY_PUSH(client_protos, char *) =
     224        apr_pstrndup(ctxt->c->pool, (char*) alpn_proto.data, alpn_proto.size);
     225    const char *selected =
     226        ap_select_protocol(ctxt->c, NULL, ctxt->c->base_server,
     227                           client_protos);
     228
     229    /* ap_select_protocol() will return NULL if none of the ALPN
     230     * proposals matched. GnuTLS negotiated alpn_proto based on the
     231     * list provided by the server, but the vhost might have changed
     232     * based on SNI. Apache seems to adjust the proposal list to avoid
     233     * such issues though.
     234     *
     235     * GnuTLS will return a fatal "no_application_protocol" alert as
     236     * required by RFC 7301 if the post client hello function returns
     237     * GNUTLS_E_NO_APPLICATION_PROTOCOL. */
     238    if (!selected)
     239    {
     240        ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, ctxt->c,
     241                      "%s: ap_select_protocol() returned NULL! Please "
     242                      "make sure any overlapping vhosts have the same "
     243                      "protocols available.",
     244                      __func__);
     245        return GNUTLS_E_NO_APPLICATION_PROTOCOL;
     246    }
     247
     248    if (strcmp(selected, ap_get_protocol(ctxt->c)) == 0)
     249    {
     250        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
     251                      "%s: Already using protocol '%s', nothing to do.",
     252                      __func__, selected);
     253        return GNUTLS_E_SUCCESS;
     254    }
     255
     256    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ctxt->c,
     257                  "%s: Switching protocol to '%s' based on ALPN.",
     258                  __func__, selected);
     259    apr_status_t status = ap_switch_protocol(ctxt->c, NULL,
     260                                             ctxt->c->base_server,
     261                                             selected);
     262    if (status != APR_SUCCESS)
     263    {
     264        ap_log_cerror(APLOG_MARK, APLOG_ERR, status, ctxt->c,
     265                      "%s: Protocol switch to '%s' failed!",
     266                      __func__, selected);
     267        return GNUTLS_E_NO_APPLICATION_PROTOCOL;
     268    }
     269    /* ALPN done! */
     270    return GNUTLS_E_SUCCESS;
     271}
     272
     273
    135274
    136275/**
     
    165304    gnutls_credentials_set(session, GNUTLS_CRD_ANON, ctxt->sc->anon_creds);
    166305
    167     if (ctxt->sc->ocsp_staple)
    168     {
    169         gnutls_certificate_set_ocsp_status_request_function(ctxt->sc->certs,
    170                                                             mgs_get_ocsp_response,
    171                                                             ctxt);
    172     }
    173 
    174306#ifdef ENABLE_SRP
    175307        /* Set SRP credentials */
     
    179311#endif
    180312
    181     /* update the priorities - to avoid negotiating a ciphersuite that is not
     313    ret = process_alpn_result(ctxt);
     314    if (ret != GNUTLS_E_SUCCESS)
     315        return ret;
     316
     317    /* Update the priorities - to avoid negotiating a ciphersuite that is not
    182318     * enabled on this virtual server. Note that here we ignore the version
    183      * negotiation.
    184      */
     319     * negotiation. */
    185320    ret = gnutls_priority_set(session, ctxt->sc->priorities);
    186321
     
    9641099static void create_gnutls_handle(conn_rec * c)
    9651100{
    966     /* Get mod_gnutls server configuration */
    967     mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
    968             ap_get_module_config(c->base_server->module_config, &gnutls_module);
    969 
    9701101    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    9711102
    9721103    /* Get connection specific configuration */
    973     mgs_handle_t *ctxt = (mgs_handle_t *) ap_get_module_config(c->conn_config, &gnutls_module);
    974     if (ctxt == NULL)
    975     {
    976         ctxt = apr_pcalloc(c->pool, sizeof (*ctxt));
    977         ap_set_module_config(c->conn_config, &gnutls_module, ctxt);
    978         ctxt->is_proxy = GNUTLS_ENABLED_FALSE;
    979     }
     1104    mgs_handle_t *ctxt = init_gnutls_ctxt(c);
    9801105    ctxt->enabled = GNUTLS_ENABLED_TRUE;
    981     ctxt->c = c;
    982     ctxt->sc = sc;
    9831106    ctxt->status = 0;
    9841107    ctxt->input_rc = APR_SUCCESS;
     
    10581181    }
    10591182
     1183    prepare_alpn_proposals(ctxt);
     1184
    10601185    /* Initialize Session Cache */
    10611186    mgs_cache_session_init(ctxt);
     
    10781203    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    10791204
     1205    if (c->master)
     1206    {
     1207        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
     1208                      "%s declined secondary connection", __func__);
     1209        return DECLINED;
     1210    }
     1211
    10801212    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
    10811213        ap_get_module_config(c->base_server->module_config, &gnutls_module);
     
    10831215        ap_get_module_config(c->conn_config, &gnutls_module);
    10841216
    1085     if ((sc && (!sc->enabled)) || (ctxt && ctxt->enabled == GNUTLS_ENABLED_FALSE))
     1217    if ((sc && (!sc->enabled))
     1218        || (ctxt && ctxt->enabled == GNUTLS_ENABLED_FALSE))
    10861219    {
    10871220        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "%s declined connection",
     
    10931226    return OK;
    10941227}
     1228
     1229
     1230
     1231/**
     1232 * process_connection hook: Do a zero byte read to trigger the
     1233 * handshake. Doesn't change anything for traditional protocols that
     1234 * just do reads, but HTTP/2 needs the TLS handshake and ALPN to
     1235 * happen before its process_connection hook runs.
     1236 */
     1237int mgs_hook_process_connection(conn_rec* c)
     1238{
     1239    mgs_handle_t *ctxt = (mgs_handle_t *)
     1240        ap_get_module_config(c->conn_config, &gnutls_module);
     1241
     1242    if ((ctxt != NULL) && (ctxt->enabled == GNUTLS_ENABLED_TRUE))
     1243    {
     1244        /* This connection is supposed to use TLS. Give the filters a
     1245         * kick with a zero byte read to trigger the handshake. */
     1246        apr_bucket_brigade* temp =
     1247            apr_brigade_create(c->pool, c->bucket_alloc);
     1248        ap_get_brigade(c->input_filters, temp,
     1249                       AP_MODE_INIT, APR_BLOCK_READ, 0);
     1250        apr_brigade_destroy(temp);
     1251    }
     1252    return DECLINED;
     1253}
     1254
     1255
    10951256
    10961257int mgs_hook_fixups(request_rec * r) {
     
    11071268    apr_table_t *env = r->subprocess_env;
    11081269
    1109     ctxt = ap_get_module_config(r->connection->conn_config,
    1110                                 &gnutls_module);
     1270    ctxt = get_effective_gnutls_ctxt(r->connection);
    11111271
    11121272    if (!ctxt || ctxt->enabled != GNUTLS_ENABLED_TRUE || ctxt->session == NULL)
     
    11881348
    11891349    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    1190     ctxt =
    1191             ap_get_module_config(r->connection->conn_config,
    1192             &gnutls_module);
     1350    ctxt = get_effective_gnutls_ctxt(r->connection);
    11931351
    11941352    if (!ctxt || ctxt->session == NULL) {
     
    19202078    if (sc->enabled != GNUTLS_ENABLED_FALSE)
    19212079    {
    1922         mgs_handle_t* ctxt =
    1923             ap_get_module_config(r->connection->conn_config, &gnutls_module);
     2080        mgs_handle_t* ctxt = get_effective_gnutls_ctxt(r->connection);
    19242081        if (ctxt && ctxt->session != NULL)
    19252082        {
Note: See TracChangeset for help on using the changeset viewer.