Changeset c0fc11e in mod_gnutls for src/gnutls_hooks.c


Ignore:
Timestamp:
Nov 5, 2018, 2:20:54 AM (23 months ago)
Author:
Fiona Klute <fiona.klute@…>
Branches:
debian/master, master, proxy-ticket
Children:
d4c1a4e
Parents:
7ff6c6c
Message:

Separate functions for default SNI and loading virtual host credentials

The default SNI method using gnutls_server_name_get() won't be
necessary with early SNI parsing, but needs to remain available as a
fallback for old GnuTLS versions.

Loading virtual host credentials should happen in a separate function
so it can easily happen in pre or post client hello hooks alike.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/gnutls_hooks.c

    r7ff6c6c rc0fc11e  
    6666
    6767static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
    68 /* use side==0 for server and side==1 for client */
     68/** use side==0 for server and side==1 for client */
    6969static 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);
    7071static int mgs_status_hook(request_rec *r, int flags);
    7172#ifdef ENABLE_MSVA
     
    303304
    304305/**
     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/**
    305354 * Post client hello function for GnuTLS, used to configure the TLS
    306355 * server based on virtual host configuration. Uses SNI to select the
     
    318367
    319368    /* try to find a virtual host */
    320     mgs_srvconf_rec *tsc = mgs_find_sni_server(session);
     369    mgs_srvconf_rec *tsc = mgs_find_sni_server(ctxt);
    321370    if (tsc != NULL)
    322371    {
     
    326375        }
    327376
    328     gnutls_certificate_server_set_request(session, ctxt->sc->client_verify_mode);
    329 
    330     /* Set x509 credentials */
    331     gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
    332     /* Set Anon credentials */
    333     gnutls_credentials_set(session, GNUTLS_CRD_ANON, ctxt->sc->anon_creds);
    334 
    335 #ifdef ENABLE_SRP
    336         /* Set SRP credentials */
    337     if (ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) {
    338         gnutls_credentials_set(session, GNUTLS_CRD_SRP, ctxt->sc->srp_creds);
    339     }
    340 #endif
    341 
    342     /* Enable session tickets */
    343     if (session_ticket_key.data != NULL &&
    344         ctxt->sc->tickets == GNUTLS_ENABLED_TRUE)
    345     {
    346         ret = gnutls_session_ticket_enable_server(ctxt->session, &session_ticket_key);
    347         if (ret != GNUTLS_E_SUCCESS)
    348             ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, ctxt->c,
    349                           "gnutls_session_ticket_enable_server failed: %s (%d)",
    350                           gnutls_strerror(ret), ret);
    351     }
     377    reload_session_credentials(ctxt);
    352378
    353379    ret = process_alpn_result(ctxt);
    354380    if (ret != GNUTLS_E_SUCCESS)
    355381        return ret;
    356 
    357     /* Update the priorities - to avoid negotiating a ciphersuite that is not
    358      * enabled on this virtual server. Note that here we ignore the version
    359      * negotiation. */
    360     ret = gnutls_priority_set(session, ctxt->sc->priorities);
    361382
    362383    /* actually it shouldn't fail since we have checked at startup */
     
    855876}
    856877
    857 /**
    858  * Default buffer size for SNI data, including the terminating NULL
    859  * byte. The size matches what gnutls-cli uses initially.
    860  */
    861 #define DEFAULT_SNI_HOST_LEN 256
     878
    862879
    863880typedef struct {
     
    957974 * hello function.
    958975 *
    959  * @param session the GnuTLS session
     976 * @param ctxt the mod_gnutls connection handle
    960977 *
    961978 * @return either the matching mod_gnutls server config, or `NULL`
    962979 */
    963 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
     980mgs_srvconf_rec *mgs_find_sni_server(mgs_handle_t *ctxt)
    964981{
    965     mgs_handle_t *ctxt = gnutls_session_get_ptr(session);
    966 
    967     char *sni_name = apr_palloc(ctxt->c->pool, DEFAULT_SNI_HOST_LEN);
    968     size_t sni_len = DEFAULT_SNI_HOST_LEN;
    969     unsigned int sni_type;
    970 
    971     /* Search for a DNS SNI element. Note that RFC 6066 prohibits more
    972      * than one server name per type. */
    973     int sni_index = -1;
    974     int rv = 0;
    975     do {
    976         /* The sni_index is incremented before each use, so if the
    977          * loop terminates with a type match we will have the right
    978          * one stored. */
    979         rv = gnutls_server_name_get(session, sni_name,
    980                                     &sni_len, &sni_type, ++sni_index);
    981         if (rv == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
    982         {
    983             ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_EGENERAL, ctxt->c,
    984                           "%s: no DNS SNI found (last index: %d).",
    985                           __func__, sni_index);
    986             return NULL;
    987         }
    988     } while (sni_type != GNUTLS_NAME_DNS);
    989     /* The (rv == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) path inside
    990      * the loop above returns, so if we reach this point we have a DNS
    991      * SNI at the current index. */
    992 
    993     if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER)
    994     {
    995         /* Allocate a new buffer of the right size and retry */
    996         sni_name = apr_palloc(ctxt->c->pool, sni_len);
    997         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
    998                       "%s: reallocated SNI data buffer for %" APR_SIZE_T_FMT
    999                       " bytes.", __func__, sni_len);
    1000         rv = gnutls_server_name_get(session, sni_name,
    1001                                     &sni_len, &sni_type, sni_index);
    1002     }
    1003 
    1004     /* Unless there's a bug in the GnuTLS API only GNUTLS_E_IDNA_ERROR
    1005      * can occur here, but a catch all is safer and no more
    1006      * complicated. */
    1007     if (rv != GNUTLS_E_SUCCESS)
    1008     {
    1009         ap_log_cerror(APLOG_MARK, APLOG_INFO, APR_EGENERAL, ctxt->c,
    1010                       "%s: error while getting SNI DNS data: '%s' (%d).",
    1011                       __func__, gnutls_strerror(rv), rv);
     982    if (ctxt->sni_name == NULL)
     983    {
     984        const char *sni_name = mgs_server_name_get(ctxt);
     985        if (sni_name != NULL)
     986            ctxt->sni_name = sni_name;
    1012987        return NULL;
    1013988    }
     
    1015990    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
    1016991                  "%s: client requested server '%s'.",
    1017                   __func__, sni_name);
    1018     ctxt->sni_name = sni_name;
     992                  __func__, ctxt->sni_name);
    1019993
    1020994    /* Search for vhosts matching connection parameters and the
     
    1024998        .ctxt = ctxt,
    1025999        .sc = NULL,
    1026         .sni_name = sni_name
     1000        .sni_name = ctxt->sni_name
    10271001    };
    1028     rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
     1002    int rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
    10291003    if (rv == 1) {
    10301004        return cbx.sc;
Note: See TracChangeset for help on using the changeset viewer.