Changes in / [dcc053e:0e55076] in mod_gnutls


Ignore:
Files:
3 added
17 edited

Legend:

Unmodified
Added
Removed
  • CHANGELOG

    rdcc053e r0e55076  
     1** Version 0.9.0 UNRELEASED
     2- Security fix: Refuse to send or receive any data over a failed TLS
     3  connection (commit 72b669eae8c45dda1850e8e5b30a97c918357b51). This
     4  could lead to requests on reverse proxy TLS connections being sent
     5  in plain text, and might allow faking requests in plain text.
     6- Security fix: Reject HTTP requests if they try to access virtual
     7  hosts that do not match their TLS connections (commit
     8  de3fad3c12f53cdbf082ad675e4b10f521a02811). Additionally check if SNI
     9  and Host header match.
     10- OCSP stapling is now enabled by default, if possible. OCSP responses
     11  are updated regularly and stored in a cache separate from the
     12  session cache. The OCSP cache uses mod_socache_shmcb by default
     13  (if the module is loaded, no other configuration required).
     14- Session tickets are now enabled by default if using GnuTLS 3.6.4 or
     15  newer. GnuTLS 3.6.4 introduced automatic rotation for the used key,
     16  and TLS 1.3 takes care of other reasons not to use tickets while
     17  requiring them for session resumption. Note that there is currently
     18  no mechanism to synchronize ticket keys across a cluster of servers.
     19- The internal cache implementation has been replaced with
     20  mod_socache. Users may need to update their GnuTLSCache settings and
     21  load the appropriate socache modules.
     22- ALPN (required for HTTP/2) now works correctly with different
     23  "Protocols" directives between virtual hosts if building with GnuTLS
     24  3.6.3 or newer. Older versions require identical "Protocols"
     25  directives for overlapping virtual hosts. Thanks to Vincent Tamet
     26  for the bug report!
     27- GnuTLSPriorities is optional now and defaults to "NORMAL" if
     28  missing. The same applies to GnuTLSProxyPriorities (if TLS proxy is
     29  enabled).
     30- The manual is now built as a manual page, too, if pandoc is
     31  available.
     32- OpenPGP support has been removed.
     33
    134** Version 0.8.4 (2018-04-13)
    235- Support Apache HTTPD 2.4.33 API for proxy TLS connections
  • configure.ac

    rdcc053e r0e55076  
    6767AC_SEARCH_LIBS([gnutls_srp_server_get_username], [gnutls], [], [use_srp="no"])
    6868
    69 SRP_CFLAGS=""
     69GNUTLS_FEAT_CFLAGS=""
    7070if test "$use_srp" != "no"; then
    71         SRP_CFLAGS="-DENABLE_SRP=1"
    72 fi
     71        GNUTLS_FEAT_CFLAGS="-DENABLE_SRP=1"
     72fi
     73
     74# check if the available GnuTLS library supports raw extension parsing
     75AC_SEARCH_LIBS([gnutls_ext_raw_parse], [gnutls], [early_sni="yes"],
     76        [early_sni="no"])
     77if test "$early_sni" != "no"; then
     78        ENABLE_EARLY_SNI=1
     79        # This is for the test server configuration
     80        EXPECT_EARLY_SNI="Define EXPECT_EARLY_SNI"
     81else
     82        ENABLE_EARLY_SNI=0
     83        EXPECT_EARLY_SNI=""
     84fi
     85AC_SUBST(ENABLE_EARLY_SNI)
     86AC_SUBST(EXPECT_EARLY_SNI)
     87AM_SUBST_NOTMAKE(EXPECT_EARLY_SNI)
    7388
    7489AC_ARG_ENABLE(strict,
     
    198213        AC_PATH_PROG([PDFLATEX], [pdflatex], [no])
    199214        if test "$PDFLATEX" != "no"; then
    200                 build_doc=yes
     215                build_doc="html, manual page, pdf"
    201216        else
    202                 build_doc="html only"
     217                build_doc="html, manual page"
    203218        fi
    204219else
     
    223238AC_PATH_PROGS([HTTP_CLI], [curl wget], [no])
    224239
    225 MODULE_CFLAGS="${LIBGNUTLS_CFLAGS} ${SRP_CFLAGS} ${MSVA_CFLAGS} ${APXS_CFLAGS} ${AP_INCLUDES} ${APR_INCLUDES} ${APU_INCLUDES} ${STRICT_CFLAGS}"
     240MODULE_CFLAGS="${LIBGNUTLS_CFLAGS} ${GNUTLS_FEAT_CFLAGS} ${MSVA_CFLAGS} ${APXS_CFLAGS} ${AP_INCLUDES} ${APR_INCLUDES} ${APU_INCLUDES} ${STRICT_CFLAGS}"
    226241MODULE_LIBS="${LIBGNUTLS_LIBS}"
    227242
     
    294309DX_RTF_FEATURE(OFF)
    295310DX_XML_FEATURE(OFF)
    296 DX_PDF_FEATURE(ON)
     311DX_PDF_FEATURE(OFF)
    297312DX_PS_FEATURE(OFF)
    298313DX_INIT_DOXYGEN([mod_gnutls], [doc/doxygen.conf], [doc/api])
     
    301316                        doc/Makefile doc/doxygen.conf include/mod_gnutls.h \
    302317                        test/proxy_backend.conf test/ocsp_server.conf \
     318                        test/apache-conf/early_sni.conf \
    303319                        test/apache-conf/listen.conf \
    304320                        test/apache-conf/netns.conf])
     
    315331echo "   * SRP Authentication:  ${use_srp}"
    316332echo "   * MSVA Client Verification:    ${use_msva}"
     333echo "   * Early SNI (experimental):    ${early_sni}"
    317334echo "   * Build documentation: ${build_doc}"
    318335echo ""
  • doc/doxygen.conf.in

    rdcc053e r0e55076  
    19981998# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
    19991999
    2000 MACRO_EXPANSION        = NO
     2000MACRO_EXPANSION        = YES
    20012001
    20022002# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
     
    20062006# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
    20072007
    2008 EXPAND_ONLY_PREDEF     = NO
     2008EXPAND_ONLY_PREDEF     = YES
    20092009
    20102010# If the SEARCH_INCLUDES tag is set to YES, the include files in the
     
    20382038# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
    20392039
    2040 PREDEFINED             = HAVE_APR_MEMCACHE=@have_apr_memcache@
     2040PREDEFINED             = ENABLE_EARLY_SNI \
     2041                         __attribute__(x)=
    20412042
    20422043# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
  • doc/mod_gnutls_manual.mdwn

    rdcc053e r0e55076  
    4747
    4848    LoadModule gnutls_module modules/mod_gnutls.so
     49
     50Note on HTTP/2
     51--------------
     52
     53HTTP/2 is supported with `mod_gnutls`. However, full support requires
     54compiling with GnuTLS 3.6.3 or later. When using lower versions all
     55virtual hosts using `mod_gnutls` with overlapping IP/port combinations
     56need to use identical `Protocols` directives for protocol negotiation
     57to work correctly.
     58
     59The technical reason is that using HTTP/2 requires ALPN (Application
     60Layer Protocol Negotiation) to be set up before GnuTLS parses the TLS
     61ClientHello message, but earlier hooks cannot use
     62`gnutls_server_name_get()` to retrieve SNI (Server Name Indication)
     63data for virtual host selection. Because of this `mod_gnutls` provides
     64its own early SNI parser, which requires the `gnutls_ext_raw_parse()`
     65function introduced in GnuTLS 3.6.3 to retrieve the extension data in
     66a *pre* client hello hook.
    4967
    5068* * * * *
     
    725743-----------------------------------------
    726744
    727 `mod_gnutls` supports "Server Name Indication", as specified in [RFC
    728 6066, Section 3](https://tools.ietf.org/html/rfc6066#section-3). This
    729 allows hosting many TLS websites with a single IP address, you can
    730 just add the virtual host conigurations. All recent browsers support
     745`mod_gnutls` supports Server Name Indication (SNI), as specified in
     746[RFC 6066, Section 3](https://tools.ietf.org/html/rfc6066#section-3).
     747This allows hosting many TLS websites with a single IP address, you
     748can just add virtual host configurations. All recent browsers support
    731749this standard. Here is an example using SNI:
    732750
     
    763781         GnuTLSCertificateFile conf/tls/site3.crt
    764782         GnuTLSKeyFile conf/tls/site3.key
     783         # Enable HTTP/2. With GnuTLS before version 3.6.3 all
     784         # virtual hosts in this example would have to share this
     785         # directive to work correctly.
     786         Protocols h2 http/1.1
    765787     </VirtualHost>
    766788
  • include/mod_gnutls.h.in

    rdcc053e r0e55076  
    2626#include "http_log.h"
    2727#include "apr_buckets.h"
    28 #include "apr_strings.h"
    2928#include "apr_tables.h"
    3029#include "ap_release.h"
    31 #include "apr_fnmatch.h"
    3230/* GnuTLS Library Headers */
    3331#include <gnutls/gnutls.h>
     
    5351#define MOD_GNUTLS_DEBUG @OOO_MAINTAIN@
    5452
     53/* Compile support for early SNI? */
     54#if @ENABLE_EARLY_SNI@ == 1
     55#define ENABLE_EARLY_SNI
     56#endif
     57
    5558/** Name of the module-wide singleton watchdog */
    5659#define MGS_SINGLETON_WATCHDOG "_mod_gnutls_singleton_"
     
    8285/** Server Configuration Record */
    8386typedef struct {
     87    /** Server this mod_gnutls configuration is for */
     88    server_rec* s;
     89
    8490    /* --- Configuration values --- */
    8591        /* Is the module enabled? */
     
    405411void *mgs_config_dir_create(apr_pool_t *p, char *dir);
    406412
    407 mgs_srvconf_rec* mgs_find_sni_server(gnutls_session_t session);
    408 
    409413const char *mgs_store_cred_path(cmd_parms * parms,
    410414                                void *dummy __attribute__((unused)),
  • src/Makefile.am

    rdcc053e r0e55076  
    77
    88mod_gnutls_la_SOURCES = mod_gnutls.c gnutls_io.c gnutls_cache.c \
    9         gnutls_config.c gnutls_hooks.c gnutls_ocsp.c gnutls_util.c \
    10         gnutls_watchdog.c
     9        gnutls_config.c gnutls_hooks.c gnutls_ocsp.c gnutls_sni.c \
     10        gnutls_util.c gnutls_watchdog.c
    1111mod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS}
    1212mod_gnutls_la_LDFLAGS = -module -avoid-version ${MODULE_LIBS}
    13 noinst_HEADERS = gnutls_cache.h gnutls_config.h gnutls_ocsp.h gnutls_util.h \
    14         gnutls_watchdog.h
     13noinst_HEADERS = gnutls_cache.h gnutls_config.h gnutls_ocsp.h gnutls_sni.h \
     14        gnutls_util.h gnutls_watchdog.h
    1515
    1616apmodpkglib_LTLIBRARIES = mod_gnutls.la
  • src/gnutls_cache.c

    rdcc053e r0e55076  
    3434
    3535#include <ap_socache.h>
     36#include <apr_strings.h>
    3637#include <mod_status.h>
    3738#include <apr_escape.h>
  • src/gnutls_config.c

    rdcc053e r0e55076  
    2222#include "mod_gnutls.h"
    2323#include "gnutls_ocsp.h"
     24
    2425#include "apr_lib.h"
     26#include <apr_strings.h>
    2527#include <gnutls/abstract.h>
    2628
     
    657659        ap_get_module_config(parms->server->module_config, &gnutls_module);
    658660
    659     if (!apr_strnatcasecmp(parms->directive->directive, "GnuTLSCacheTimeout"))
     661    if (!strcasecmp(parms->directive->directive, "GnuTLSCacheTimeout"))
    660662        sc->cache_timeout = apr_time_from_sec(argint);
    661     else if (!apr_strnatcasecmp(parms->directive->directive,
    662                                 "GnuTLSOCSPCacheTimeout"))
     663    else if (!strcasecmp(parms->directive->directive,
     664                         "GnuTLSOCSPCacheTimeout"))
    663665        sc->ocsp_cache_time = apr_time_from_sec(argint);
    664     else if (!apr_strnatcasecmp(parms->directive->directive,
    665                                 "GnuTLSOCSPFailureTimeout"))
     666    else if (!strcasecmp(parms->directive->directive,
     667                         "GnuTLSOCSPFailureTimeout"))
    666668        sc->ocsp_failure_timeout = apr_time_from_sec(argint);
    667     else if (!apr_strnatcasecmp(parms->directive->directive,
    668                                 "GnuTLSOCSPFuzzTime"))
     669    else if (!strcasecmp(parms->directive->directive,
     670                         "GnuTLSOCSPFuzzTime"))
    669671        sc->ocsp_fuzz_time = apr_time_from_sec(argint);
    670     else if (!apr_strnatcasecmp(parms->directive->directive,
    671                                 "GnuTLSOCSPSocketTimeout"))
     672    else if (!strcasecmp(parms->directive->directive,
     673                         "GnuTLSOCSPSocketTimeout"))
    672674        sc->ocsp_socket_timeout = apr_time_from_sec(argint);
    673675    else
  • src/gnutls_hooks.c

    rdcc053e r0e55076  
    2323#include "gnutls_config.h"
    2424#include "gnutls_ocsp.h"
     25#include "gnutls_sni.h"
    2526#include "gnutls_util.h"
    2627#include "gnutls_watchdog.h"
     
    3132#include <util_mutex.h>
    3233#include <apr_escape.h>
     34/* This provides strcmp and related functions */
     35#define APR_WANT_STRFUNC
     36#include <apr_want.h>
    3337
    3438#ifdef ENABLE_MSVA
     
    6266
    6367static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
    64 /* use side==0 for server and side==1 for client */
     68/** use side==0 for server and side==1 for client */
    6569static 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);
    6671static int mgs_status_hook(request_rec *r, int flags);
    6772#ifdef ENABLE_MSVA
     
    178183    const apr_array_header_t *pupgrades = NULL;
    179184    apr_status_t ret =
    180         ap_get_protocol_upgrades(ctxt->c, NULL, ctxt->c->base_server,
     185        ap_get_protocol_upgrades(ctxt->c, NULL, ctxt->sc->s,
    181186                                 /*report_all*/ 0, &pupgrades);
    182187    if (ret != APR_SUCCESS)
     
    249254        apr_pstrndup(ctxt->c->pool, (char*) alpn_proto.data, alpn_proto.size);
    250255    const char *selected =
    251         ap_select_protocol(ctxt->c, NULL, ctxt->c->base_server,
    252                            client_protos);
     256        ap_select_protocol(ctxt->c, NULL, ctxt->sc->s, client_protos);
    253257
    254258    /* ap_select_protocol() will return NULL if none of the ALPN
     
    283287                  __func__, selected);
    284288    apr_status_t status = ap_switch_protocol(ctxt->c, NULL,
    285                                              ctxt->c->base_server,
     289                                             ctxt->sc->s,
    286290                                             selected);
    287291    if (status != APR_SUCCESS)
     
    299303
    300304/**
    301  * Post client hello function for GnuTLS, used to configure the TLS
    302  * server based on virtual host configuration. Uses SNI to select the
    303  * virtual host if available.
     305 * (Re-)Load credentials and priorities for the connection. This is
     306 * meant to be called after virtual host selection in the pre or post
     307 * client hello hook.
     308 */
     309static int reload_session_credentials(mgs_handle_t *ctxt)
     310{
     311    int ret = 0;
     312
     313    gnutls_certificate_server_set_request(ctxt->session,
     314                                          ctxt->sc->client_verify_mode);
     315
     316    /* Set x509 credentials */
     317    gnutls_credentials_set(ctxt->session,
     318                           GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
     319    /* Set Anon credentials */
     320    gnutls_credentials_set(ctxt->session, GNUTLS_CRD_ANON,
     321                           ctxt->sc->anon_creds);
     322
     323#ifdef ENABLE_SRP
     324        /* Set SRP credentials */
     325    if (ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) {
     326        gnutls_credentials_set(ctxt->session, GNUTLS_CRD_SRP,
     327                               ctxt->sc->srp_creds);
     328    }
     329#endif
     330
     331    /* Enable session tickets */
     332    if (session_ticket_key.data != NULL &&
     333        ctxt->sc->tickets == GNUTLS_ENABLED_TRUE)
     334    {
     335        ret = gnutls_session_ticket_enable_server(ctxt->session, &session_ticket_key);
     336        if (ret != GNUTLS_E_SUCCESS)
     337            ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, ctxt->c,
     338                          "gnutls_session_ticket_enable_server failed: %s (%d)",
     339                          gnutls_strerror(ret), ret);
     340    }
     341
     342    /* Update the priorities - to avoid negotiating a ciphersuite that is not
     343     * enabled on this virtual server. Note that here we ignore the version
     344     * negotiation. */
     345    ret = gnutls_priority_set(ctxt->session, ctxt->sc->priorities);
     346
     347    return ret;
     348}
     349
     350
     351
     352/**
     353 * Post client hello hook function for GnuTLS. This function has two
     354 * purposes: Firstly, it acts as a fallback for early_sni_hook(), by
     355 * parsing SNI and selecting a virtual host based on it if
     356 * necessary. Secondly, it calls ALPN processing.
    304357 *
    305358 * @param session the TLS session
     
    308361 * definition
    309362 */
    310 static int mgs_select_virtual_server_cb(gnutls_session_t session)
     363static int post_client_hello_hook(gnutls_session_t session)
    311364{
    312365    int ret = 0;
    313366    mgs_handle_t *ctxt = gnutls_session_get_ptr(session);
    314367
    315     /* try to find a virtual host */
    316     mgs_srvconf_rec *tsc = mgs_find_sni_server(session);
    317     if (tsc != NULL)
    318     {
    319         /* Found a TLS vhost based on the SNI, configure the
    320          * connection context. */
    321         ctxt->sc = tsc;
    322         }
    323 
    324     gnutls_certificate_server_set_request(session, ctxt->sc->client_verify_mode);
    325 
    326     /* Set x509 credentials */
    327     gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
    328     /* Set Anon credentials */
    329     gnutls_credentials_set(session, GNUTLS_CRD_ANON, ctxt->sc->anon_creds);
    330 
    331 #ifdef ENABLE_SRP
    332         /* Set SRP credentials */
    333     if (ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) {
    334         gnutls_credentials_set(session, GNUTLS_CRD_SRP, ctxt->sc->srp_creds);
    335     }
    336 #endif
    337 
    338     /* Enable session tickets */
    339     if (session_ticket_key.data != NULL &&
    340         ctxt->sc->tickets == GNUTLS_ENABLED_TRUE)
    341     {
    342         ret = gnutls_session_ticket_enable_server(ctxt->session, &session_ticket_key);
    343         if (ret != GNUTLS_E_SUCCESS)
    344             ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, ctxt->c,
    345                           "gnutls_session_ticket_enable_server failed: %s (%d)",
    346                           gnutls_strerror(ret), ret);
     368    /* If ctxt->sni_name is set at this point the early_sni_hook()
     369     * function ran, found an SNI server name, selected a virtual
     370     * host, and set up credentials, so we don't need to do that
     371     * again. Otherwise try again, to cover GnuTLS versions < 3.6.3
     372     * and pick up future extensions to gnutls_server_name_get(). */
     373    if (ctxt->sni_name == NULL)
     374    {
     375        /* try to find a virtual host */
     376        mgs_srvconf_rec *tsc = mgs_find_sni_server(ctxt);
     377        if (tsc != NULL)
     378        {
     379            /* Found a TLS vhost based on the SNI, configure the
     380             * connection context. */
     381            ctxt->sc = tsc;
     382        }
     383
     384        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
     385                      "%s: Loading credentials in post client hello hook",
     386                      __func__);
     387        reload_session_credentials(ctxt);
    347388    }
    348389
     
    350391    if (ret != GNUTLS_E_SUCCESS)
    351392        return ret;
    352 
    353     /* Update the priorities - to avoid negotiating a ciphersuite that is not
    354      * enabled on this virtual server. Note that here we ignore the version
    355      * negotiation. */
    356     ret = gnutls_priority_set(session, ctxt->sc->priorities);
    357393
    358394    /* actually it shouldn't fail since we have checked at startup */
     
    610646    {
    611647        sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
     648        sc->s = s;
    612649        sc->cache_enable = sc_base->cache_enable;
    613650        sc->cache = sc_base->cache;
     
    851888}
    852889
    853 /**
    854  * Default buffer size for SNI data, including the terminating NULL
    855  * byte. The size matches what gnutls-cli uses initially.
    856  */
    857 #define DEFAULT_SNI_HOST_LEN 256
     890
    858891
    859892typedef struct {
     
    875908int check_server_aliases(vhost_cb_rec *x, server_rec * s, mgs_srvconf_rec *tsc)
    876909{
    877         apr_array_header_t *names;
    878         int rv = 0;
    879         char ** name;
    880 
    881         /* Check ServerName First! */
    882         if(apr_strnatcasecmp(x->sni_name, s->server_hostname) == 0) {
    883                 // We have a match, save this server configuration
    884                 x->sc = tsc;
    885                 rv = 1;
    886         /* Check any ServerAlias directives */
    887         } else if(s->names->nelts) {
    888                 names = s->names;
    889                 name = (char **)names->elts;
    890                 for (int i = 0; i < names->nelts; ++i)
     910    apr_array_header_t *names;
     911    int rv = 0;
     912    char ** name;
     913
     914    /* Check ServerName First! */
     915    if (strcasecmp(x->sni_name, s->server_hostname) == 0) {
     916        // We have a match, save this server configuration
     917        x->sc = tsc;
     918        rv = 1;
     919        /* Check any ServerAlias directives */
     920    } else if(s->names->nelts) {
     921        names = s->names;
     922        name = (char **) names->elts;
     923        for (int i = 0; i < names->nelts; ++i)
    891924        {
    892                         if (!name[i]) { continue; }
    893                                 if (apr_strnatcasecmp(x->sni_name, name[i]) == 0) {
    894                                         // We have a match, save this server configuration
    895                                         x->sc = tsc;
    896                                         rv = 1;
    897                         }
    898                 }
    899         /* Wild any ServerAlias Directives */
    900         } else if(s->wild_names->nelts) {
    901                 names = s->wild_names;
    902         name = (char **)names->elts;
    903                 for (int i = 0; i < names->nelts; ++i)
     925            if (!name[i])
     926                continue;
     927            if (strcasecmp(x->sni_name, name[i]) == 0)
     928            {
     929                // We have a match, save this server configuration
     930                x->sc = tsc;
     931                rv = 1;
     932            }
     933        }
     934        /* ServerAlias directives may contain wildcards, check those last. */
     935    } else if(s->wild_names->nelts) {
     936        names = s->wild_names;
     937        name = (char **) names->elts;
     938        for (int i = 0; i < names->nelts; ++i)
    904939        {
    905                         if (!name[i]) { continue; }
    906                                 if(apr_fnmatch(name[i], x->sni_name ,
    907                                                                 APR_FNM_CASE_BLIND|
    908                                                                 APR_FNM_PERIOD|
    909                                                                 APR_FNM_PATHNAME|
    910                                                                 APR_FNM_NOESCAPE) == APR_SUCCESS) {
    911                                 x->sc = tsc;
    912                                 rv = 1;
    913                         }
    914                 }
    915         }
    916         return rv;
     940            if (!name[i])
     941                continue;
     942            if (ap_strcasecmp_match(x->sni_name, name[i]) == 0)
     943            {
     944                x->sc = tsc;
     945                rv = 1;
     946            }
     947        }
     948    }
     949    return rv;
    917950}
    918951
     
    953986 * hello function.
    954987 *
    955  * @param session the GnuTLS session
     988 * @param ctxt the mod_gnutls connection handle
    956989 *
    957990 * @return either the matching mod_gnutls server config, or `NULL`
    958991 */
    959 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
     992mgs_srvconf_rec *mgs_find_sni_server(mgs_handle_t *ctxt)
    960993{
    961     mgs_handle_t *ctxt = gnutls_session_get_ptr(session);
    962 
    963     char *sni_name = apr_palloc(ctxt->c->pool, DEFAULT_SNI_HOST_LEN);
    964     size_t sni_len = DEFAULT_SNI_HOST_LEN;
    965     unsigned int sni_type;
    966 
    967     /* Search for a DNS SNI element. Note that RFC 6066 prohibits more
    968      * than one server name per type. */
    969     int sni_index = -1;
    970     int rv = 0;
    971     do {
    972         /* The sni_index is incremented before each use, so if the
    973          * loop terminates with a type match we will have the right
    974          * one stored. */
    975         rv = gnutls_server_name_get(session, sni_name,
    976                                     &sni_len, &sni_type, ++sni_index);
    977         if (rv == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
    978         {
    979             ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_EGENERAL, ctxt->c,
    980                           "%s: no DNS SNI found (last index: %d).",
    981                           __func__, sni_index);
     994    if (ctxt->sni_name == NULL)
     995    {
     996        const char *sni_name = mgs_server_name_get(ctxt);
     997        if (sni_name != NULL)
     998            ctxt->sni_name = sni_name;
     999        else
    9821000            return NULL;
    983         }
    984     } while (sni_type != GNUTLS_NAME_DNS);
    985     /* The (rv == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) path inside
    986      * the loop above returns, so if we reach this point we have a DNS
    987      * SNI at the current index. */
    988 
    989     if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER)
    990     {
    991         /* Allocate a new buffer of the right size and retry */
    992         sni_name = apr_palloc(ctxt->c->pool, sni_len);
    993         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
    994                       "%s: reallocated SNI data buffer for %" APR_SIZE_T_FMT
    995                       " bytes.", __func__, sni_len);
    996         rv = gnutls_server_name_get(session, sni_name,
    997                                     &sni_len, &sni_type, sni_index);
    998     }
    999 
    1000     /* Unless there's a bug in the GnuTLS API only GNUTLS_E_IDNA_ERROR
    1001      * can occur here, but a catch all is safer and no more
    1002      * complicated. */
    1003     if (rv != GNUTLS_E_SUCCESS)
    1004     {
    1005         ap_log_cerror(APLOG_MARK, APLOG_INFO, APR_EGENERAL, ctxt->c,
    1006                       "%s: error while getting SNI DNS data: '%s' (%d).",
    1007                       __func__, gnutls_strerror(rv), rv);
    1008         return NULL;
    10091001    }
    10101002
    10111003    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
    10121004                  "%s: client requested server '%s'.",
    1013                   __func__, sni_name);
    1014     ctxt->sni_name = sni_name;
     1005                  __func__, ctxt->sni_name);
    10151006
    10161007    /* Search for vhosts matching connection parameters and the
     
    10201011        .ctxt = ctxt,
    10211012        .sc = NULL,
    1022         .sni_name = sni_name
     1013        .sni_name = ctxt->sni_name
    10231014    };
    1024     rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
     1015    int rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
    10251016    if (rv == 1) {
    10261017        return cbx.sc;
     
    10281019    return NULL;
    10291020}
     1021
     1022
     1023
     1024#ifdef ENABLE_EARLY_SNI
     1025/**
     1026 * Pre client hello hook function for GnuTLS that implements early SNI
     1027 * processing using `gnutls_ext_raw_parse()` (available since GnuTLS
     1028 * 3.6.3). Reading the SNI (if any) before GnuTLS processes the client
     1029 * hello allows loading virtual host settings that cannot be changed
     1030 * in the post client hello hook, including ALPN proposals (required
     1031 * for HTTP/2 support using the `Protocols` directive). In addition to
     1032 * ALPN this function configures the server credentials.
     1033 *
     1034 * The function signature is required by the GnuTLS API.
     1035 *
     1036 * @param session the current session
     1037 * @param htype handshake message type
     1038 * @param when hook position relative to GnuTLS processing
     1039 * @param incoming true if the message is incoming, for client hello
     1040 * that means the hook is running on the server
     1041 * @param msg raw message data
     1042 *
     1043 * @return `GNUTLS_E_SUCCESS` or a GnuTLS error code
     1044 */
     1045static int early_sni_hook(gnutls_session_t session,
     1046                          unsigned int htype,
     1047                          unsigned when,
     1048                          unsigned int incoming,
     1049                          const gnutls_datum_t *msg)
     1050{
     1051    if (!incoming)
     1052        return 0;
     1053
     1054    mgs_handle_t *ctxt = (mgs_handle_t *) gnutls_session_get_ptr(session);
     1055
     1056    /* This is a hook for pre client hello ONLY! */
     1057    if (htype != GNUTLS_HANDSHAKE_CLIENT_HELLO || when != GNUTLS_HOOK_PRE)
     1058    {
     1059        ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EINVAL, ctxt->c,
     1060                      "%s called outside pre client hello hook, this "
     1061                      "indicates a programming error!",
     1062                      __func__);
     1063        return GNUTLS_E_SELF_TEST_ERROR;
     1064    }
     1065
     1066    int ret = gnutls_ext_raw_parse(session, mgs_sni_ext_hook, msg,
     1067                                   GNUTLS_EXT_RAW_FLAG_TLS_CLIENT_HELLO);
     1068    if (ret == 0 && ctxt->sni_name != NULL)
     1069        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ctxt->c,
     1070                      "%s found SNI name: '%s'",
     1071                      __func__, ctxt->sni_name);
     1072
     1073    /* try to find a virtual host for that name */
     1074    mgs_srvconf_rec *tsc = mgs_find_sni_server(ctxt);
     1075    if (tsc != NULL)
     1076    {
     1077        /* Found a TLS vhost based on the SNI, configure the
     1078         * connection context. */
     1079        ctxt->sc = tsc;
     1080        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ctxt->c,
     1081                      "%s: Selected virtual host %s from early SNI, "
     1082                      "connection server is still %s.",
     1083                      __func__, ctxt->sc->s->server_hostname,
     1084                      ctxt->c->base_server->server_hostname);
     1085    }
     1086
     1087    reload_session_credentials(ctxt);
     1088
     1089    prepare_alpn_proposals(ctxt);
     1090
     1091    return ret;
     1092}
     1093#endif
     1094
     1095
    10301096
    10311097/**
     
    11191185        ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
    11201186                      "gnutls_priority_set failed!");
    1121     /* Set Handshake function */
     1187
     1188#ifdef ENABLE_EARLY_SNI
     1189    /* Pre-handshake hook, EXPERIMENTAL */
     1190    gnutls_handshake_set_hook_function(ctxt->session,
     1191                                       GNUTLS_HANDSHAKE_CLIENT_HELLO,
     1192                                       GNUTLS_HOOK_PRE, early_sni_hook);
     1193#else
     1194    prepare_alpn_proposals(ctxt);
     1195#endif
     1196
     1197    /* Post client hello hook (called after GnuTLS has parsed it) */
    11221198    gnutls_handshake_set_post_client_hello_function(ctxt->session,
    1123             mgs_select_virtual_server_cb);
     1199            post_client_hello_hook);
    11241200
    11251201    /* Set GnuTLS user pointer, so we can access the module session
     
    11271203    gnutls_session_set_ptr(ctxt->session, ctxt);
    11281204
    1129     /* If mod_gnutls is the TLS server, mgs_select_virtual_server_cb
    1130      * will load appropriate credentials during handshake. However,
     1205    /* If mod_gnutls is the TLS server, early_sni_hook (or
     1206     * post_client_hello_hook, if early SNI is not available) will
     1207     * load appropriate credentials during the handshake. However,
    11311208     * when handling a proxy backend connection, mod_gnutls acts as
    11321209     * TLS client and credentials must be loaded here. */
     
    11471224                          __func__, gnutls_strerror(err), err);
    11481225    }
    1149 
    1150     prepare_alpn_proposals(ctxt);
    11511226
    11521227    /* Initialize Session Cache */
  • src/mod_gnutls.c

    rdcc053e r0e55076  
    2222#include "gnutls_ocsp.h"
    2323#include "gnutls_util.h"
     24
     25#include <apr_strings.h>
    2426
    2527#ifdef APLOG_USE_MODULE
  • test/apache-conf/.gitignore

    rdcc053e r0e55076  
    11netns.conf
    22listen.conf
     3early_sni.conf
  • test/newtest

    rdcc053e r0e55076  
    77while [ "$confirmed" -eq 0 ]; do
    88
    9     read -e -p "describe your new test briefly: " -i "$tname" TEST_NAME
     9    if [ -z "${TEST_NAME}" ]; then
     10        read -e -p "describe your new test briefly: " -i "$tname" TEST_NAME
     11    fi
    1012
    1113    tname="${TEST_NAME// /_}"
     
    1315    newname="$(printf "%02d_%s" "${newnum}" "$tname")"
    1416
    15     read -p "your new test will be named tests/$newname.  OK [Y/n]? "
     17    read -p "your new test will be named tests/$newname. OK? [Y/n]"
    1618    if [ "$REPLY" == "" ] || [ "${REPLY/Y/y}" == "y" ]; then
    1719        confirmed=1
     
    2426newscript="test-${newname}.bash"
    2527echo '#!/bin/bash' >"${newscript}"
    26 echo "make -f TestMakefile t-${newnum}" >>"${newscript}"
     28echo "\${srcdir}/runtests t-${newnum}" >>"${newscript}"
    2729chmod a+x "${newscript}"
    2830
  • test/test_ca.mk

    rdcc053e r0e55076  
    2222        chmod 0700 $(dir $@)
    2323        certtool --outfile $@ --generate-privkey
     24
     25.PRECIOUS: %/secret.key
    2426
    2527%/secret.pgp.raw: %.uid %/secret.key
  • test/tests/28_HTTP2_support/apache.conf

    rdcc053e r0e55076  
    99</Location>
    1010
     11<IfDefine EXPECT_EARLY_SNI>
     12# Different ALPN settings on the same port work only with early SNI
     13<VirtualHost _default_:${TEST_PORT}>
     14        # No "Protocols" directive, HTTP/1.1 only
     15        ServerName              vhost.example.com
     16        GnuTLSEnable            On
     17        GnuTLSCertificateFile   server/x509.pem
     18        GnuTLSKeyFile           server/secret.key
     19        GnuTLSPriorities        NORMAL
     20</VirtualHost>
     21</IfDefine>
     22
    1123<VirtualHost _default_:${TEST_PORT}>
    1224        Protocols               h2 http/1.1
  • test/tests/30_ip_based_vhosts/apache.conf

    rdcc053e r0e55076  
    11Include ${srcdir}/base_apache.conf
    2 Include ${srcdir}/cgi_module.conf
    32
    43GnuTLSCache ${DEFAULT_CACHE}
     4
     5LoadModule      rewrite_module  ${AP_LIBEXECDIR}/mod_rewrite.so
    56
    67<VirtualHost ${VHOST1_IP}:${TEST_PORT}>
     
    1718        GnuTLSKeyFile           server/secret.key
    1819
    19         # CGI is allowed only on this virtual host, so a successful
    20         # request to a CGI script shows that the right server has been
    21         # selected.
    22         <Directory ${srcdir}/data>
    23                 Options +ExecCGI
    24         </Directory>
     20        # Use mod_rewrite to set up a path that will work only on this
     21        # virtual host
     22        RewriteEngine   On
     23        RewriteRule     "^/vhost/test\.txt$" "/test.txt" [PT]
    2524</VirtualHost>
  • test/tests/30_ip_based_vhosts/input

    rdcc053e r0e55076  
    1 GET /dump.cgi HTTP/1.1
     1GET /vhost/test.txt HTTP/1.1
    22Host: __HOSTNAME__
    33
  • test/tests/30_ip_based_vhosts/output

    rdcc053e r0e55076  
    1 HTTP/1.1 200 OK
     1Accept-Ranges: bytes
     2Content-Length: 5
    23Connection: close
    3 Transfer-Encoding: chunked
    44Content-Type: text/plain
    55
    6 54
    7 ----Certificate:----
    8 
    9 
    10 ----Verification Status:----
    11 NONE
    12 
    13 ----SubjectAltName:----
    14 
    15 
    16 
    17 0
    18 
     6test
    197- Peer has closed the GnuTLS connection
Note: See TracChangeset for help on using the changeset viewer.