Changeset 98cf33f in mod_gnutls


Ignore:
Timestamp:
Sep 17, 2017, 1:01:23 PM (3 months ago)
Author:
Thomas Klute <thomas2.klute@…>
Branches:
master
Children:
2ae1c3c
Parents:
017ef2d
git-author:
Thomas Klute <thomas2.klute@…> (09/17/17 12:52:37)
git-committer:
Thomas Klute <thomas2.klute@…> (09/17/17 13:01:23)
Message:

Rewrite SNI handler to accept long names and ignore unknown name types

Names longer than the default buffer require a dynamic buffer
allocation of the size reported by GnuTLS. DNS is the only type
currently known to GnuTLS, but mod_gnutls should be able to handle any
future extension gracefully.

Location:
src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/gnutls_hooks.c

    r017ef2d r98cf33f  
    44 *  Copyright 2011 Dash Shendy
    55 *  Copyright 2013-2014 Daniel Kahn Gillmor
    6  *  Copyright 2015-2016 Thomas Klute
     6 *  Copyright 2015-2017 Thomas Klute
    77 *
    88 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    741741}
    742742
    743 #define MAX_HOST_LEN 255
     743/**
     744 * Default buffer size for SNI data, including the terminating NULL
     745 * byte. The size matches what gnutls-cli uses initially.
     746 */
     747#define DEFAULT_SNI_HOST_LEN 256
    744748
    745749typedef struct {
     
    834838}
    835839
     840/**
     841 * Get SNI data from GnuTLS (if any) and search for a matching virtual
     842 * host configuration. This method is called from the post client
     843 * hello function.
     844 *
     845 * @param session the GnuTLS session
     846 *
     847 * @return either the matching mod_gnutls server config, or `NULL`
     848 */
    836849mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
    837850{
     851    mgs_handle_t *ctxt = gnutls_session_get_ptr(session);
     852
     853    char *sni_name = apr_palloc(ctxt->c->pool, DEFAULT_SNI_HOST_LEN);
     854    size_t sni_len = DEFAULT_SNI_HOST_LEN;
    838855    unsigned int sni_type;
    839     size_t data_len = MAX_HOST_LEN;
    840     char sni_name[MAX_HOST_LEN];
    841 
    842     if (session == NULL)
    843         return NULL;
    844 
    845     mgs_handle_t *ctxt = gnutls_session_get_ptr(session);
    846     int rv = gnutls_server_name_get(session, sni_name,
    847                                     &data_len, &sni_type, 0);
    848 
    849 
    850     if (rv != 0) {
    851         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_EGENERAL, ctxt->c,
    852                       "%s: no SNI data found: %s (%d)",
     856
     857    /* Search for a DNS SNI element. Note that RFC 6066 prohibits more
     858     * than one server name per type. */
     859    int sni_index = -1;
     860    int rv = 0;
     861    do {
     862        /* The sni_index is incremented before each use, so if the
     863         * loop terminates with a type match we will have the right
     864         * one stored. */
     865        rv = gnutls_server_name_get(session, sni_name,
     866                                    &sni_len, &sni_type, ++sni_index);
     867        if (rv == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
     868        {
     869            ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_EGENERAL, ctxt->c,
     870                          "%s: no DNS SNI found (last index: %d).",
     871                          __func__, sni_index);
     872            return NULL;
     873        }
     874    } while (sni_type != GNUTLS_NAME_DNS);
     875    /* The (rv == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) path inside
     876     * the loop above returns, so if we reach this point we have a DNS
     877     * SNI at the current index. */
     878
     879    if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER)
     880    {
     881        /* Allocate a new buffer of the right size and retry */
     882        sni_name = apr_palloc(ctxt->c->pool, sni_len);
     883        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
     884                      "%s: reallocated SNI data buffer for %" APR_SIZE_T_FMT
     885                      " bytes.", __func__, sni_len);
     886        rv = gnutls_server_name_get(session, sni_name,
     887                                    &sni_len, &sni_type, sni_index);
     888    }
     889
     890    /* Unless there's a bug in the GnuTLS API only GNUTLS_E_IDNA_ERROR
     891     * can occur here, but a catch all is safer and no more
     892     * complicated. */
     893    if (rv != GNUTLS_E_SUCCESS)
     894    {
     895        ap_log_cerror(APLOG_MARK, APLOG_INFO, APR_EGENERAL, ctxt->c,
     896                      "%s: error while getting SNI DNS data: '%s' (%d).",
    853897                      __func__, gnutls_strerror(rv), rv);
    854898        return NULL;
    855899    }
    856900
    857     if (sni_type != GNUTLS_NAME_DNS) {
    858         ap_log_cerror(APLOG_MARK, APLOG_CRIT, 0, ctxt->c,
    859                       "GnuTLS: Unknown type '%d' for SNI: '%s'",
    860                       sni_type, sni_name);
    861         return NULL;
    862     }
    863 
    864     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctxt->c,
     901    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
    865902                  "%s: client requested server '%s'.",
    866903                  __func__, sni_name);
  • src/gnutls_io.c

    rcebb74a r98cf33f  
    33 *  Copyright 2008 Nikos Mavrogiannopoulos
    44 *  Copyright 2011 Dash Shendy
    5  *  Copyright 2015-2016 Thomas Klute
     5 *  Copyright 2015-2017 Thomas Klute
    66 *
    77 *  Licensed under the Apache License, Version 2.0 (the "License");
Note: See TracChangeset for help on using the changeset viewer.