Changeset c0fc11e in mod_gnutls


Ignore:
Timestamp:
Nov 5, 2018, 2:20:54 AM (13 months ago)
Author:
Fiona Klute <fiona.klute@…>
Branches:
debian/master, master
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.

Files:
4 edited

Legend:

Unmodified
Added
Removed
  • include/mod_gnutls.h.in

    r7ff6c6c rc0fc11e  
    403403void *mgs_config_dir_create(apr_pool_t *p, char *dir);
    404404
    405 mgs_srvconf_rec* mgs_find_sni_server(gnutls_session_t session);
    406 
    407405const char *mgs_store_cred_path(cmd_parms * parms,
    408406                                void *dummy __attribute__((unused)),
  • 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;
  • src/gnutls_sni.c

    r7ff6c6c rc0fc11e  
    138138    return 0;
    139139}
     140
     141
     142
     143/**
     144 * Default buffer size for SNI data, including the terminating NULL
     145 * byte. The size matches what gnutls-cli uses initially.
     146 */
     147#define DEFAULT_SNI_HOST_LEN 256
     148
     149const char* mgs_server_name_get(mgs_handle_t *ctxt)
     150{
     151    char *sni_name = apr_palloc(ctxt->c->pool, DEFAULT_SNI_HOST_LEN);
     152    size_t sni_len = DEFAULT_SNI_HOST_LEN;
     153    unsigned int sni_type;
     154
     155    /* Search for a DNS SNI element. Note that RFC 6066 prohibits more
     156     * than one server name per type. */
     157    int sni_index = -1;
     158    int rv = 0;
     159    do {
     160        /* The sni_index is incremented before each use, so if the
     161         * loop terminates with a type match we will have the right
     162         * one stored. */
     163        rv = gnutls_server_name_get(ctxt->session, sni_name,
     164                                    &sni_len, &sni_type, ++sni_index);
     165        if (rv == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
     166        {
     167            ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_EGENERAL, ctxt->c,
     168                          "%s: no DNS SNI found (last index: %d).",
     169                          __func__, sni_index);
     170            return NULL;
     171        }
     172    } while (sni_type != GNUTLS_NAME_DNS);
     173    /* The (rv == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) path inside
     174     * the loop above returns, so if we reach this point we have a DNS
     175     * SNI at the current index. */
     176
     177    if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER)
     178    {
     179        /* Allocate a new buffer of the right size and retry */
     180        sni_name = apr_palloc(ctxt->c->pool, sni_len);
     181        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
     182                      "%s: reallocated SNI data buffer for %" APR_SIZE_T_FMT
     183                      " bytes.", __func__, sni_len);
     184        rv = gnutls_server_name_get(ctxt->session, sni_name,
     185                                    &sni_len, &sni_type, sni_index);
     186    }
     187
     188    /* Unless there's a bug in the GnuTLS API only GNUTLS_E_IDNA_ERROR
     189     * can occur here, but a catch all is safer and no more
     190     * complicated. */
     191    if (rv != GNUTLS_E_SUCCESS)
     192    {
     193        ap_log_cerror(APLOG_MARK, APLOG_INFO, APR_EGENERAL, ctxt->c,
     194                      "%s: error while getting SNI DNS data: '%s' (%d).",
     195                      __func__, gnutls_strerror(rv), rv);
     196        return NULL;
     197    }
     198
     199    return sni_name;
     200}
  • src/gnutls_sni.h

    r7ff6c6c rc0fc11e  
    2121                     const unsigned char *data, unsigned size);
    2222
     23
     24/**
     25 * Wrapper for gnutls_server_name_get(): Retrieve SNI data from the
     26 * TLS session associated with the connection, store it in a string
     27 * allocated from the connection pool.
     28 *
     29 * Note that `ctxt->sni_name` is not automatically updated.
     30 *
     31 * @param ctxt the connection to read from
     32 *
     33 * @return the requested server name, or NULL.
     34 */
     35const char* mgs_server_name_get(mgs_handle_t *ctxt);
     36
    2337#endif /* __MOD_GNUTLS_SNI_H__ */
Note: See TracChangeset for help on using the changeset viewer.