Changeset ea9c699 in mod_gnutls


Ignore:
Timestamp:
Jan 28, 2019, 2:50:38 PM (7 months ago)
Author:
Fiona Klute <fiona.klute@…>
Branches:
debian/master
Children:
19e80a5
Parents:
8a264b0 (diff), 510764a (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:

New upstream version 0.9.0

Files:
68 added
27 deleted
72 edited
2 moved

Legend:

Unmodified
Added
Removed
  • CHANGELOG

    r8a264b0 rea9c699  
    1 **TODO:
    2 - Handle Unclean Shutdowns
    3 - make session cache use generic apache caches
     1** Version 0.9.0 (2019-01-23)
     2- Security fix: Refuse to send or receive any data over a failed TLS
     3  connection (commit 72b669eae8c45dda1850e8e5b30a97c918357b51). The
     4  previous behavior could lead to requests on reverse proxy TLS
     5  connections being sent in plain text, and might have allowed faking
     6  requests in plain text.
     7- Security fix: Reject HTTP requests if they try to access virtual
     8  hosts that do not match their TLS connections (commit
     9  de3fad3c12f53cdbf082ad675e4b10f521a02811). Additionally check if SNI
     10  and Host header match. Thanks to Krista Karppinen for contributing
     11  tests!
     12- OCSP stapling is now enabled by default, if possible. OCSP responses
     13  are updated regularly and stored in a cache separate from the
     14  session cache. The OCSP cache uses mod_socache_shmcb by default
     15  (if the module is loaded, no other configuration required).
     16- Session tickets are now enabled by default if using GnuTLS 3.6.4 or
     17  newer. GnuTLS 3.6.4 introduced automatic rotation for the used key,
     18  and TLS 1.3 takes care of other reasons not to use tickets while
     19  requiring them for session resumption. Note that there is currently
     20  no mechanism to synchronize ticket keys across a cluster of servers.
     21- The internal cache implementation has been replaced with
     22  mod_socache. Users may need to update their GnuTLSCache settings and
     23  load the appropriate socache modules.
     24- ALPN (required for HTTP/2) now works correctly with different
     25  "Protocols" directives between virtual hosts if building with GnuTLS
     26  3.6.3 or newer. Older versions require identical "Protocols"
     27  directives for overlapping virtual hosts. Thanks to Vincent Tamet
     28  for the bug report!
     29- ALPN is now supported for proxy connections, making HTTP/2 proxy
     30  connections using mod_proxy_http2 possible.
     31- GnuTLSPriorities is optional now and defaults to "NORMAL" if
     32  missing. The same applies to GnuTLSProxyPriorities (if TLS proxy is
     33  enabled).
     34- The manual is now built as a manual page, too, if pandoc is
     35  available.
     36- OpenPGP support has been removed.
     37- Don't require pem2openpgp for tests when building without MSVA
     38  support.
     39
     40** Version 0.8.4 (2018-04-13)
     41- Support Apache HTTPD 2.4.33 API for proxy TLS connections
     42- Support TLS for HTTP/2 connections with mod_http2
     43- Fix configuration of OCSP stapling callback
     44
     45** Version 0.8.3 (2017-10-20)
     46- Use GnuTLS' default DH parameters by default
     47- Handle long Server Name Indication data and gracefully ignore
     48  unknown SNI types
     49- Send SNI for proxy connections
     50- Deprecate OpenPGP support like GnuTLS did (will be removed
     51  completely in a future release)
     52- Do not announce session ticket support for proxy connections
     53- Minor documentation updates (SSL_CLIENT_I_DN, reference for SNI)
     54- Test suite: Simplify handling of proxy backend servers and OCSP
     55  responders
     56- Test suite: stability/compatibility fixes
     57
     58** Version 0.8.2 (2017-01-08)
     59- Test suite: Ensure CRLF line ends in HTTP headers
     60- Test suite, gen_ocsp_index.c: Handle serial as fixed order byte array
     61
     62** Version 0.8.1 (2016-12-20)
     63- Bugfix: Use APR_SIZE_T_FMT for portable apr_size_t formatting
     64
     65** Version 0.8.0 (2016-12-11)
     66- New: Support for OCSP stapling
     67- Bugfix: Access to DBM cache is locked using global mutex
     68  "gnutls-cache"
     69- Bugfix: GnuTLSSessionTickets is now disabled by default as described
     70  in the handbook
     71- Fixed memory leak while checking proxy backend certificate
     72- Fixed memory leaks in post_config
     73- Safely delete session ticket key (requires GnuTLS >= 3.4)
     74- Improved error handling in post_config hook
     75- Various handbook updates
     76- Internal API documentation can be generated using Doxygen
     77- Unused code has been removed (conditionals for GnuTLS 2.x and Apache
     78  versions before 2.2, internal Lua bytecode structure last used in
     79  2011).
     80- Test suite: Fixed locking for access to the PGP keyring of the test
     81  certificate authority
     82- mod_gnutls can be built using Clang (unsupported)
     83
     84** Version 0.7.5 (2016-05-28)
     85- Sunil Mohan Adapa reported retry loops during session shutdown in
     86  cleanup_gnutls_session() due to gnutls_bye() incorrectly returning
     87  GNUTLS_E_INTERRUPTED or GNUTLS_E_AGAIN. Setting the GnuTLS session
     88  errno in mgs_transport_write() fixes the problem.
     89- Import Daniel Kahn Gillmor's patches for GnuPG v2 support from the
     90  Debian package.
     91- Build system improvements that allow VPATH builds and get "make
     92  distcheck" to work
     93
     94** Version 0.7.4 (2016-04-13)
     95- Support SoftHSM 2 for PKCS #11 testing
     96- Increase verbosity of test logs
    497
    598** Version 0.7.3 (2016-01-12)
  • Makefile.am

    r8a264b0 rea9c699  
    1 AUTOMAKE_OPTIONS = foreign dist-bzip2
     1AUTOMAKE_OPTIONS = foreign dist-bzip2 no-dist-gzip
    22
    33EXTRA_DIST = m4/outoforder.m4 m4/apache.m4 \
    4                 m4/apr_memcache.m4 \
    54                m4/apache_test.m4  \
    65                include/mod_gnutls.h.in \
     
    87                NOTICE LICENSE
    98
     9AM_DISTCHECK_CONFIGURE_FLAGS = "--enable-vpath-install" \
     10        "SOFTHSM_LIB='$(SOFTHSM_LIB)'"
     11DISTCLEANFILES = config.nice
     12MOSTLYCLEANFILES = $(DX_CLEANFILES)
     13
    1014SUBDIRS = src test doc
    1115ACLOCAL_AMFLAGS = -I m4
     16
     17@DX_RULES@
  • README

    r8a264b0 rea9c699  
    1010Lead Maintainer:
    1111
    12   Thomas Klute <thomas2.klute@uni-dortmund.de>
     12  Fiona Klute <fiona.klute@gmx.de>
    1313
    1414Past maintainers and other contributors:
     
    2222-------------
    2323
    24  * GnuTLS          >= 3.1.4 <http://www.gnutls.org/> (3.2.* or newer preferred)
    25  * Apache HTTPD    >= 2.2 <http://httpd.apache.org/> (2.4.* preferred)
    26  * autotools, GNU make, & gcc
     24 * GnuTLS          >= 3.3 <https://www.gnutls.org/> (3.4 or newer recommended)
     25 * Apache HTTPD    >= 2.4.17 <https://httpd.apache.org/>
     26 * autotools, GNU make, & GCC
    2727 * libmsv          >= 0.1 (Optional, enable with ./configure --enable-msva)
    2828 * pandoc   (for documentation, optional)
     
    3232------------
    3333
    34  tar xzvf mod_gnutls-version.tar.gz
     34 tar xzvf mod_gnutls-version.tar.bz2
    3535 cd mod_gnutls-version/
    3636 autoreconf -fiv
     
    4444correctly, please see test/README for details.
    4545
     46If Doxygen is available, you can build internal API documentation
     47using "make doxygen-doc". The documentation will be placed in
     48doc/api/.
     49
    4650Configuration
    4751-------------
  • configure.ac

    r8a264b0 rea9c699  
    1 dnl
    2 AC_INIT(mod_gnutls, 0.7.3)
     1AC_INIT(mod_gnutls, 0.9.0)
    32OOO_CONFIG_NICE(config.nice)
    43MOD_GNUTLS_VERSION=AC_PACKAGE_VERSION
     
    1413AM_CONFIG_HEADER(include/mod_gnutls_config.h:config.in)
    1514
     15LT_INIT([disable-static])
     16
    1617AC_SUBST(MOD_GNUTLS_VERSION)
    1718
     
    2425AC_CONFIG_MACRO_DIR([m4])
    2526
    26 AP_VERSION=2.2.0
     27AP_VERSION=2.4.17
    2728CHECK_APACHE(,$AP_VERSION,
    2829    :,:,
     
    3031)
    3132
    32 PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 3.1.4])
     33dnl Maybe use the binaries for tests, too?
     34AC_ARG_WITH([gnutls-dev],
     35        AS_HELP_STRING([--with-gnutls-dev=DIR],
     36                [Use GnuTLS libraries from a development (git) tree. Use \
     37                this if you want to test mod_gnutls with the latest \
     38                GnuTLS code.]),
     39        [
     40                AS_IF([test -d "${with_gnutls_dev}" ],
     41                [
     42                        LIBGNUTLS_CFLAGS="-I${with_gnutls_dev}/lib/includes"
     43                        LIBGNUTLS_LIBS="-lgnutls -L${with_gnutls_dev}/lib/.libs -R${with_gnutls_dev}/lib/.libs"
     44                ],
     45                [AC_MSG_ERROR([--with-gnutls-dev=DIR requires a directory!])])
     46        ], [])
     47
     48PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 3.3.0])
    3349
    3450LIBGNUTLS_VERSION=`pkg-config --modversion gnutls`
     51
     52AC_ARG_ENABLE(vpath-install,
     53       AS_HELP_STRING([--enable-vpath-install],
     54               [Modify the Apache module directory provided by apxs to \
     55               follow --prefix, if necessary. Most users will not want this, \
     56               but it is required for VPATH builds including "make \
     57               distcheck".]),
     58       vpath_install=$enableval, vpath_install=no)
     59AM_CONDITIONAL([ENABLE_VPATH_INSTALL], [test "$vpath_install" = "yes"])
    3560
    3661AC_ARG_ENABLE(srp,
     
    4267AC_SEARCH_LIBS([gnutls_srp_server_get_username], [gnutls], [], [use_srp="no"])
    4368
    44 SRP_CFLAGS=""
     69GNUTLS_FEAT_CFLAGS=""
    4570if test "$use_srp" != "no"; then
    46         SRP_CFLAGS="-DENABLE_SRP=1"
    47 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)
    4888
    4989AC_ARG_ENABLE(strict,
     
    5494STRICT_CFLAGS=""
    5595if test "$use_strict" != "no"; then
    56         STRICT_CFLAGS="-Wall -Werror -Wextra"
     96        STRICT_CFLAGS="-Wall -Werror -Wextra -Wno-error=deprecated-declarations"
    5797fi
    5898
     
    73113        AS_IF([${FLOCK} --timeout 1 ${lockfile} true >&AS_MESSAGE_LOG_FD 2>&1],
    74114              [flock_works="yes"], [flock_works="no"])
     115        AC_MSG_RESULT([$flock_works])
     116        # Old versions of flock do not support --verbose. They fail
     117        # without executing the command but still return 0. Check for
     118        # this behavior by testing if the rm command was executed.
     119        AC_MSG_CHECKING([whether ${FLOCK} supports --verbose])
     120        testfile="$(mktemp)"
     121        AS_IF([${FLOCK} --verbose --timeout 1 ${lockfile} rm "${testfile}" \
     122                        >&AS_MESSAGE_LOG_FD 2>&1; test ! -e "${testfile}"],
     123              [flock_verbose="yes"; FLOCK="${FLOCK} --verbose"],
     124              [flock_verbose="no"; rm "${testfile}"])
     125        AC_MSG_RESULT([$flock_verbose])
    75126        rm "${lockfile}"
    76         AC_MSG_RESULT([$flock_works])
    77127      ],
    78128      [flock_works="no"])
     
    81131               [test "$enable_flock" = "no" || test "$flock_works" = "no"])
    82132
     133# openssl is needed as the responder for OCSP tests
     134AC_PATH_PROG([OPENSSL], [openssl], [no])
     135# OCSP checks with gnutls-cli from GnuTLS versions before 3.3.23,
     136# 3.4.12, or 3.5.1 (on the respective 3.x branch) fail if intermediate
     137# CAs cannot be status checked, even if there are no intermediate CAs
     138# like in the mod_gnutls test suite where end entity certificates are
     139# directly issued by a root CA.
     140AC_MSG_CHECKING([for gnutls-cli version supporting OCSP for EE under root CA])
     141AC_PREPROC_IFELSE(
     142        [AC_LANG_SOURCE([[#include "gnutls/gnutls.h"
     143                        #if GNUTLS_VERSION_NUMBER < 0x030317
     144                        #error
     145                        #elif GNUTLS_VERSION_NUMBER >= 0x030400 && GNUTLS_VERSION_NUMBER < 0x03040c
     146                        #error
     147                        #elif GNUTLS_VERSION_NUMBER == 0x030500
     148                        #error
     149                        #endif
     150                        ]])],
     151        [gnutls_ocsp_ok="yes"],
     152        [gnutls_ocsp_ok="no"],
     153)
     154AC_MSG_RESULT([$gnutls_ocsp_ok])
     155AM_CONDITIONAL([ENABLE_OCSP_TEST], [test "${OPENSSL}" != "no" && test "${gnutls_ocsp_ok}" = "yes"])
     156
    83157dnl Enable test namespaces? Default is "yes".
    84158AC_ARG_ENABLE(test-namespaces,
    85         AS_HELP_STRING([--disable-test-namespaces], [Disable use of network \
    86         namespaces to run tests in parallel (some architectures might not \
    87         support it)]),
     159        AS_HELP_STRING([--disable-test-namespaces], [Disable use of \
     160        namespaces for tests (limits parallelization)]),
    88161        [use_netns=$enableval], [use_netns=yes])
    89162
    90 # Check if "unshare" is available and has permission to create network
    91 # and user namespaces
     163# Check if "unshare" is available and has permission to create
     164# network, IPC, and user namespaces
    92165AC_PATH_PROG([UNSHARE], [unshare], [no])
    93166AS_IF([test "${UNSHARE}" != "no"],
    94167      [
    95         AC_MSG_CHECKING([for permission to create network and user namespaces])
    96         AS_IF([${UNSHARE} --net -r /bin/sh -c \
     168        AC_MSG_CHECKING([for permission to use namespaces])
     169        AS_IF([${UNSHARE} --net --ipc -r /bin/sh -c \
    97170                "ip link set up lo && ip addr show" >&AS_MESSAGE_LOG_FD 2>&1],
    98171              [unshare_works="yes"], [unshare_works="no"])
     
    108181# and test specific PID files if using namespaces, defaults otherwise.
    109182AS_IF([test "$use_netns" = "yes"],
    110       [MUTEX_TYPE="pthread"; PID_AFFIX="-\${TEST_NAME}"],
    111       [MUTEX_TYPE="default"; PID_AFFIX=""])
    112 AC_SUBST(MUTEX_TYPE)
     183      [MUTEX_CONF="Mutex pthread default"; PID_AFFIX="-\${TEST_NAME}"],
     184      [MUTEX_CONF=""; PID_AFFIX=""])
     185AC_SUBST(MUTEX_CONF)
    113186AC_SUBST(PID_AFFIX)
    114 AM_SUBST_NOTMAKE(MUTEX_TYPE)
     187AM_SUBST_NOTMAKE(MUTEX_CONF)
    115188AM_SUBST_NOTMAKE(PID_AFFIX)
    116189
     
    133206AC_MSG_RESULT($use_msva)
    134207
    135 have_apr_memcache=0
    136 CHECK_APR_MEMCACHE([have_apr_memcache=1], [have_apr_memcache=0])
    137 AC_SUBST(have_apr_memcache)
    138 
    139208# Building documentation requires pandoc, which in turn needs pdflatex
    140209# to build PDF output.
     
    144213        AC_PATH_PROG([PDFLATEX], [pdflatex], [no])
    145214        if test "$PDFLATEX" != "no"; then
    146                 build_doc=yes
     215                build_doc="html, manual page, pdf"
    147216        else
    148                 build_doc="html only"
     217                build_doc="html, manual page"
    149218        fi
    150219else
     
    169238AC_PATH_PROGS([HTTP_CLI], [curl wget], [no])
    170239
    171 MODULE_CFLAGS="${LIBGNUTLS_CFLAGS} ${SRP_CFLAGS} ${MSVA_CFLAGS} ${APR_MEMCACHE_CFLAGS} ${APXS_CFLAGS} ${AP_INCLUDES} ${APR_INCLUDES} ${APU_INCLUDES} ${STRICT_CFLAGS}"
    172 MODULE_LIBS="${APR_MEMCACHE_LIBS} ${LIBGNUTLS_LIBS}"
     240MODULE_CFLAGS="${LIBGNUTLS_CFLAGS} ${GNUTLS_FEAT_CFLAGS} ${MSVA_CFLAGS} ${APXS_CFLAGS} ${AP_INCLUDES} ${APR_INCLUDES} ${APU_INCLUDES} ${STRICT_CFLAGS}"
     241MODULE_LIBS="${LIBGNUTLS_LIBS}"
     242
     243AC_PATH_PROGS([SOFTHSM], [softhsm2-util softhsm], [no])
     244if test "${SOFTHSM}" != "no"; then
     245        softhsm_version=$(${SOFTHSM} --version)
     246        AS_VERSION_COMPARE([$(${SOFTHSM} --version)], [2.0.0],
     247                           [AC_SUBST(SOFTHSM_MAJOR_VERSION, [1])],
     248                           [AC_SUBST(SOFTHSM_MAJOR_VERSION, [2])],
     249                           [AC_SUBST(SOFTHSM_MAJOR_VERSION, [2])])
     250fi
     251AM_CONDITIONAL([HAVE_SOFTHSM], [test "${SOFTHSM}" != "no"])
     252AM_CONDITIONAL([HAVE_SOFTHSM1], [test "${SOFTHSM_MAJOR_VERSION}" = "1"])
     253AM_CONDITIONAL([HAVE_SOFTHSM2], [test "${SOFTHSM_MAJOR_VERSION}" = "2"])
    173254
    174255AC_SUBST(MODULE_CFLAGS)
     
    185266                      "[::1] 127.0.0.1". Note that IPv6 addresses must be \
    186267                      enclosed in square brackets.])
    187 AM_SUBST_NOTMAKE(TEST_IP)
     268
     269: ${TEST_LOCK_WAIT:="30"}
     270: ${TEST_QUERY_TIMEOUT:="30"}
     271AC_ARG_VAR([TEST_LOCK_WAIT], [Timeout in seconds to acquire locks for \
     272                             Apache instances in the test suite, or the \
     273                             previous instance to remove its PID file if \
     274                             flock is not used. Default is 30.])
     275AC_ARG_VAR([TEST_QUERY_TIMEOUT], [Timeout in seconds for HTTPS requests \
     276                                 sent using gnutls-cli in the test suite. \
     277                                 Default is 30.])
     278
     279dnl Allow user to set SoftHSM PKCS #11 module
     280AC_ARG_VAR([SOFTHSM_LIB], [Absolute path of the SoftHSM PKCS @%:@11 module to \
     281                          use. By default the test suite will search common \
     282                          library paths.])
    188283
    189284dnl Build list of "Listen" statements for Apache
    190 LISTEN_LIST="# Listen addresses for the test servers"
     285LISTEN_LIST="@%:@ Listen addresses for the test servers"
    191286for i in ${TEST_IP}; do
    192287        LISTEN_LIST="${LISTEN_LIST}
    193288Listen ${i}:\${TEST_PORT}"
    194289done
    195 dnl HTTP ports, only active if TEST_HTTP_PORT is defined
     290# Available extra ports, tests can "Define" variables of the listed
     291# names in their apache.conf to enable them.
     292for j in TEST_HTTP_PORT; do
    196293LISTEN_LIST="${LISTEN_LIST}
    197 <IfDefine TEST_HTTP_PORT>"
     294<IfDefine ${j}>"
    198295for i in ${TEST_IP}; do
    199296        LISTEN_LIST="${LISTEN_LIST}
    200         Listen ${i}:\${TEST_HTTP_PORT}"
     297        Listen ${i}:\${${j}}"
    201298done
    202299LISTEN_LIST="${LISTEN_LIST}
    203300</IfDefine>"
     301done
    204302AC_SUBST(LISTEN_LIST)
    205303AM_SUBST_NOTMAKE(LISTEN_LIST)
    206304
     305DX_DOXYGEN_FEATURE(ON)
     306DX_DOT_FEATURE(ON)
     307DX_HTML_FEATURE(ON)
     308DX_MAN_FEATURE(OFF)
     309DX_RTF_FEATURE(OFF)
     310DX_XML_FEATURE(OFF)
     311DX_PDF_FEATURE(OFF)
     312DX_PS_FEATURE(OFF)
     313DX_INIT_DOXYGEN([mod_gnutls], [doc/doxygen.conf], [doc/api])
     314
    207315AC_CONFIG_FILES([Makefile src/Makefile test/Makefile test/tests/Makefile \
    208                         doc/Makefile include/mod_gnutls.h \
    209                         test/proxy_backend.conf \
     316                        doc/Makefile doc/doxygen.conf include/mod_gnutls.h \
     317                        test/proxy_backend.conf test/ocsp_server.conf \
     318                        test/apache-conf/early_sni.conf \
    210319                        test/apache-conf/listen.conf \
    211320                        test/apache-conf/netns.conf])
     
    218327echo "   * Apache Modules directory:    ${AP_LIBEXECDIR}"
    219328echo "   * GnuTLS Library version:      ${LIBGNUTLS_VERSION}"
     329echo "   * CFLAGS for GnuTLS:           ${LIBGNUTLS_CFLAGS}"
     330echo "   * LDFLAGS for GnuTLS:  ${LIBGNUTLS_LIBS}"
    220331echo "   * SRP Authentication:  ${use_srp}"
    221332echo "   * MSVA Client Verification:    ${use_msva}"
     333echo "   * Early SNI:                   ${early_sni}"
    222334echo "   * Build documentation: ${build_doc}"
    223335echo ""
  • doc/Makefile.am

    r8a264b0 rea9c699  
    1 EXTRA_DIST = mod_gnutls_manual.mdwn
     1EXTRA_DIST = mod_gnutls_manual.mdwn mod_gnutls_manual.yaml.in
    22
    33if USE_PANDOC
    44html_DATA = mod_gnutls_manual.html
     5man3_MANS = mod_gnutls_manual.man
    56if USE_PDFLATEX
    67# pandoc && pdflatex
     
    1415endif
    1516
    16 MOSTLYCLEANFILES = $(html_DATA) $(pdf_DATA)
     17MOSTLYCLEANFILES = $(html_DATA) $(pdf_DATA) $(man3_MANS)
    1718
    18 # pdf_DATA will be empty if pandoc isn't available
    19 $(html_DATA) $(pdf_DATA): mod_gnutls_manual.mdwn
     19%.yaml: %.yaml.in
     20        sed -e s/__MOD_GNUTLS_VERSION__/@MOD_GNUTLS_VERSION@/ < $< > $@
     21
     22if USE_PANDOC
     23%.man: %.mdwn %.yaml
     24        $(PANDOC) --standalone -f markdown -t man -o $@ $^
     25
     26if USE_PDFLATEX
     27%.pdf: %.mdwn
     28        $(PANDOC) --toc -f markdown -o $@ $<
     29endif
     30endif
     31
     32%.html: %.mdwn
    2033if USE_PANDOC
    2134        $(PANDOC) --toc --standalone -f markdown -o $@ $<
  • doc/mod_gnutls_manual.mdwn

    r8a264b0 rea9c699  
    44
    55`mod_gnutls` is a module for the Apache web server that provides HTTPS
    6 (HTTP over Transport Layer Security (TLS) or the older Secure Sockets
    7 Layer (SSL)) using the GnuTLS library.  More information about the
    8 module can be found at [the project's website](https://mod.gnutls.org/).
     6(HTTP over Transport Layer Security (TLS)) using the GnuTLS library.
     7More information about the module can be found at
     8[the project's website](https://mod.gnutls.org/).
    99
    1010* * * * *
     
    4848    LoadModule gnutls_module modules/mod_gnutls.so
    4949
     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.
     67
     68During build `./configure` will report "Early SNI: yes" if your
     69version of GnuTLS is new enough.
     70
    5071* * * * *
    5172
     
    5374========================
    5475
    55 `GnuTLSEnable`
    56 --------------
     76General Options
     77---------------
     78
     79### GnuTLSEnable
    5780
    5881Enable GnuTLS for this virtual host
     
    6588This directive enables SSL/TLS Encryption for a Virtual Host.
    6689
    67 `GnuTLSCache`
    68 -------------
    69 
    70 Configure SSL Session Cache
    71 
    72     GnuTLSCache [dbm|gdbm|memcache|none] [PATH|SERVERLIST|-]
     90### GnuTLSCache
     91
     92Configure TLS Session Cache
     93
     94    GnuTLSCache (shmcb|dbm|memcache|...|none)[:PARAMETERS]
    7395
    7496Default: `GnuTLSCache none`\
    7597Context: server config
    7698
    77 This directive configures the SSL Session Cache for `mod_gnutls`.
    78 This could be shared between machines of different architectures.
    79 
    80 `dbm` (Requires Berkeley DBM)
    81 :   Uses the default Berkeley DB backend of APR DBM to cache SSL
    82     Sessions results.  The argument is a relative or absolute path to
    83     be used as the DBM Cache file. This is compatible with most
    84     operating systems, but needs the Apache Runtime to be compiled
    85     with Berkeley DBM support.
    86 
    87 `gdbm`
    88 :   Uses the GDBM backend of APR DBM to cache SSL Sessions results.
    89 
    90     The argument is a relative or absolute path to be used as the DBM Cache
    91     file.  This is the recommended option.
     99This directive configures the TLS Session Cache for `mod_gnutls`. This
     100could be shared between machines of different architectures. If the
     101selected cache implementation is not thread-safe, access is serialized
     102using the `gnutls-cache` mutex.
     103
     104Which cache implementations are available depends on your Apache
     105installation and configuration, `mod_gnutls` can use any socache
     106provider. In general you will need to load a `mod_socache_PROVIDER`
     107module. Common options are described below, please check the Apache
     108HTTPD documentation for details on available providers and their
     109configuration.
     110
     111`shmcb`
     112:   Uses a shared memory segment. This is a high performance local
     113    cache. The parameter is a relative or absolute path to be used if
     114    the local shared memory implementation requires one, followed by
     115    the cache size in bytes enclosed in parentheses.
     116
     117    Example: `shmcb:cache/gnutls_cache(65536)`
     118
     119`dbm`
     120:   Uses a DBM cache file. The parameter is a relative or absolute
     121    path to be used as the DBM cache file.
     122
     123    Example: `dbm:cache/gnutls_cache`
    92124
    93125`memcache`
    94 :   Uses a memcached server to cache the SSL Session.
    95 
    96     The argument is a space separated list of servers. If no port
    97     number is supplied, the default of 11211 is used.  This can be
    98     used to share a session cache between all servers in a cluster.
     126:   Uses memcached server(s) to cache TLS session data. The parameter
     127    is a comma separated list of servers (host:port). This can be used
     128    to share a session cache between all servers in a cluster.
     129
     130    Example: `memcache:memcache.example.com:12345,memcache2.example.com:12345`
    99131
    100132`none`
    101 :   Turns off all caching of SSL Sessions.
    102 
    103     This can significantly reduce the performance of `mod_gnutls` since
    104     even followup connections by a client must renegotiate parameters
    105     instead of reusing old ones.  This is the default, since it
    106     requires no configuration.
    107 
    108 `GnuTLSCacheTimeout`
    109 --------------------
    110 
    111 Timeout for SSL Session Cache expiration
     133:   Turns off all caching of TLS sessions.
     134
     135    This can significantly reduce the performance of `mod_gnutls`
     136    since even followup connections by a client must renegotiate
     137    parameters instead of reusing old ones. This is the default, since
     138    it requires no configuration.
     139
     140    Session tickets are an alternative to using a session cache,
     141    please see `GnuTLSSessionTickets`. Note that for TLS 1.3 GnuTLS
     142    supports resumption using session tickets only as of version
     143    3.6.4.
     144
     145### GnuTLSCacheTimeout
     146
     147Timeout for TLS Session Cache expiration
    112148
    113149    GnuTLSCacheTimeout SECONDS
    114150
    115151Default: `GnuTLSCacheTimeout 300`\
    116 Context: server config
    117 
    118 Sets the timeout for SSL Session Cache entries expiration.  This
    119 directive is valid even if Session Tickets are used, and indicates the
    120 expiration time of the ticket in seconds.
    121 
    122 `GnuTLSSessionTickets`
    123 ----------------------
     152Context: server config, virtual host
     153
     154Sets the expiration timeout for cached TLS sessions.
     155
     156### GnuTLSSessionTickets
    124157
    125158Enable Session Tickets for the server
     
    127160    GnuTLSSessionTickets [on|off]
    128161
    129 Default: `off`\
    130 Context: server config, virtual host
    131 
    132 To avoid storing data for TLS session resumption it is allowed to
    133 provide client with a ticket, to use on return.  Use for servers with
    134 limited storage, and don't combine with GnuTLSCache. For a pool of
    135 servers this option is not recommended since the tickets are unique
    136 for the issuing server only.
    137 
    138 
    139 `GnuTLSCertificateFile`
    140 -----------------------
    141 
    142 Set to the PEM Encoded Server Certificate
    143 
    144     GnuTLSCertificateFile FILEPATH
    145 
    146 Default: *none*\
    147 Context: server config, virtual host
    148 
    149 Takes an absolute or relative path to a PEM-encoded X.509 certificate to
    150 use as this Server's End Entity (EE) certificate. If you need to supply
    151 certificates for intermediate Certificate Authorities (iCAs), they
    152 should be listed in sequence in the file, from EE to the iCA closest to
    153 the root CA. Optionally, you can also include the root CA's certificate
    154 as the last certificate in the list.
    155 
    156 Since version 0.7 this can be a PKCS #11 URL.
    157 
    158 `GnuTLSKeyFile`
    159 ---------------
    160 
    161 Set to the PEM Encoded Server Private Key
    162 
    163     GnuTLSKeyFile FILEPATH
    164 
    165 Default: *none*\
    166 Context: server config, virtual host
    167 
    168 Takes an absolute or relative path to the Server Private Key. Set
    169 `GnuTLSPIN` if the key file is encrypted.
    170 
    171 Since version 0.7 this can be a PKCS #11 URL.
    172 
    173 **Security Warning:**\
    174 This private key must be protected. It is read while Apache is still
    175 running as root, and does not need to be readable by the nobody or
    176 apache user.
    177 
    178 `GnuTLSPGPCertificateFile`
    179 --------------------------
    180 
    181 Set to a base64 Encoded Server OpenPGP Certificate
    182 
    183     GnuTLSPGPCertificateFile FILEPATH
    184 
    185 Default: *none*\
    186 Context: server config, virtual host
    187 
    188 Takes an absolute or relative path to a base64 Encoded OpenPGP
    189 Certificate to use as this Server's Certificate.
    190 
    191 `GnuTLSPGPKeyFile`
    192 ------------------
    193 
    194 Set to the Server OpenPGP Secret Key
    195 
    196     GnuTLSPGPKeyFile FILEPATH
    197 
    198 Default: *none*\
    199 Context: server config, virtual host
    200 
    201 Takes an absolute or relative path to the Server Private Key. This key
    202 cannot currently be password protected.
    203 
    204 **Security Warning:**\
    205  This private key must be protected. It is read while Apache is still
    206 running as root, and does not need to be readable by the nobody or
    207 apache user.
    208 
    209 `GnuTLSClientVerify`
    210 --------------------
    211 
    212 Enable Client Certificate Verification\
     162Default: `on` with GnuTLS 3.6.4 and newer, `off` otherwise\
     163Context: server config, virtual host
     164
     165Session tickets allow TLS session resumption without session state
     166stored on the server, using encrypted tickets provided to the clients
     167instead. Tickets are an alternative to using a session cache, and
     168currently the only session resumption mechanism in TLS 1.3. For a pool
     169of servers this option is not recommended since the tickets are bound
     170to the issuing server only.
     171
     172If this option is set in the global configuration, virtual hosts
     173without a `GnuTLSSessionTickets` setting will use the global setting.
     174
     175*Warning:* With GnuTLS version before 3.6.4 the master key that
     176protects the tickets is generated only on server start, and there is
     177no mechanism to roll over the key. If session tickets are enabled it
     178is highly recommended to restart the server regularly to protect past
     179sessions in case an attacker gains access to server memory. GnuTLS
     1803.6.4 introduced an automatic TOTP-based key rollover, so this warning
     181does not apply any more and tickets are enabled by default.
     182
     183### GnuTLSClientVerify
     184
     185Enable Client Certificate Verification
    213186
    214187    GnuTLSClientVerify [ignore|request|require]
     
    217190Context: server config, virtual host, directory, .htaccess
    218191
    219 This directive controls the use of SSL Client Certificate
     192This directive controls the use of TLS Client Certificate
    220193Authentication. If used in the .htaccess context, it can force TLS
    221194re-negotiation.
    222195
    223196`ignore`
    224 :   `mod_gnutls` will ignore the contents of any SSL Client Certificates
     197:   `mod_gnutls` will ignore the contents of any TLS Client Certificates
    225198    sent. It will not request that the client sends a certificate.
    226199
     
    236209    environment variable will only be set to `SUCCESS`.
    237210
    238 `GnuTLSClientCAFile`
    239 --------------------
    240 
    241 Set to the PEM Encoded Certificate Authority Certificate
     211### GnuTLSDHFile
     212
     213Use the provided PKCS \#3 encoded Diffie-Hellman parameters
     214
     215    GnuTLSDHFile FILEPATH
     216
     217Default: *none*\
     218Context: server config, virtual host
     219
     220By default, `mod_gnutls` uses the DH parameters included with GnuTLS
     221corresponding to the security level of the configured private keys if
     222compiled with GnuTLS 3.5.6 or newer, and the ffdhe2048 DH group as
     223defined in RFC 7919, Appendix A.1 otherwise.
     224
     225If you need to use different DH parameters, you can provide a PEM file
     226containing them in PKCS \#3 encoding using this option. Please see the
     227"[Parameter
     228generation](https://gnutls.org/manual/html_node/Parameter-generation.html)"
     229section of the GnuTLS documentation for a short discussion of the
     230security implications.
     231
     232### GnuTLSPriorities
     233
     234Set the allowed protocol versions, ciphers, key exchange algorithms,
     235MACs and compression methods
     236
     237    GnuTLSPriorities NORMAL:+CIPHER_0:+CIPHER_1:...:+CIPHER_N
     238
     239Default: `NORMAL`\
     240Context: server config, virtual host
     241
     242Sets the allowed protocol version(s), ciphers, key exchange methods,
     243message authentication codes, and other TLS parameters for the server.
     244The parameter is a GnuTLS priority string as described in the
     245[the GnuTLS documentation](https://gnutls.org/manual/html_node/Priority-Strings.html).
     246
     247For example, to disable TLS 1.0 use `NORMAL:-VERS-TLS1.0`.
     248
     249### GnuTLSP11Module
     250
     251Load this PKCS #11 module.
     252
     253    GnuTLSP11Module PATH_TO_LIBRARY
     254
     255Default: *none*\
     256Context: server config
     257
     258Load this PKCS #11 provider module, instead of the system
     259defaults. May occur multiple times to load multiple modules.
     260
     261### GnuTLSPIN
     262
     263Set the PIN to be used to access encrypted key files or PKCS #11 objects.
     264
     265    GnuTLSPIN XXXXXX
     266
     267Default: *none*\
     268Context: server config, virtual host
     269
     270Takes a string to be used as a PIN for the protected objects in
     271a security module, or as a key to be used to decrypt PKCS #8, PKCS #12,
     272or openssl encrypted keys.
     273
     274### GnuTLSSRKPIN
     275
     276Set the SRK PIN to be used to access the TPM.
     277
     278    GnuTLSSRKPIN XXXXXX
     279
     280Default: *none*\
     281Context: server config, virtual host
     282
     283Takes a string to be used as a PIN for the protected objects in
     284the TPM module.
     285
     286### GnuTLSExportCertificates
     287
     288Export the PEM encoded certificates to CGIs
     289
     290    GnuTLSExportCertificates [off|on|SIZE]
     291
     292Default: `off`\
     293Context: server config, virtual host
     294
     295This directive configures exporting the full certificates of the
     296server and the client to CGI scripts via the `SSL_SERVER_CERT` and
     297`SSL_CLIENT_CERT` environment variables. The exported certificates
     298will be PEM-encoded, limited to the given size. The type of the
     299certificate will be exported in `SSL_SERVER_CERT_TYPE` and
     300`SSL_CLIENT_CERT_TYPE`.
     301
     302SIZE should be an integer number of bytes, or may be written with a
     303trailing `K` to indicate kibibytes.  `off` means the same thing as
     304`0`, in which case the certificates will not be exported to the
     305environment. `on` is an alias for `16K`. If a non-zero size is
     306specified for this directive, but a certificate is too large to fit in
     307the buffer, then the corresponding environment variable will contain
     308the fixed string `GNUTLS_CERTIFICATE_SIZE_LIMIT_EXCEEDED`.
     309
     310With GnuTLSExportCertificates enabled, `mod_gnutls` exports the same
     311environment variables to the CGI process as `mod_ssl`.
     312
     313X.509 Certificate Authentication
     314--------------------------------
     315
     316### GnuTLSCertificateFile
     317
     318Set the PEM encoded server certificate or certificate chain
     319
     320    GnuTLSCertificateFile FILEPATH
     321
     322Default: *none*\
     323Context: server config, virtual host
     324
     325FILEPATH is an absolute or relative path to a file containing the
     326PEM-encoded X.509 certificate to use as this Server's End Entity (EE)
     327certificate, and optionally those of the issuing Certificate
     328Authorities (CAs). If the file contains multiple certificates they
     329should be ordered from EE to the CA closest to the root CA (or the
     330root CA itself).
     331
     332Including at least the immediately issuing CA is highly recommended
     333because it is required for OCSP stapling.
     334
     335Since version 0.7 this can be a PKCS #11 URL instead of a file.
     336
     337On Linux and other Unix-like systems you can create the file with a
     338command like this (assuming "CA 1" issued the server certificate and
     339has been issued by "Root CA" itself):
     340
     341        $ cat server.pem ca-1.pem root-ca.pem >server-chain.pem
     342
     343### GnuTLSKeyFile
     344
     345Set to the PEM Encoded Server Private Key
     346
     347    GnuTLSKeyFile FILEPATH
     348
     349Default: *none*\
     350Context: server config, virtual host
     351
     352Takes an absolute or relative path to the Server Private Key. Set
     353`GnuTLSPIN` if the key file is encrypted.
     354
     355Since version 0.7 this can be a PKCS #11 URL.
     356
     357**Security Warning:**\
     358This private key must be protected. It is read while Apache is still
     359running as root, and does not need to be readable by the nobody or
     360apache user.
     361
     362### GnuTLSClientCAFile
     363
     364Set the PEM encoded Certificate Authority list to use for X.509 base
     365client authentication
    242366
    243367    GnuTLSClientCAFile FILEPATH
     
    250374This file may contain a list of trusted authorities.
    251375
    252 `GnuTLSPGPKeyringFile`
    253 ----------------------
    254 
    255 Set to a base64 Encoded key ring
    256 
    257     GnuTLSPGPKeyringFile FILEPATH
    258 
    259 Default: *none*\
    260 Context: server config, virtual host
    261 
    262 Takes an absolute or relative path to a base64 Encoded Certificate
    263 list (key ring) to use as a means of verification of Client
    264 Certificates.  This file should contain a list of trusted signers.
    265 
    266 `GnuTLSDHFile`
    267 --------------
    268 
    269 Set to the PKCS \#3 encoded Diffie Hellman parameters
    270 
    271     GnuTLSDHFile FILEPATH
    272 
    273 Default: *none*\
    274 Context: server config, virtual host
    275 
    276 Takes an absolute or relative path to a PKCS \#3 encoded DH
    277 parameters.Those are used when the DHE key exchange method is enabled.
    278 You can generate this file using `certtool --generate-dh-params --bits
    279 2048`.  If not set `mod_gnutls` will use the included parameters.
    280 
    281 `GnuTLSSRPPasswdFile`
    282 ---------------------
     376SRP Authentication
     377------------------
     378
     379### GnuTLSSRPPasswdFile
    283380
    284381Set to the SRP password file for SRP ciphersuites
     
    296393dependency to the SRP parameters.
    297394
    298 `GnuTLSSRPPasswdConfFile`
    299 -------------------------
     395### GnuTLSSRPPasswdConfFile
    300396
    301397Set to the SRP password.conf file for SRP ciphersuites
    302398
    303     GnuTLSSRPPasswdConfFile FILEPATH 
     399    GnuTLSSRPPasswdConfFile FILEPATH
    304400
    305401Default: *none*\
     
    312408(the verifiers depends on these parameters).
    313409
    314 `GnuTLSPriorities`
    315 ------------------
    316 
    317 Set the allowed ciphers, key exchange algorithms, MACs and compression
    318 methods
    319 
    320     GnuTLSPriorities NORMAL:+CIPHER_0:+CIPHER_1:...:+CIPHER_N
    321 
    322 Default: *none*\
    323 Context: server config, virtual host
    324 
    325 Takes a semi-colon separated list of ciphers, key exchange methods
    326 Message authentication codes and compression methods to enable.
    327 The allowed keywords are specified in the `gnutls_priority_init()`
    328 function of GnuTLS.
    329 
    330 Full details can be found at [the GnuTLS documentation](http://gnutls.org/manual/html_node/Priority-Strings.html#Priority-Strings).
    331 In brief you can specify a set of ciphersuites from the choices:
    332 
    333 `NONE`
    334 :   The empty list.
    335 
    336 `EXPORT`
    337 :   A list with all the supported cipher combinations
    338     including the `EXPORT` strength algorithms.
    339 
    340 `PERFORMANCE`
    341 :   A list with all the secure cipher combinations sorted in terms of performance.
    342 
    343 `NORMAL`
    344 :   A list with all the secure cipher combinations sorted
    345     with respect to security margin (subjective term).
    346 
    347 `SECURE`
    348 :   A list with all the secure cipher combinations including
    349     the 256-bit ciphers sorted with respect to security margin.
    350 
    351 Additionally you can add or remove algorithms using the `+` and `!`
    352 prefixes respectively.
    353 
    354 For example, in order to disable the `ARCFOUR` cipher from the `NORMAL` set
    355 you can use the string `NORMAL:!ARCFOUR-128`
    356 
    357 Other options such as the protocol version and the compression method
    358 can be specified using the `VERS-` and `COMP-` prefixes.
    359 
    360 So in order to remove or add a specific TLS version from the `NORMAL`
    361 set, use `NORMAL:!VERS-SSL3.0`.  And to enable zlib compression use
    362 `NORMAL:+COMP-DEFLATE`.
    363 
    364 
    365 However it is recommended not to add compression at this level.  With
    366 the `NONE` set, in order to be usable, you have to specify a complete
    367 set of combinations of protocol versions, cipher algorithms
    368 (`AES-128-CBC`), key exchange algorithms (`RSA`), message
    369 authentication codes (`SHA1`) and compression methods (`COMP-NULL`).
    370 
    371 You can find a list of all supported Ciphers, Versions, MACs, etc.  by
    372 running `gnutls-cli --list`.
    373 
    374 The special keyword `%COMPAT` will disable some security features such
    375 as protection against statistical attacks to ciphertext data in order to
    376 achieve maximum compatibility (some broken mobile clients need this).
    377 
    378 `GnuTLSP11Module`
    379 ------------------
    380 
    381 Load this PKCS #11 module.
    382 
    383     GnuTLSP11Module PATH_TO_LIBRARY
    384 
    385 Default: *none*\
    386 Context: server config
    387 
    388 Load this PKCS #11 provider module, instead of the system
    389 defaults. May occur multiple times to load multiple modules.
    390 
    391 `GnuTLSPIN`
    392 ------------------
    393 
    394 Set the PIN to be used to access encrypted key files or PKCS #11 objects.
    395 
    396     GnuTLSPIN XXXXXX
    397 
    398 Default: *none*\
    399 Context: server config, virtual host
    400 
    401 Takes a string to be used as a PIN for the protected objects in
    402 a security module, or as a key to be used to decrypt PKCS #8, PKCS #12,
    403 or openssl encrypted keys.
    404 
    405 `GnuTLSSRKPIN`
    406 ------------------
    407 
    408 Set the SRK PIN to be used to unlaccess the TPM.
    409 
    410     GnuTLSSRKPIN XXXXXX
    411 
    412 Default: *none*\
    413 Context: server config, virtual host
    414 
    415 Takes a string to be used as a PIN for the protected objects in
    416 the TPM module.
    417 
    418 `GnuTLSExportCertificates`
    419 --------------------------
    420 
    421 Export the PEM encoded certificates to CGIs
    422 
    423     GnuTLSExportCertificates [off|on|SIZE]
    424 
    425 Default: `off`\
    426 Context: server config, virtual host
    427 
    428 This directive configures exporting the full certificates of the
    429 server and the client to CGI scripts via the `SSL_SERVER_CERT` and
    430 `SSL_CLIENT_CERT` environment variables. The exported certificates
    431 will be PEM-encoded (if X.509) or ASCII-armored (if OpenPGP) up to the
    432 size given.  The type of the certificate will be exported in
    433 `SSL_SERVER_CERT_TYPE` and `SSL_CLIENT_CERT_TYPE`.
    434 
    435 SIZE should be an integer number of bytes, or may be written with a
    436 trailing `K` to indicate kibibytes.  `off` means the same thing as
    437 `0`, in which case the certificates will not be exported to the
    438 environment.  `on` is an alias for `16K`.  If a non-zero size is
    439 specified for this directive, but a certificate is too large to fit in
    440 the buffer, then the corresponding environment variable will contain
    441 the fixed string `GNUTLS_CERTIFICATE_SIZE_LIMIT_EXCEEDED`.
    442 
    443 With GnuTLSExportCertificates enabled, `mod_gnutls` exports the same
    444 environment variables to the CGI process as `mod_ssl`.
    445 
    446 
    447 `GnuTLSProxyEngine`
    448 --------------
     410TLS Proxy Configuration
     411-----------------------
     412
     413### GnuTLSProxyEngine
    449414
    450415Enable TLS proxy connections for this virtual host
     
    458423host.
    459424
    460 `GnuTLSProxyCAFile`
    461 --------------------
     425### GnuTLSProxyCAFile
    462426
    463427Set to the PEM encoded Certificate Authority Certificate
     
    474438always fail due to lack of a trusted CA.
    475439
    476 `GnuTLSProxyCRLFile`
    477 --------------------
     440### GnuTLSProxyCRLFile
    478441
    479442Set to the PEM encoded Certificate Revocation List
     
    488451back end servers. The file may contain a list of CRLs.
    489452
    490 `GnuTLSProxyCertificateFile`
    491 -----------------------
     453### GnuTLSProxyCertificateFile
    492454
    493455Set to the PEM encoded Client Certificate
     
    510472provide the matching private key.
    511473
    512 `GnuTLSProxyKeyFile`
    513 ---------------
     474### GnuTLSProxyKeyFile
    514475
    515476Set to the PEM encoded Private Key
     
    529490apache user.
    530491
    531 `GnuTLSProxyPriorities`
    532 ------------------
     492### GnuTLSProxyPriorities
    533493
    534494Set the allowed ciphers, key exchange algorithms, MACs and compression
     
    537497    GnuTLSProxyPriorities NORMAL:+CIPHER_0:+CIPHER_1:...:+CIPHER_N
    538498
    539 Default: *none*\
    540 Context: server config, virtual host
    541 
    542 This option is used to set the allowed ciphers, key exchange
    543 algorithms, MACs and compression methods for proxy connections. It
    544 takes the same parameters as `GnuTLSPriorities`. Required if
    545 `GnuTLSProxyEngine` is `On`.
     499Default: `NORMAL`\
     500Context: server config, virtual host
     501
     502Sets the allowed protocol version(s), ciphers, key exchange methods,
     503message authentication codes, and other TLS parameters for TLS proxy
     504connections. Like for `GnuTLSPriorities` the parameter is a GnuTLS
     505priority string as described in the
     506[the GnuTLS documentation](https://gnutls.org/manual/html_node/Priority-Strings.html).
     507
     508OCSP Stapling Configuration
     509---------------------------
     510
     511### GnuTLSOCSPStapling
     512
     513Enable OCSP stapling for this (virtual) host.
     514
     515    GnuTLSOCSPStapling [On|Off]
     516
     517Default: *on* if requirements are met, *off* otherwise\
     518Context: server config, virtual host
     519
     520OCSP stapling, formally known as the TLS Certificate Status Request
     521extension, allows the server to provide the client with a cached OCSP
     522response for its certificate during the handshake. With OCSP stapling
     523the client does not have to send an OCSP request to the issuer CA to
     524check the certificate status, which offers privacy and performance
     525advantages, and avoids the security issue of how to handle errors that
     526prevent the client from getting a response.
     527
     528Using OCSP stapling has a few requirements:
     529
     530* `GnuTLSCertificateFile` must contain the issuer CA certificate in
     531  addition to the server certificate so responses can be verified.
     532* The server certificate must either contain an OCSP access URI using
     533  HTTP, or `GnuTLSOCSPResponseFile` must be set.
     534* Caching OCSP responses requires a cache to store responses. If
     535  `mod_socache_shmcb` is loaded `mod_gnutls` can set up the cache
     536  automatically without additional configuration, see
     537  `GnuTLSOCSPCache`.
     538
     539Stapling is activated by default if these requirements are met. If
     540`GnuTLSOCSPStapling` is explicitly set to `on` unmet requirements are
     541an error.
     542
     543OCSP cache updates are serialized using the `gnutls-ocsp` mutex.
     544
     545### GnuTLSOCSPCache
     546
     547OCSP stapling cache configuration
     548
     549        GnuTLSOCSPCache (shmcb|memcache|...|none)[:PARAMETERS]
     550
     551Default: `shmcb:gnutls_ocsp_cache`\
     552Context: server config
     553
     554This directive configures the OCSP stapling cache, and uses the same
     555syntax as `GnuTLSOCSPCache`. Please check there for details.
     556
     557The default should be reasonable for most servers and requires
     558[mod\_socache\_shmcb](http://httpd.apache.org/docs/current/en/mod/mod_socache_shmcb.html)
     559to be loaded. Servers with very many virtual hosts may need to
     560increase the default cache size via the parameters string, those with
     561few virtual hosts and memory constraints could save a few KB by reducing
     562it. Note that `mod_socache_dbm` has a size constraint for entries that
     563is generally too small for OCSP responses.
     564
     565If the selected cache implementation is not thread-safe, access
     566is serialized using the `gnutls-ocsp-cache` mutex.
     567
     568### GnuTLSOCSPAutoRefresh
     569
     570Regularly refresh cached OCSP response independent of TLS handshakes?
     571
     572    GnuTLSOCSPAutoRefresh [On|Off]
     573
     574Default: *on*\
     575Context: server config, virtual host
     576
     577By default `mod_gnutls` will regularly refresh the cached OCSP
     578response for hosts that have OCSP stapling enabled, regardless of
     579whether it is used. This has advantages over updating the OCSP
     580response only if a TLS handshake needs it:
     581
     582* Updating the cached response before it expires can hide short
     583  unavailability of the OCSP responder, if a repeated request is
     584  successful before the cache expires (see below).
     585
     586* Handshakes are not slowed down by fetching responses.
     587
     588The interval to the next request is determined as follows: After a
     589successful OCSP request the next one is scheduled for a random period
     590between `GnuTLSOCSPFuzzTime` and half of it before
     591`GnuTLSOCSPCacheTimeout` expires. For example, if the cache timeout is
     5923600 seconds and the fuzz time 600 seconds, the next request will be
     593sent after 3000 to 3300 seconds. If the validity period of the
     594response expires before then, the selected interval is halved until it
     595is smaller than the time until expiry. If an OCSP request fails, it is
     596retried after `GnuTLSOCSPFailureTimeout`.
     597
     598Regularly updating the OCSP cache requires `mod_watchdog`,
     599`mod_gnutls` will fall back to updating the OCSP cache during
     600handshakes if `mod_watchdog` is not available or this option is set to
     601`Off`.
     602
     603### GnuTLSOCSPCheckNonce
     604
     605Check the nonce in OCSP responses?
     606
     607    GnuTLSOCSPCheckNonce [On|Off]
     608
     609Default: *on*\
     610Context: server config, virtual host
     611
     612Some CAs refuse to send nonces in their OCSP responses, probably
     613because that way they can cache responses. If your CA is one of them
     614you can use this flag to disable nonce verification. Note that
     615`mod_gnutls` will _send_ a nonce either way.
     616
     617### GnuTLSOCSPResponseFile
     618
     619Read the OCSP response for stapling from this file instead of sending
     620a request over HTTP.
     621
     622    GnuTLSOCSPResponseFile /path/to/response.der
     623
     624Default: *empty*\
     625Context: server config, virtual host
     626
     627The response file must be updated externally, for example using a cron
     628job. This option is an alternative to the server fetching OCSP
     629responses over HTTP. Reasons to use this option include:
     630
     631* Performing OCSP requests separate from the web server, to prevent slow
     632  responses from stalling handshakes.
     633* The issuer CA uses an access method other than HTTP.
     634* Testing
     635
     636You can use a GnuTLS `ocsptool` command like the following to create
     637and update the response file:
     638
     639    ocsptool --ask --nonce --load-issuer ca_cert.pem \
     640        --load-cert server_cert.pem --outfile ocsp_response.der
     641
     642Additional error checking is highly recommended. You may have to
     643remove the `--nonce` option if the OCSP responder of your CA does not
     644support nonces.
     645
     646### GnuTLSOCSPCacheTimeout
     647
     648Cache timeout for OCSP responses
     649
     650    GnuTLSOCSPCacheTimeout SECONDS
     651
     652Default: *3600*\
     653Context: server config, virtual host
     654
     655Cached OCSP responses will be refreshed after the configured number of
     656seconds. How long this timeout should reasonably be depends on your
     657CA, namely how often its OCSP responder is updated and how long
     658responses are valid. Note that a response will not be cached beyond
     659its lifetime as denoted in the `nextUpdate` field of the response.
     660
     661### GnuTLSOCSPFailureTimeout
     662
     663Wait this many seconds before retrying a failed OCSP request.
     664
     665    GnuTLSOCSPFailureTimeout SECONDS
     666
     667Default: *300*\
     668Context: server config, virtual host
     669
     670Retries of failed OCSP requests must be rate limited to avoid
     671overloading both the server using mod_gnutls and the CA's OCSP
     672responder. A shorter value increases the load on both sides, a longer
     673one means that stapling will remain disabled for longer after a failed
     674request.
     675
     676### GnuTLSOCSPFuzzTime
     677
     678Update the cached OCSP response up to this time before the cache expires
     679
     680    GnuTLSOCSPFuzzTime SECONDS
     681
     682Default: *larger of GnuTLSOCSPCacheTimeout / 8 and GnuTLSOCSPFailureTimeout \* 2*\
     683Context: server config, virtual host
     684
     685Refreshing the cached response before it expires hides short OCSP
     686responder unavailability. See `GnuTLSOCSPAutoRefresh` for how this
     687value is used, using at least twice `GnuTLSOCSPFailureTimeout` is
     688recommended.
     689
     690### GnuTLSOCSPSocketTimeout
     691
     692Timeout for TCP sockets used to send OCSP requests
     693
     694    GnuTLSOCSPFailureTimeout SECONDS
     695
     696Default: *6*\
     697Context: server config, virtual host
     698
     699Stalled OCSP requests must time out after a while to prevent stalling
     700the server too much. However, if the timeout is too short requests may
     701fail with a slow OCSP responder or high latency network
     702connection. This parameter allows you to adjust the timeout if
     703necessary.
     704
     705Note that this is not an upper limit for the completion of an OCSP
     706request but a socket timeout. The connection will time out if there is
     707no activity (successful send or receive) at all for the configured
     708time.
    546709
    547710* * * * *
     
    550713======================
    551714
    552 Simple Standard SSL Example
    553 ---------------------------
    554 
    555 The following is an example of standard SSL Hosting, using one IP
    556 Addresses for each virtual host
     715Minimal Example
     716---------------
     717
     718A minimal server configuration using mod_gnutls might look like this
     719(other than the default setup):
     720
     721     # Load mod_gnutls into Apache.
     722     LoadModule gnutls_module modules/mod_gnutls.so
     723
     724         Listen 192.0.2.1:443
     725
     726     <VirtualHost _default_:443>
     727             # Standard virtual host stuff
     728         DocumentRoot /www/site1.example.com/html
     729         ServerName site1.example.com:443
     730         
     731                 # Minimal mod_gnutls setup: enable, and set credentials
     732                 GnuTLSEnable on
     733         GnuTLSCertificateFile conf/tls/site1_cert_chain.pem
     734         GnuTLSKeyFile conf/tls/site1_key.pem
     735     </VirtualHost>
     736
     737This gives you an HTTPS site using the GnuTLS `NORMAL` set of
     738ciphersuites. OCSP stapling will be enabled if the server certificate
     739contains an OCSP URI, `conf/tls/site1_cert_chain.pem` contains the
     740issuer certificate in addition to the server's, and
     741[mod\_socache\_shmcb](http://httpd.apache.org/docs/current/en/mod/mod_socache_shmcb.html)
     742is loaded. With Gnutls 3.6.4 or newer session tickets are enabled,
     743too.
     744
     745Virtual Hosts with Server Name Indication
     746-----------------------------------------
     747
     748`mod_gnutls` supports Server Name Indication (SNI), as specified in
     749[RFC 6066, Section 3](https://tools.ietf.org/html/rfc6066#section-3).
     750This allows hosting many TLS websites with a single IP address, you
     751can just add virtual host configurations. All recent browsers support
     752this standard. Here is an example using SNI:
    557753
    558754     # Load the module into Apache.
    559755     LoadModule gnutls_module modules/mod_gnutls.so
    560      GnuTLSCache gdbm /var/cache/www-tls-cache
    561      GnuTLSCacheTimeout 500
    562      # With normal SSL Websites, you need one IP Address per-site.
    563      Listen 1.2.3.1:443
    564      Listen 1.2.3.2:443
    565      Listen 1.2.3.3:443
    566      Listen 1.2.3.4:443
    567      <VirtualHost 1.2.3.1:443>
    568      GnuTLSEnable on
    569      GnuTLSPriorities NONE:+AES-128-CBC:+3DES-CBC:+ARCFOUR-128:+RSA:+DHE-RSA:+DHE-DSS:+SHA1:+MD5:+COMP-NULL
    570      DocumentRoot /www/site1.example.com/html
    571      ServerName site1.example.com:443
    572      GnuTLSCertificateFile conf/ssl/site1.crt
    573      GnuTLSKeyFile conf/ss/site1.key
     756         # This example server uses session tickets, no cache.
     757     GnuTLSSessionTickets on
     758
     759     # SNI allows hosting multiple sites using one IP address. This
     760     # could also be 'Listen *:443', just like '*:80' is common for
     761     # non-HTTPS
     762     Listen 198.51.100.1:443
     763
     764     <VirtualHost _default_:443>
     765         GnuTLSEnable on
     766         DocumentRoot /www/site1.example.com/html
     767         ServerName site1.example.com:443
     768         GnuTLSCertificateFile conf/tls/site1.crt
     769         GnuTLSKeyFile conf/tls/site1.key
    574770     </VirtualHost>
    575      <VirtualHost 1.2.3.2:443>
    576      # This virtual host enables SRP authentication
    577      GnuTLSEnable on
    578      GnuTLSPriorities NORMAL:+SRP
    579      DocumentRoot /www/site2.example.com/html
    580      ServerName site2.example.com:443
    581      GnuTLSSRPPasswdFile conf/ssl/tpasswd.site2
    582      GnuTLSSRPPasswdConfFile conf/ssl/tpasswd.site2.conf
     771
     772     <VirtualHost _default_:443>
     773         GnuTLSEnable on
     774         DocumentRoot /www/site2.example.com/html
     775         ServerName site2.example.com:443
     776         GnuTLSCertificateFile conf/tls/site2.crt
     777         GnuTLSKeyFile conf/tls/site2.key
    583778     </VirtualHost>
    584      <VirtualHost 1.2.3.3:443>
    585      # This server enables SRP, OpenPGP and X.509 authentication.
    586      GnuTLSEnable on
    587      GnuTLSPriorities NORMAL:+SRP:+SRP-RSA:+SRP-DSS
    588      DocumentRoot /www/site3.example.com/html
    589      ServerName site3.example.com:443
    590      GnuTLSCertificateFile conf/ssl/site3.crt
    591      GnuTLSKeyFile conf/ss/site3.key
    592      GnuTLSClientVerify ignore
    593      GnuTLSPGPCertificateFile conf/ss/site3.pub.asc
    594      GnuTLSPGPKeyFile conf/ss/site3.sec.asc
    595      GnuTLSSRPPasswdFile conf/ssl/tpasswd.site3
    596      GnuTLSSRPPasswdConfFile conf/ssl/tpasswd.site3.conf
     779
     780     <VirtualHost _default_:443>
     781         GnuTLSEnable on
     782         DocumentRoot /www/site3.example.com/html
     783         ServerName site3.example.com:443
     784         GnuTLSCertificateFile conf/tls/site3.crt
     785         GnuTLSKeyFile conf/tls/site3.key
     786         # Enable HTTP/2. With GnuTLS before version 3.6.3 all
     787         # virtual hosts in this example would have to share this
     788         # directive to work correctly.
     789         Protocols h2 http/1.1
    597790     </VirtualHost>
    598      <VirtualHost 1.2.3.4:443>
    599      GnuTLSEnable on
    600      # %COMPAT disables some security features to enable maximum compatibility with clients.
    601      GnuTLSPriorities NONE:+AES-128-CBC:+ARCFOUR-128:+RSA:+SHA1:+MD5:+COMP-NULL:%COMPAT
    602      DocumentRoot /www/site4.example.com/html
    603      ServerName site4.example.com:443
    604      GnuTLSCertificateFile conf/ssl/site4.crt
    605      GnuTLSKeyFile conf/ss/site4.key
    606      </VirtualHost>
    607 
    608 Server Name Indication Example
    609 ------------------------------
    610 
    611 `mod_gnutls` can also use "Server Name Indication", as specified in
    612 RFC 3546.  This allows hosting many SSL Websites, with a Single IP
    613 Address.  Currently all the recent browsers support this
    614 standard. Here is an example, using SNI: ` `
    615 
     791
     792Virtual Hosts without SNI
     793-------------------------
     794
     795If you need to support clients that do not use SNI, you have to use a
     796unique IP address/port combination for each virtual host. In this
     797example all virtual hosts use the default port for HTTPS (443) and
     798different IP addresses.
    616799
    617800     # Load the module into Apache.
    618801     LoadModule gnutls_module modules/mod_gnutls.so
    619      # With normal SSL Websites, you need one IP Address per-site.
    620      Listen 1.2.3.1:443
    621      # This could also be 'Listen *:443',
    622      # just like '*:80' is common for non-https
    623      # No caching. Enable session tickets. Timeout is still used for
    624      # ticket expiration.
    625      GnuTLSCacheTimeout 600
    626      # This tells apache, that for this IP/Port combination, we want to use
    627      # Name Based Virtual Hosting. In the case of Server Name Indication,
    628      # it lets mod_gnutls pick the correct Server Certificate.
    629      NameVirtualHost 1.2.3.1:443
    630      <VirtualHost 1.2.3.1:443>
    631      GnuTLSEnable on
    632      GnuTLSSessionTickets on
    633      GnuTLSPriorities NORMAL
    634      DocumentRoot /www/site1.example.com/html
    635      ServerName site1.example.com:443
    636      GnuTLSCertificateFile conf/ssl/site1.crt
    637      GnuTLSKeyFile conf/ss/site1.key
     802         # This example server uses a session cache.
     803     GnuTLSCache dbm:/var/cache/www-tls-cache
     804     GnuTLSCacheTimeout 1200
     805
     806     # Without SNI you need one IP Address per site. The IP addresses
     807         # are listed separately for clarity, you could also use "Listen 443"
     808         # to use that port on all available IP addresses.
     809     Listen 192.0.2.1:443
     810     Listen 192.0.2.2:443
     811     Listen 192.0.2.3:443
     812
     813     <VirtualHost 192.0.2.1:443>
     814         GnuTLSEnable on
     815         GnuTLSPriorities SECURE128
     816         DocumentRoot /www/site1.example.com/html
     817         ServerName site1.example.com:443
     818         GnuTLSCertificateFile conf/tls/site1.crt
     819         GnuTLSKeyFile conf/tls/site1.key
    638820     </VirtualHost>
    639      <VirtualHost 1.2.3.1:443>
    640      GnuTLSEnable on
    641      GnuTLSPriorities NORMAL
    642      DocumentRoot /www/site2.example.com/html
    643      ServerName site2.example.com:443
    644      GnuTLSCertificateFile conf/ssl/site2.crt
    645      GnuTLSKeyFile conf/ss/site2.key
     821
     822     <VirtualHost 192.0.2.2:443>
     823         # This virtual host enables SRP authentication
     824         GnuTLSEnable on
     825         GnuTLSPriorities NORMAL:+SRP
     826         DocumentRoot /www/site2.example.com/html
     827         ServerName site2.example.com:443
     828         GnuTLSSRPPasswdFile conf/tls/tpasswd.site2
     829         GnuTLSSRPPasswdConfFile conf/tls/tpasswd.site2.conf
    646830     </VirtualHost>
    647      <VirtualHost 1.2.3.1:443>
    648      GnuTLSEnable on
    649      GnuTLSPriorities NORMAL
    650      DocumentRoot /www/site3.example.com/html
    651      ServerName site3.example.com:443
    652      GnuTLSCertificateFile conf/ssl/site3.crt
    653      GnuTLSKeyFile conf/ss/site3.key
     831
     832     <VirtualHost 192.0.2.3:443>
     833         # This server enables SRP and X.509 authentication.
     834         GnuTLSEnable on
     835         GnuTLSPriorities NORMAL:+SRP:+SRP-RSA:+SRP-DSS
     836         DocumentRoot /www/site3.example.com/html
     837         ServerName site3.example.com:443
     838         GnuTLSCertificateFile conf/tls/site3.crt
     839         GnuTLSKeyFile conf/tls/site3.key
     840         GnuTLSClientVerify ignore
     841         GnuTLSSRPPasswdFile conf/tls/tpasswd.site3
     842         GnuTLSSRPPasswdConfFile conf/tls/tpasswd.site3.conf
    654843     </VirtualHost>
    655      <VirtualHost 1.2.3.1:443>
    656      GnuTLSEnable on
    657      GnuTLSPriorities NORMAL
    658      DocumentRoot /www/site4.example.com/html
    659      ServerName site4.example.com:443
    660      GnuTLSCertificateFile conf/ssl/site4.crt
    661      GnuTLSKeyFile conf/ss/site4.key
    662      </VirtualHost>
    663 
    664 
    665 * * * * *
    666 
    667 Performance Issues
    668 ==================
    669 
    670 `mod_gnutls` by default uses conservative settings for the server.
    671 You can fine tune the configuration to reduce the load on a busy
    672 server.  The following examples do exactly this:
    673 
     844
     845OCSP Stapling Example
     846---------------------
     847
     848This is an example with a customized OCSP stapling configuration. What
     849is a resonable cache timeout varies depending on how long your CA's
     850OCSP responses are valid. Some CAs provide responses that are valid
     851for multiple days, in that case timeout and fuzz time could be
     852significantly larger.
    674853
    675854     # Load the module into Apache.
    676855     LoadModule gnutls_module modules/mod_gnutls.so
    677      # Using 4 memcache servers to distribute the SSL Session Cache.
    678      GnuTLSCache memcache "mc1.example.com mc2.example.com mc3.example.com mc4.example.com"
    679      GnuTLSCacheTimeout 600
    680      Listen 1.2.3.1:443
    681      NameVirtualHost 1.2.3.1:443
    682      <VirtualHost 1.2.3.1:443>
    683      GnuTLSEnable on
    684      # Here we disable the Perfect forward secrecy ciphersuites (DHE)
    685      # and disallow AES-256 since AES-128 is just fine.
    686      GnuTLSPriorities NORMAL:!DHE-RSA:!DHE-DSS:!AES-256-CBC:%COMPAT
    687      DocumentRoot /www/site1.example.com/html
    688      ServerName site1.example.com:443
    689      GnuTLSCertificateFile conf/ssl/site1.crt
    690      GnuTLSKeyFile conf/ss/site1.key
    691      </VirtualHost>
    692      <VirtualHost 1.2.3.1:443>
    693      GnuTLSEnable on
    694      # Here we instead of disabling the DHE ciphersuites we use
    695      # Diffie Hellman parameters of smaller size than the default (2048 bits).
    696      # Using small numbers from 768 to 1024 bits should be ok once they are
    697      # regenerated every few hours.
    698      # Use "certtool --generate-dh-params --bits 1024" to get those
    699      GnuTLSDHFile /etc/apache2/dh.params
    700      GnuTLSPriorities NORMAL:!AES-256-CBC:%COMPAT
    701      DocumentRoot /www/site2.example.com/html
    702      ServerName site2.example.com:443
    703      GnuTLSCertificateFile conf/ssl/site2.crt
    704      GnuTLSKeyFile conf/ss/site2.key
     856         # A 64K cache is more than enough for one response
     857     GnuTLSOCSPCache shmcb:ocsp_cache(65536)
     858
     859     Listen 192.0.2.1:443
     860
     861     <VirtualHost _default_:443>
     862         GnuTLSEnable           On
     863         DocumentRoot           /www/site1.example.com/html
     864         ServerName             site1.example.com:443
     865         GnuTLSCertificateFile  conf/tls/site1_cert_chain.pem
     866         GnuTLSKeyFile          conf/tls/site1_key.pem
     867         GnuTLSOCSPStapling     On
     868                 # The cached OCSP response is kept for up to 4 hours,
     869                 # with updates scheduled every 3 to 3.5 hours.
     870         GnuTLSOCSPCacheTimeout 21600
     871                 GnuTLSOCSPFuzzTime     3600
    705872     </VirtualHost>
    706873
     
    799966-----------------
    800967
    801 The SSL or TLS cipher suite name
     968The distinguished name of the issuer of the client's certificate in
     969RFC2253 format.
    802970
    803971`SSL_CLIENT_S_AN%`
     
    8351003------------------
    8361004
    837 The PEM-encoded (X.509) or ASCII-armored (OpenPGP) server certificate
    838 (see the `GnuTLSExportCertificates` directive).
     1005The PEM-encoded (X.509) server certificate (see the
     1006`GnuTLSExportCertificates` directive).
    8391007
    8401008`SSL_SERVER_CERT_TYPE`
    8411009----------------------
    8421010
    843 The certificate type can be `X.509` or `OPENPGP`.
     1011The certificate type will be `X.509`.
    8441012
    8451013`SSL_CLIENT_CERT`
    8461014------------------
    8471015
    848 The PEM-encoded (X.509) or ASCII-armored (OpenPGP) client certificate
    849 (see the `GnuTLSExportCertificates` directive).
     1016PEM-encoded (X.509) client certificate, if any (see the
     1017`GnuTLSExportCertificates` directive).
    8501018
    8511019`SSL_CLIENT_CERT_TYPE`
    8521020----------------------
    8531021
    854 The certificate type can be `X.509` or `OPENPGP`.
     1022The certificate type will be `X.509`, if any.
  • include/mod_gnutls.h.in

    r8a264b0 rea9c699  
    1 /**
     1/*
    22 *  Copyright 2004-2005 Paul Querna
    33 *  Copyright 2014 Nikos Mavrogiannopoulos
    4  *  Copyright 2015 Thomas Klute
     4 *  Copyright 2015-2018 Fiona Klute
    55 *
    66 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    1515 *  See the License for the specific language governing permissions and
    1616 *  limitations under the License.
    17  *
    1817 */
    1918
     
    2726#include "http_log.h"
    2827#include "apr_buckets.h"
    29 #include "apr_strings.h"
    3028#include "apr_tables.h"
    3129#include "ap_release.h"
    32 #include "apr_fnmatch.h"
    3330/* GnuTLS Library Headers */
    3431#include <gnutls/gnutls.h>
    35 #if GNUTLS_VERSION_MAJOR == 2
    36 #include <gnutls/extra.h>
    37 #endif
    3832#include <gnutls/abstract.h>
    39 #include <gnutls/openpgp.h>
    4033#include <gnutls/x509.h>
    4134
    4235#ifndef __mod_gnutls_h_inc
    4336#define __mod_gnutls_h_inc
    44 
    45 #define HAVE_APR_MEMCACHE    @have_apr_memcache@
    4637
    4738extern module AP_MODULE_DECLARE_DATA gnutls_module;
     
    6051#define MOD_GNUTLS_DEBUG @OOO_MAINTAIN@
    6152
    62 /*
    63  * Recent Versions of 2.1 renamed several hooks.
    64  * This allows us to compile on 2.0.xx
    65  */
    66 #if AP_SERVER_MINORVERSION_NUMBER >= 2 || (AP_SERVER_MINORVERSION_NUMBER == 1 && AP_SERVER_PATCHLEVEL_NUMBER >= 3)
    67         #define USING_2_1_RECENT 1
    68 #else
    69         #define USING_2_1_RECENT 0
     53/* Compile support for early SNI? */
     54#if @ENABLE_EARLY_SNI@ == 1
     55#define ENABLE_EARLY_SNI
    7056#endif
    7157
    72 /* mod_gnutls Cache Types */
    73 typedef enum {
    74         /* No Cache */
    75     mgs_cache_none,
    76         /* Use Old Berkley DB */
    77     mgs_cache_dbm,
    78         /* Use Gnu's version of Berkley DB */
    79     mgs_cache_gdbm,
    80 #if HAVE_APR_MEMCACHE
    81         /* Use Memcache */
    82     mgs_cache_memcache,
    83 #endif
    84     mgs_cache_unset
    85 } mgs_cache_e;
     58/** Name of the module-wide singleton watchdog */
     59#define MGS_SINGLETON_WATCHDOG "_mod_gnutls_singleton_"
     60
     61
     62/* Internal cache data, defined in gnutls_cache.h */
     63typedef struct mgs_cache* mgs_cache_t;
    8664
    8765typedef enum {
     
    9573typedef struct {
    9674    int client_verify_mode;
    97     const char* lua_bytecode;
    98     apr_size_t lua_bytecode_len;
    9975} mgs_dirconf_rec;
     76
     77
     78/* Internal per-vhost config for OCSP, defined in gnutls_ocsp.h */
     79typedef struct mgs_ocsp_data* mgs_ocsp_data_t;
    10080
    10181
    10282/* The maximum number of certificates to send in a chain */
    10383#define MAX_CHAIN_SIZE 8
    104 /* The maximum number of SANs to read from a x509 certificate */
    105 #define MAX_CERT_SAN 5
    106 
    107 /* Server Configuration Record */
     84
     85/** Server Configuration Record */
    10886typedef struct {
     87    /** Server this mod_gnutls configuration is for */
     88    server_rec* s;
     89
    10990    /* --- Configuration values --- */
    11091        /* Is the module enabled? */
     
    11293        /* Is mod_proxy enabled? */
    11394    int proxy_enabled;
    114         /* A Plain HTTP request */
    115     int non_ssl_request;
    11695
    11796    /* List of PKCS #11 provider modules to load, only valid in the
     
    129108    char *x509_ca_file;
    130109
    131     char *pgp_cert_file;
    132     char *pgp_key_file;
    133     char *pgp_ring_file;
    134 
    135110    char *dh_file;
    136111
     
    143118        /* Cache timeout value */
    144119    int cache_timeout;
    145         /* Chose Cache Type */
    146     mgs_cache_e cache_type;
    147     const char* cache_config;
     120    /* Enable cache */
     121    unsigned char cache_enable : 2;
     122    /* Internal cache data */
     123    mgs_cache_t cache;
    148124
    149125        /* GnuTLS uses Session Tickets */
    150126    int tickets;
    151 
    152     /* --- Things initialized at _child_init --- */
    153127
    154128    /* x509 Certificate Structure */
     
    171145     * connections */
    172146    gnutls_anon_client_credentials_t anon_client_creds;
    173         /* Current x509 Certificate CN [Common Name] */
    174     char* cert_cn;
    175         /* Current x509 Certificate SAN [Subject Alternate Name]s*/
    176     char* cert_san[MAX_CERT_SAN];
    177147        /* An x509 Certificate Chain */
    178148    gnutls_pcert_st *certs_x509_chain;
     
    183153        /* Current x509 Certificate Private Key */
    184154    gnutls_privkey_t privkey_x509;
    185 
    186         /* OpenPGP Certificate */
    187     gnutls_pcert_st *cert_pgp;
    188     gnutls_openpgp_crt_t *cert_crt_pgp;
    189 
    190         /* OpenPGP Certificate Private Key */
    191     gnutls_privkey_t privkey_pgp;
    192 #if GNUTLS_VERSION_NUMBER < 0x030312
    193     /* Internal structure for the OpenPGP private key, used in the
    194      * workaround for a bug in gnutls_privkey_import_openpgp_raw that
    195      * frees memory that is still needed. DO NOT USE for any other
    196      * purpose. */
    197     gnutls_openpgp_privkey_t privkey_pgp_internal;
    198 #endif
    199155
    200156    /* Export full certificates to CGI environment: */
     
    206162        /* A list of CA Certificates */
    207163    gnutls_x509_crt_t *ca_list;
    208         /* OpenPGP Key Ring */
    209     gnutls_openpgp_keyring_t pgp_list;
    210164        /* CA Certificate list size */
    211165    unsigned int ca_list_size;
     
    214168        /* Client Certificate Verification Method */
    215169    mgs_client_verification_method_e client_verify_method;
    216         /* Last Cache timestamp */
    217     apr_time_t last_cache_check;
     170
     171    /* Enable OCSP stapling */
     172    unsigned char ocsp_staple;
     173    /* Automatically refresh cached OCSP response? */
     174    unsigned char ocsp_auto_refresh;
     175    /* Check nonce in OCSP responses? */
     176    unsigned char ocsp_check_nonce;
     177    /* Read OCSP response for stapling from this file instead of
     178     * sending a request over HTTP */
     179    char *ocsp_response_file;
     180    /* Internal OCSP data for this server */
     181    mgs_ocsp_data_t ocsp;
     182    /* Mutex to prevent parallel OCSP requests */
     183    apr_global_mutex_t *ocsp_mutex;
     184    /* Internal OCSP cache data */
     185    mgs_cache_t ocsp_cache;
     186    /* Cache timeout for OCSP responses. Note that the nextUpdate
     187     * field of the response takes precedence if shorter. */
     188    apr_interval_time_t ocsp_cache_time;
     189    /* If an OCSP request fails wait this long before trying again. */
     190    apr_interval_time_t ocsp_failure_timeout;
     191    /** How long before a cached OCSP response expires should it be
     192     * updated? During configuration parsing this is set to the
     193     * maximum, during post configuration the value will be set to
     194     * half that. After each update the interval to for the next one
     195     * is choosen randomly as `ocsp_fuzz_time + ocsp_fuzz_time *
     196     * RANDOM` with `0 <= RANDOM <= 1`. */
     197    apr_interval_time_t ocsp_fuzz_time;
     198    /* Socket timeout for OCSP requests */
     199    apr_interval_time_t ocsp_socket_timeout;
     200
     201    /** This module's singleton watchdog, used for async OCSP cache
     202     * updates. */
     203    struct mgs_watchdog *singleton_wd;
    218204} mgs_srvconf_rec;
    219205
     
    224210} mgs_char_buffer_t;
    225211
    226 /* GnuTLS Handle */
     212/** GnuTLS connection handle */
    227213typedef struct {
    228214        /* Server configuration record */
     
    236222        /* GnuTLS Session handle */
    237223    gnutls_session_t session;
     224    /** Server name requested via SNI if any, or NULL. */
     225    const char *sni_name;
    238226        /* module input status */
    239227    apr_status_t input_rc;
     
    262250        /* Output length */
    263251    apr_size_t output_length;
    264         /* General Status */
     252    /** Connection status: 0 before (re-)handshake, 1 when up, -1 on
     253     * error (checks use status < 0 or status > 0) */
    265254    int status;
    266255} mgs_handle_t;
     
    273262apr_status_t apr_signal_block(int signum);
    274263
    275  /* Proxy Support */
     264/* Proxy Support */
    276265/* An optional function which returns non-zero if the given connection
    277266is using SSL/TLS. */
    278267APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *));
     268/* The ssl_var_lookup() optional function retrieves SSL environment
     269 * variables. */
     270APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup,
     271                        (apr_pool_t *, server_rec *,
     272                         conn_rec *, request_rec *,
     273                         char *));
    279274/* The ssl_proxy_enable() and ssl_engine_disable() optional functions
    280275 * are used by mod_proxy to enable use of SSL for outgoing
     
    282277APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));
    283278APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));
     279APR_DECLARE_OPTIONAL_FN(int, ssl_engine_set, (conn_rec *,
     280                                              ap_conf_vector_t *,
     281                                              int proxy, int enable));
     282mgs_handle_t* get_effective_gnutls_ctxt(conn_rec *c);
    284283int ssl_is_https(conn_rec *c);
     284char* ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c,
     285                     request_rec *r, char *var);
    285286int ssl_proxy_enable(conn_rec *c);
    286287int ssl_engine_disable(conn_rec *c);
     
    347348
    348349/**
    349  * Init the Cache after Configuration is done
    350  */
    351 int mgs_cache_post_config(apr_pool_t *p, server_rec *s,
    352                                  mgs_srvconf_rec *sc);
    353 /**
    354  * Init the Cache inside each Process
    355  */
    356 int mgs_cache_child_init(apr_pool_t *p, server_rec *s,
    357                                 mgs_srvconf_rec *sc);
    358 /**
    359  * Setup the Session Caching
    360  */
    361 int mgs_cache_session_init(mgs_handle_t *ctxt);
    362 
    363 #define GNUTLS_SESSION_ID_STRING_LEN \
    364     ((GNUTLS_MAX_SESSION_ID + 1) * 2)
    365 
    366 /**
    367350 * Perform any reinitialization required in PKCS #11
    368351 */
    369352int mgs_pkcs11_reinit(server_rec * s);
    370353
    371 /**
    372  * Convert a SSL Session ID into a Null Terminated Hex Encoded String
    373  * @param id raw SSL Session ID
    374  * @param idlen Length of the raw Session ID
    375  * @param str Location to store the Hex Encoded String
    376  * @param strsize The Maximum Length that can be stored in str
    377  */
    378 char *mgs_session_id2sz(unsigned char *id, int idlen,
    379                                 char *str, int strsize);
    380 
    381 /**
    382  * Convert a time_t into a Null Terminated String
    383  * @param t time_t time
    384  * @param str Location to store the Hex Encoded String
    385  * @param strsize The Maximum Length that can be stored in str
    386  */
    387 char *mgs_time2sz(time_t t, char *str, int strsize);
    388354
    389355
     
    391357
    392358/* Loads all files set in the configuration */
    393 int mgs_load_files(apr_pool_t * p, server_rec * s);
     359int mgs_load_files(apr_pool_t *pconf, apr_pool_t *ptemp, server_rec *s)
     360    __attribute__((nonnull));
    394361
    395362const char *mgs_set_srp_tpasswd_conf_file(cmd_parms * parms, void *dummy,
     
    405372                             const char *arg);
    406373
    407 const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy,
    408                                         const char *arg);
    409 
    410 const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy,
    411                              const char *arg);
    412 
    413 const char *mgs_set_cache(cmd_parms * parms, void *dummy,
    414                           const char *type, const char* arg);
    415 
    416 const char *mgs_set_cache_timeout(cmd_parms * parms, void *dummy,
    417                                   const char *arg);
     374const char *mgs_set_timeout(cmd_parms *parms, void *dummy, const char *arg);
    418375
    419376const char *mgs_set_client_verify(cmd_parms * parms, void *dummy,
     
    433390
    434391const char *mgs_set_srk_pin(cmd_parms * parms, void *dummy,
    435                                    const char *arg);
    436 
    437 const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy,
    438392                                   const char *arg);
    439393
     
    447401                            const int arg);
    448402
    449 const char *mgs_set_require_section(cmd_parms *cmd,
    450                                     void *mconfig, const char *arg);
    451403void *mgs_config_server_create(apr_pool_t * p, server_rec * s);
    452404void *mgs_config_server_merge(apr_pool_t *p, void *BASE, void *ADD);
     
    455407
    456408void *mgs_config_dir_create(apr_pool_t *p, char *dir);
    457 
    458 const char *mgs_set_require_bytecode(cmd_parms *cmd,
    459                                     void *mconfig, const char *arg);
    460 
    461 mgs_srvconf_rec* mgs_find_sni_server(gnutls_session_t session);
    462409
    463410const char *mgs_store_cred_path(cmd_parms * parms,
     
    470417                        apr_pool_t * plog, apr_pool_t * ptemp);
    471418
    472 int mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog,
    473                          apr_pool_t * ptemp,
    474                          server_rec * base_server);
     419int mgs_hook_post_config(apr_pool_t *pconf,
     420                         apr_pool_t *plog,
     421                         apr_pool_t *ptemp,
     422                         server_rec *base_server);
    475423
    476424void mgs_hook_child_init(apr_pool_t *p, server_rec *s);
     
    482430int mgs_hook_pre_connection(conn_rec * c, void *csd);
    483431
     432int mgs_hook_process_connection(conn_rec* c);
     433
    484434int mgs_hook_fixups(request_rec *r);
    485435
     436/** Post request hook, checks if TLS connection and vhost match */
     437int mgs_req_vhost_check(request_rec *r);
     438
    486439int mgs_hook_authz(request_rec *r);
    487440
  • m4/apache.m4

    r8a264b0 rea9c699  
    3939
    4040        AP_PREFIX="`$APXS_BIN -q prefix 2>/dev/null`"
     41        AP_EXEC_PREFIX="`$APXS_BIN -q exec_prefix 2>/dev/null`"
    4142
    4243        AP_BINDIR="`$APXS_BIN -q bindir 2>/dev/null`"
     
    126127        AC_SUBST(AP_DEFS)
    127128        AC_SUBST(AP_PREFIX)
     129        AC_SUBST(AP_EXEC_PREFIX)
    128130        AC_SUBST(AP_CFLAGS)
    129131        AC_SUBST(AP_CPPFLAGS)
  • src/Makefile.am

    r8a264b0 rea9c699  
    1 CLEANFILES = .libs/libmod_gnutls *~
     1# installation directory for Apache modules
     2if ENABLE_VPATH_INSTALL
     3apmodpkglibdir = $(subst ${AP_EXEC_PREFIX},${prefix},${AP_LIBEXECDIR})
     4else
     5apmodpkglibdir = ${AP_LIBEXECDIR}
     6endif
    27
    3 libmod_gnutls_la_SOURCES = mod_gnutls.c gnutls_io.c gnutls_cache.c gnutls_config.c gnutls_hooks.c
    4 libmod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS}
    5 libmod_gnutls_la_LDFLAGS = -rpath ${AP_LIBEXECDIR} -module -avoid-version ${MODULE_LIBS}
     8mod_gnutls_la_SOURCES = mod_gnutls.c gnutls_io.c gnutls_cache.c \
     9        gnutls_config.c gnutls_hooks.c gnutls_ocsp.c gnutls_proxy.c \
     10        gnutls_sni.c gnutls_util.c gnutls_watchdog.c
     11mod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS}
     12mod_gnutls_la_LDFLAGS = -module -avoid-version ${MODULE_LIBS}
     13noinst_HEADERS = gnutls_cache.h gnutls_config.h gnutls_ocsp.h \
     14        gnutls_proxy.h gnutls_sni.h gnutls_util.h gnutls_watchdog.h
    615
    7 lib_LTLIBRARIES = libmod_gnutls.la
    8 
    9 make_so: $(lib_LTLIBRARIES)
    10         @if test ! -L mod_gnutls.so ; then ln -s .libs/libmod_gnutls.so mod_gnutls.so ; fi
    11 
    12 clean:
    13         rm -f mod_gnutls.so
    14         rm -f *.o *.lo *.la
    15         rm -fr .libs
    16 
    17 install: make_so
    18         @${APXS_BIN} -i -n gnutls mod_gnutls.so
    19         @echo ""
    20         @echo ""
    21         @echo "***********************************************"
    22         @echo ""
    23         @echo "  Please read the manual in the doc/ directory for"
    24         @echo "  details on the configuration of this module"
    25         @echo ""
    26         @echo "***********************************************"
    27         @echo ""
     16apmodpkglib_LTLIBRARIES = mod_gnutls.la
  • src/gnutls_cache.c

    r8a264b0 rea9c699  
    1 /**
     1/*
    22 *  Copyright 2004-2005 Paul Querna
    33 *  Copyright 2008 Nikos Mavrogiannopoulos
    44 *  Copyright 2011 Dash Shendy
    5  *  Copyright 2015 Thomas Klute
     5 *  Copyright 2015-2018 Fiona Klute
    66 *
    77 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    1616 *  See the License for the specific language governing permissions and
    1717 *  limitations under the License.
    18  *
    19  */
    20 
     18 */
     19
     20/**
     21 * @file gnutls_cache.c
     22 *
     23 * This file contains the cache implementation used for session
     24 * caching and OCSP stapling. The `socache_*_session` functions
     25 * implement the GnuTLS session cache API using the configured cache,
     26 * using mgs_cache_store() and mgs_cache_fetch() as appropriate (see
     27 * gnutls_cache.h).
     28 */
     29
     30#include "gnutls_cache.h"
    2131#include "mod_gnutls.h"
    22 
    23 #if HAVE_APR_MEMCACHE
    24 #include "apr_memcache.h"
    25 #endif
    26 
    27 #include "apr_dbm.h"
    28 
    29 #include "ap_mpm.h"
    30 
    31 #include <unistd.h>
    32 #include <sys/types.h>
    33 
    34 #if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
    35 #include "unixd.h"
    36 #endif
    37 
    38 /* it seems the default has some strange errors. Use SDBM
    39  */
    40 #define MC_TAG "mod_gnutls:"
    41 #define MC_TAG_LEN sizeof(MC_TAG)
    42 #define STR_SESSION_LEN (GNUTLS_SESSION_ID_STRING_LEN + MC_TAG_LEN)
    43 
    44 #if MODULE_MAGIC_NUMBER_MAJOR < 20081201
    45 #define ap_unixd_config unixd_config
     32#include "gnutls_config.h"
     33#include "gnutls_ocsp.h"
     34
     35#include <ap_socache.h>
     36#include <apr_strings.h>
     37#include <mod_status.h>
     38#include <apr_escape.h>
     39#include <util_mutex.h>
     40
     41/** Default session cache timeout */
     42#define MGS_DEFAULT_CACHE_TIMEOUT 300
     43
     44/** Session cache name */
     45#define MGS_SESSION_CACHE_NAME "gnutls_session"
     46
     47/** Default type for OCSP cache */
     48#define DEFAULT_OCSP_CACHE_TYPE "shmcb"
     49/** Default config string for OCSP cache */
     50#define DEFAULT_OCSP_CACHE_CONF "gnutls_ocsp_cache"
     51
     52/** Maximum length of the hex string representation of a GnuTLS
     53 * session ID: two characters per byte, plus one more for `\0` */
     54#if GNUTLS_VERSION_NUMBER >= 0x030400
     55#define GNUTLS_SESSION_ID_STRING_LEN ((GNUTLS_MAX_SESSION_ID_SIZE * 2) + 1)
     56#else
     57#define GNUTLS_SESSION_ID_STRING_LEN ((GNUTLS_MAX_SESSION_ID * 2) + 1)
    4658#endif
    4759
     
    5062#endif
    5163
    52 char *mgs_session_id2sz(unsigned char *id, int idlen,
    53         char *str, int strsize) {
    54     char *cp;
    55     int n;
    56 
    57     cp = str;
    58     for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) {
    59         apr_snprintf(cp, strsize - (cp - str), "%02X", id[n]);
    60         cp += 2;
    61     }
    62     *cp = '\0';
    63     return str;
    64 }
    65 
    66 /* Name the Session ID as:
    67  * server:port.SessionID
    68  * to disallow resuming sessions on different servers
    69  */
    70 static int mgs_session_id2dbm(conn_rec * c, unsigned char *id, int idlen,
    71         apr_datum_t * dbmkey) {
    72     char buf[STR_SESSION_LEN];
    73     char *sz;
    74 
    75     sz = mgs_session_id2sz(id, idlen, buf, sizeof (buf));
    76     if (sz == NULL)
     64/**
     65 * Turn a GnuTLS session ID into the key format we use for
     66 * caches. Name the Session ID as `server:port.SessionID` to disallow
     67 * resuming sessions on different servers.
     68 *
     69 * @return `0` on success, `-1` on failure
     70 */
     71static int mgs_session_id2dbm(conn_rec *c, unsigned char *id, int idlen,
     72                              gnutls_datum_t *dbmkey)
     73{
     74    char sz[GNUTLS_SESSION_ID_STRING_LEN];
     75    apr_status_t rv = apr_escape_hex(sz, id, idlen, 0, NULL);
     76    if (rv != APR_SUCCESS)
    7777        return -1;
    7878
    79     dbmkey->dptr =
    80             apr_psprintf(c->pool, "%s:%d.%s",
    81             c->base_server->server_hostname,
    82             c->base_server->port, sz);
    83     dbmkey->dsize = strlen(dbmkey->dptr);
    84 
     79    char *newkey = apr_psprintf(c->pool, "%s:%d.%s",
     80                                c->base_server->server_hostname,
     81                                c->base_server->port, sz);
     82    dbmkey->size = strlen(newkey);
     83    /* signedness does not matter for arbitrary bits */
     84    dbmkey->data = (unsigned char*) newkey;
    8585    return 0;
    8686}
    8787
    88 #define CTIME "%b %d %k:%M:%S %Y %Z"
    89 
    90 char *mgs_time2sz(time_t in_time, char *str, int strsize) {
     88/** The OPENSSL_TIME_FORMAT macro and mgs_time2sz() serve to print
     89 * time in a format compatible with OpenSSL's `ASN1_TIME_print()`
     90 * function. */
     91#define OPENSSL_TIME_FORMAT "%b %d %k:%M:%S %Y %Z"
     92
     93char *mgs_time2sz(time_t in_time, char *str, int strsize)
     94{
    9195    apr_time_exp_t vtm;
    9296    apr_size_t ret_size;
     
    96100    apr_time_ansi_put(&t, in_time);
    97101    apr_time_exp_gmt(&vtm, t);
    98     apr_strftime(str, &ret_size, strsize - 1, CTIME, &vtm);
     102    apr_strftime(str, &ret_size, strsize - 1, OPENSSL_TIME_FORMAT, &vtm);
    99103
    100104    return str;
    101105}
    102106
    103 #if HAVE_APR_MEMCACHE
    104 
    105 /* Name the Session ID as:
    106  * server:port.SessionID
    107  * to disallow resuming sessions on different servers
    108  */
    109 static char *mgs_session_id2mc(conn_rec * c, unsigned char *id, int idlen) {
    110     char buf[STR_SESSION_LEN];
    111     char *sz;
    112 
    113     sz = mgs_session_id2sz(id, idlen, buf, sizeof (buf));
    114     if (sz == NULL)
    115         return NULL;
    116 
    117     return apr_psprintf(c->pool, MC_TAG "%s:%d.%s",
    118             c->base_server->server_hostname,
    119             c->base_server->port, sz);
    120 }
     107
     108
     109int mgs_cache_store(mgs_cache_t cache, server_rec *server,
     110                    gnutls_datum_t key, gnutls_datum_t data,
     111                    apr_time_t expiry)
     112{
     113    apr_pool_t *spool;
     114    apr_pool_create(&spool, NULL);
     115
     116    if (cache->prov->flags & AP_SOCACHE_FLAG_NOTMPSAFE)
     117        apr_global_mutex_lock(cache->mutex);
     118    apr_status_t rv = cache->prov->store(cache->socache, server,
     119                                         key.data, key.size,
     120                                         expiry,
     121                                         data.data, data.size,
     122                                         spool);
     123    if (cache->prov->flags & AP_SOCACHE_FLAG_NOTMPSAFE)
     124        apr_global_mutex_unlock(cache->mutex);
     125
     126    if (rv != APR_SUCCESS)
     127    {
     128        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, server,
     129                     "error storing in cache '%s:%s'",
     130                     cache->prov->name, cache->config);
     131        apr_pool_destroy(spool);
     132        return -1;
     133    }
     134
     135    ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, server,
     136                 "stored %u bytes of data (%u byte key) in cache '%s:%s'",
     137                 data.size, key.size,
     138                 cache->prov->name, cache->config);
     139    apr_pool_destroy(spool);
     140    return 0;
     141}
     142
     143
    121144
    122145/**
    123  * GnuTLS Session Cache using libmemcached
    124  *
    125  */
    126 
    127 /* The underlying apr_memcache system is thread safe... woohoo */
    128 static apr_memcache_t *mc;
    129 
    130 static int mc_cache_child_init(apr_pool_t * p, server_rec * s,
    131         mgs_srvconf_rec * sc) {
    132     apr_status_t rv = APR_SUCCESS;
    133     int thread_limit = 0;
    134     int nservers = 0;
    135     char *cache_config;
    136     char *split;
    137     char *tok;
    138 
    139     ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
    140 
    141     /* Find all the servers in the first run to get a total count */
    142     cache_config = apr_pstrdup(p, sc->cache_config);
    143     split = apr_strtok(cache_config, " ", &tok);
    144     while (split) {
    145         nservers++;
    146         split = apr_strtok(NULL, " ", &tok);
    147     }
    148 
    149     rv = apr_memcache_create(p, nservers, 0, &mc);
    150     if (rv != APR_SUCCESS) {
    151         ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    152                 "[gnutls_cache] Failed to create Memcache Object of '%d' size.",
    153                 nservers);
    154         return rv;
    155     }
    156 
    157     /* Now add each server to the memcache */
    158     cache_config = apr_pstrdup(p, sc->cache_config);
    159     split = apr_strtok(cache_config, " ", &tok);
    160     while (split) {
    161         apr_memcache_server_t *st;
    162         char *host_str;
    163         char *scope_id;
    164         apr_port_t port;
    165 
    166         rv = apr_parse_addr_port(&host_str, &scope_id, &port,
    167                 split, p);
    168         if (rv != APR_SUCCESS) {
    169             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    170                     "[gnutls_cache] Failed to Parse Server: '%s'",
    171                     split);
    172             return rv;
    173         }
    174 
    175         if (host_str == NULL) {
    176             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    177                     "[gnutls_cache] Failed to Parse Server, "
    178                     "no hostname specified: '%s'", split);
    179             return rv;
    180         }
    181 
    182         if (port == 0) {
    183             port = 11211; /* default port */
    184         }
    185 
    186         /* Should Max Conns be (thread_limit / nservers) ? */
    187         rv = apr_memcache_server_create(p,
    188                 host_str, port,
    189                 0,
    190                 1, thread_limit, 600, &st);
    191         if (rv != APR_SUCCESS) {
    192             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    193                     "[gnutls_cache] Failed to Create Server: %s:%d",
    194                     host_str, port);
    195             return rv;
    196         }
    197 
    198         rv = apr_memcache_add_server(mc, st);
    199         if (rv != APR_SUCCESS) {
    200             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    201                     "[gnutls_cache] Failed to Add Server: %s:%d",
    202                     host_str, port);
    203             return rv;
    204         }
    205 
    206         split = apr_strtok(NULL, " ", &tok);
    207     }
    208     return rv;
    209 }
    210 
    211 static int mc_cache_store(void *baton, gnutls_datum_t key,
    212         gnutls_datum_t data) {
    213     apr_status_t rv = APR_SUCCESS;
     146 * Store function for the GnuTLS session cache, see
     147 * gnutls_db_set_store_function().
     148 *
     149 * @param baton mgs_handle_t for the connection, as set via
     150 * gnutls_db_set_ptr()
     151 *
     152 * @param key object key to store
     153 *
     154 * @param data the object to store
     155 *
     156 * @return `0` in case of success, `-1` in case of failure
     157 */
     158static int socache_store_session(void *baton, gnutls_datum_t key,
     159                                 gnutls_datum_t data)
     160{
    214161    mgs_handle_t *ctxt = baton;
    215     char *strkey = NULL;
    216     apr_uint32_t timeout;
    217 
    218     strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
    219     if (!strkey)
     162    gnutls_datum_t dbmkey;
     163
     164    if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    220165        return -1;
    221166
    222     timeout = apr_time_sec(ctxt->sc->cache_timeout);
    223 
    224     rv = apr_memcache_set(mc, strkey, (char *) data.data, data.size, timeout,
    225             0);
    226 
    227     if (rv != APR_SUCCESS) {
    228         ap_log_error(APLOG_MARK, APLOG_CRIT, rv,
    229                 ctxt->c->base_server,
    230                 "[gnutls_cache] error setting key '%s' "
    231                 "with %d bytes of data", strkey, data.size);
    232         return -1;
    233     }
    234 
    235     return 0;
    236 }
    237 
    238 static gnutls_datum_t mc_cache_fetch(void *baton, gnutls_datum_t key) {
    239     apr_status_t rv = APR_SUCCESS;
    240     mgs_handle_t *ctxt = baton;
    241     char *strkey = NULL;
    242     char *value;
    243     apr_size_t value_len;
     167    apr_time_t expiry = apr_time_now() + ctxt->sc->cache_timeout;
     168
     169    return mgs_cache_store(ctxt->sc->cache, ctxt->c->base_server,
     170                           dbmkey, data, expiry);
     171}
     172
     173
     174
     175/** 8K is the maximum size accepted when receiving OCSP responses,
     176 * sessions cache entries should be much smaller. The buffer is
     177 * reallocated to actual size after fetching, so memory waste is
     178 * minimal and temporary. */
     179#define SOCACHE_FETCH_BUF_SIZE (8 * 1024)
     180
     181gnutls_datum_t mgs_cache_fetch(mgs_cache_t cache, server_rec *server,
     182                               gnutls_datum_t key, apr_pool_t *pool)
     183{
    244184    gnutls_datum_t data = {NULL, 0};
    245 
    246     strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
    247     if (!strkey) {
    248         return data;
    249     }
    250 
    251     rv = apr_memcache_getp(mc, ctxt->c->pool, strkey,
    252             &value, &value_len, NULL);
    253 
    254     if (rv != APR_SUCCESS) {
    255 #if MOD_GNUTLS_DEBUG
    256         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    257                 ctxt->c->base_server,
    258                 "[gnutls_cache] error fetching key '%s' ",
    259                 strkey);
    260 #endif
    261         data.size = 0;
    262         data.data = NULL;
    263         return data;
    264     }
    265 
    266     /* TODO: Eliminate this memcpy. gnutls-- */
    267     data.data = gnutls_malloc(value_len);
     185    data.data = gnutls_malloc(SOCACHE_FETCH_BUF_SIZE);
    268186    if (data.data == NULL)
    269187        return data;
    270 
    271     data.size = value_len;
    272     memcpy(data.data, value, value_len);
     188    data.size = SOCACHE_FETCH_BUF_SIZE;
     189
     190    apr_pool_t *spool;
     191    apr_pool_create(&spool, pool);
     192
     193    if (cache->prov->flags & AP_SOCACHE_FLAG_NOTMPSAFE)
     194        apr_global_mutex_lock(cache->mutex);
     195    apr_status_t rv = cache->prov->retrieve(cache->socache, server,
     196                                            key.data, key.size,
     197                                            data.data, &data.size,
     198                                            spool);
     199    if (cache->prov->flags & AP_SOCACHE_FLAG_NOTMPSAFE)
     200        apr_global_mutex_unlock(cache->mutex);
     201
     202    if (rv != APR_SUCCESS)
     203    {
     204        /* APR_NOTFOUND means there's no such object. */
     205        if (rv == APR_NOTFOUND)
     206            ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, server,
     207                         "requested entry not found in cache '%s:%s'.",
     208                         cache->prov->name, cache->config);
     209        else
     210            ap_log_error(APLOG_MARK, APLOG_WARNING, rv, server,
     211                         "error fetching from cache '%s:%s'",
     212                         cache->prov->name, cache->config);
     213        /* free unused buffer */
     214        gnutls_free(data.data);
     215        data.data = NULL;
     216        data.size = 0;
     217    }
     218    else
     219    {
     220        ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, server,
     221                     "fetched %u bytes from cache '%s:%s'",
     222                     data.size, cache->prov->name, cache->config);
     223
     224        /* Realloc buffer to data.size. Data size must be less than or
     225         * equal to the initial buffer size, so this REALLY should not
     226         * fail. */
     227        data.data = gnutls_realloc(data.data, data.size);
     228        if (__builtin_expect(data.data == NULL, 0))
     229        {
     230            ap_log_error(APLOG_MARK, APLOG_CRIT, APR_ENOMEM, server,
     231                         "%s: Could not realloc fetch buffer to data size!",
     232                         __func__);
     233            data.size = 0;
     234        }
     235    }
     236    apr_pool_destroy(spool);
    273237
    274238    return data;
    275239}
    276240
    277 static int mc_cache_delete(void *baton, gnutls_datum_t key) {
    278     apr_status_t rv = APR_SUCCESS;
     241
     242
     243/**
     244 * Fetch function for the GnuTLS session cache, see
     245 * gnutls_db_set_retrieve_function().
     246 *
     247 * *Warning*: The `data` element of the returned `gnutls_datum_t` is
     248 * allocated using `gnutls_malloc()` for compatibility with the GnuTLS
     249 * session caching API, and must be released using `gnutls_free()`.
     250 *
     251 * @param baton mgs_handle_t for the connection, as set via
     252 * gnutls_db_set_ptr()
     253 *
     254 * @param key object key to fetch
     255 *
     256 * @return the requested cache entry, or `{NULL, 0}`
     257 */
     258static gnutls_datum_t socache_fetch_session(void *baton, gnutls_datum_t key)
     259{
     260    gnutls_datum_t data = {NULL, 0};
     261    gnutls_datum_t dbmkey;
    279262    mgs_handle_t *ctxt = baton;
    280     char *strkey = NULL;
    281 
    282     strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
    283     if (!strkey)
     263
     264    if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
     265        return data;
     266
     267    return mgs_cache_fetch(ctxt->sc->cache, ctxt->c->base_server,
     268                           dbmkey, ctxt->c->pool);
     269}
     270
     271
     272
     273/**
     274 * Remove function for the GnuTLS session cache, see
     275 * gnutls_db_set_remove_function().
     276 *
     277 * @param baton mgs_handle_t for the connection, as set via
     278 * gnutls_db_set_ptr()
     279 *
     280 * @param key object key to remove
     281 *
     282 * @return `0` in case of success, `-1` in case of failure
     283 */
     284static int socache_delete_session(void *baton, gnutls_datum_t key)
     285{
     286    gnutls_datum_t tmpkey;
     287    mgs_handle_t *ctxt = baton;
     288
     289    if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &tmpkey) < 0)
    284290        return -1;
    285291
    286     rv = apr_memcache_delete(mc, strkey, 0);
    287 
    288     if (rv != APR_SUCCESS) {
    289         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    290                 ctxt->c->base_server,
    291                 "[gnutls_cache] error deleting key '%s' ",
    292                 strkey);
    293         return -1;
    294     }
    295 
    296     return 0;
    297 }
    298 
    299 #endif  /* have_apr_memcache */
    300 
    301 static const char *db_type(mgs_srvconf_rec * sc) {
    302     if (sc->cache_type == mgs_cache_gdbm)
    303         return "gdbm";
    304     else
    305         return "db";
    306 }
    307 
    308 #define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )
    309 
    310 static void dbm_cache_expire(mgs_handle_t * ctxt) {
    311     apr_status_t rv;
    312     apr_dbm_t *dbm;
    313     apr_datum_t dbmkey;
    314     apr_datum_t dbmval;
    315     apr_time_t now;
    316     apr_time_t dtime;
    317     apr_pool_t *spool;
    318     int total, deleted;
    319 
    320     now = apr_time_now();
    321 
    322     if (now - ctxt->sc->last_cache_check <
    323             (ctxt->sc->cache_timeout) / 2)
    324         return;
    325 
    326     ctxt->sc->last_cache_check = now;
    327 
    328     apr_pool_create(&spool, ctxt->c->pool);
    329 
    330     total = 0;
    331     deleted = 0;
    332 
    333     rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
    334             ctxt->sc->cache_config, APR_DBM_RWCREATE,
    335             SSL_DBM_FILE_MODE, spool);
     292    if (ctxt->sc->cache->prov->flags & AP_SOCACHE_FLAG_NOTMPSAFE)
     293        apr_global_mutex_lock(ctxt->sc->cache->mutex);
     294    apr_status_t rv = ctxt->sc->cache->prov->remove(ctxt->sc->cache->socache,
     295                                                    ctxt->c->base_server,
     296                                                    key.data, key.size,
     297                                                    ctxt->c->pool);
     298    if (ctxt->sc->cache->prov->flags & AP_SOCACHE_FLAG_NOTMPSAFE)
     299        apr_global_mutex_unlock(ctxt->sc->cache->mutex);
     300
    336301    if (rv != APR_SUCCESS) {
    337302        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    338                 ctxt->c->base_server,
    339                 "[gnutls_cache] error opening cache searcher '%s'",
    340                 ctxt->sc->cache_config);
    341         apr_pool_destroy(spool);
    342         return;
    343     }
    344 
    345     apr_dbm_firstkey(dbm, &dbmkey);
    346     while (dbmkey.dptr != NULL) {
    347         apr_dbm_fetch(dbm, dbmkey, &dbmval);
    348         if (dbmval.dptr != NULL
    349                 && dbmval.dsize >= sizeof (apr_time_t)) {
    350             memcpy(&dtime, dbmval.dptr, sizeof (apr_time_t));
    351 
    352             if (now >= dtime) {
    353                 apr_dbm_delete(dbm, dbmkey);
    354                 deleted++;
    355             }
    356             apr_dbm_freedatum(dbm, dbmval);
    357         } else {
    358             apr_dbm_delete(dbm, dbmkey);
    359             deleted++;
    360         }
    361         total++;
    362         apr_dbm_nextkey(dbm, &dbmkey);
    363     }
    364     apr_dbm_close(dbm);
    365 
    366     ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    367             ctxt->c->base_server,
    368             "[gnutls_cache] Cleaned up cache '%s'. Deleted %d and left %d",
    369             ctxt->sc->cache_config, deleted, total - deleted);
    370 
    371     apr_pool_destroy(spool);
    372 
    373     return;
    374 }
    375 
    376 static gnutls_datum_t dbm_cache_fetch(void *baton, gnutls_datum_t key) {
    377     gnutls_datum_t data = {NULL, 0};
    378     apr_dbm_t *dbm;
    379     apr_datum_t dbmkey;
    380     apr_datum_t dbmval;
    381     mgs_handle_t *ctxt = baton;
    382     apr_status_t rv;
    383 
    384     if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    385         return data;
    386 
    387     rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
    388             ctxt->sc->cache_config, APR_DBM_READONLY,
    389             SSL_DBM_FILE_MODE, ctxt->c->pool);
    390     if (rv != APR_SUCCESS) {
    391         ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    392                 ctxt->c->base_server,
    393                 "[gnutls_cache] error opening cache '%s'",
    394                 ctxt->sc->cache_config);
    395         return data;
    396     }
    397 
    398     rv = apr_dbm_fetch(dbm, dbmkey, &dbmval);
    399 
    400     if (rv != APR_SUCCESS) {
    401         apr_dbm_close(dbm);
    402         return data;
    403     }
    404 
    405     if (dbmval.dptr == NULL || dbmval.dsize <= sizeof (apr_time_t)) {
    406         apr_dbm_freedatum(dbm, dbmval);
    407         apr_dbm_close(dbm);
    408         return data;
    409     }
    410 
    411     data.size = dbmval.dsize - sizeof (apr_time_t);
    412 
    413     data.data = gnutls_malloc(data.size);
    414     if (data.data == NULL) {
    415         apr_dbm_freedatum(dbm, dbmval);
    416         apr_dbm_close(dbm);
    417         return data;
    418     }
    419 
    420     memcpy(data.data, dbmval.dptr + sizeof (apr_time_t), data.size);
    421 
    422     apr_dbm_freedatum(dbm, dbmval);
    423     apr_dbm_close(dbm);
    424 
    425     return data;
    426 }
    427 
    428 static int dbm_cache_store(void *baton, gnutls_datum_t key,
    429         gnutls_datum_t data) {
    430     apr_dbm_t *dbm;
    431     apr_datum_t dbmkey;
    432     apr_datum_t dbmval;
    433     mgs_handle_t *ctxt = baton;
    434     apr_status_t rv;
    435     apr_time_t expiry;
    436     apr_pool_t *spool;
    437 
    438     if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
     303                     ctxt->c->base_server,
     304                     "error deleting from cache '%s:%s'",
     305                     ctxt->sc->cache->prov->name, ctxt->sc->cache->config);
    439306        return -1;
    440 
    441     /* we expire dbm only on every store
    442      */
    443     dbm_cache_expire(ctxt);
    444 
    445     apr_pool_create(&spool, ctxt->c->pool);
    446 
    447     /* create DBM value */
    448     dbmval.dsize = data.size + sizeof (apr_time_t);
    449     dbmval.dptr = (char *) apr_palloc(spool, dbmval.dsize);
    450 
    451     expiry = apr_time_now() + ctxt->sc->cache_timeout;
    452 
    453     memcpy((char *) dbmval.dptr, &expiry, sizeof (apr_time_t));
    454     memcpy((char *) dbmval.dptr + sizeof (apr_time_t),
    455             data.data, data.size);
    456 
    457     rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
    458             ctxt->sc->cache_config, APR_DBM_RWCREATE,
    459             SSL_DBM_FILE_MODE, ctxt->c->pool);
    460     if (rv != APR_SUCCESS) {
    461         ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    462                 ctxt->c->base_server,
    463                 "[gnutls_cache] error opening cache '%s'",
    464                 ctxt->sc->cache_config);
    465         apr_pool_destroy(spool);
    466         return -1;
    467     }
    468 
    469     rv = apr_dbm_store(dbm, dbmkey, dbmval);
    470 
    471     if (rv != APR_SUCCESS) {
    472         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    473                 ctxt->c->base_server,
    474                 "[gnutls_cache] error storing in cache '%s'",
    475                 ctxt->sc->cache_config);
    476         apr_dbm_close(dbm);
    477         apr_pool_destroy(spool);
    478         return -1;
    479     }
    480 
    481     apr_dbm_close(dbm);
    482 
    483     apr_pool_destroy(spool);
    484 
     307    }
    485308    return 0;
    486309}
    487310
    488 static int dbm_cache_delete(void *baton, gnutls_datum_t key) {
    489     apr_dbm_t *dbm;
    490     apr_datum_t dbmkey;
    491     mgs_handle_t *ctxt = baton;
    492     apr_status_t rv;
    493 
    494     if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    495         return -1;
    496 
    497     rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
    498             ctxt->sc->cache_config, APR_DBM_RWCREATE,
    499             SSL_DBM_FILE_MODE, ctxt->c->pool);
    500     if (rv != APR_SUCCESS) {
    501         ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    502                 ctxt->c->base_server,
    503                 "[gnutls_cache] error opening cache '%s'",
    504                 ctxt->sc->cache_config);
    505         return -1;
    506     }
    507 
    508     rv = apr_dbm_delete(dbm, dbmkey);
    509 
    510     if (rv != APR_SUCCESS) {
    511         ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    512                 ctxt->c->base_server,
    513                 "[gnutls_cache] error deleting from cache '%s'",
    514                 ctxt->sc->cache_config);
    515         apr_dbm_close(dbm);
    516         return -1;
    517     }
    518 
    519     apr_dbm_close(dbm);
    520 
     311
     312
     313const char *mgs_cache_inst_config(mgs_cache_t *cache, server_rec *server,
     314                                  const char* type, const char* config,
     315                                  apr_pool_t *pconf, apr_pool_t *ptemp)
     316{
     317    /* Allocate cache structure, will be assigned to *cache after
     318     * successful configuration. */
     319    mgs_cache_t c = apr_pcalloc(pconf, sizeof(struct mgs_cache));
     320    if (c == NULL)
     321        return "Could not allocate memory for cache configuration!";
     322
     323    /* Find the right socache provider */
     324    c->prov = ap_lookup_provider(AP_SOCACHE_PROVIDER_GROUP,
     325                                 type,
     326                                 AP_SOCACHE_PROVIDER_VERSION);
     327    if (c->prov == NULL)
     328    {
     329        return apr_psprintf(ptemp,
     330                            "Could not find socache provider '%s', please "
     331                            "make sure that the provider name is valid and "
     332                            "the appropriate module is loaded (maybe "
     333                            "mod_socache_%s.so?).",
     334                            type, type);
     335    }
     336
     337    /* shmcb works fine with NULL, but make sure there's a valid (if
     338     * empty) string for logging */
     339    if (config != NULL)
     340        c->config = apr_pstrdup(pconf, config);
     341    else
     342        c->config = "";
     343
     344    /* Create and configure the cache instance. */
     345    const char *err = c->prov->create(&c->socache, c->config, ptemp, pconf);
     346    if (err != NULL)
     347    {
     348        return apr_psprintf(ptemp,
     349                            "Creating cache '%s:%s' failed: %s",
     350                            c->prov->name, c->config, err);
     351    }
     352    ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, server,
     353                 "%s: Socache '%s:%s' created.",
     354                 __func__, c->prov->name, c->config);
     355
     356    /* assign configured cache structure to server */
     357    *cache = c;
     358
     359    return NULL;
     360}
     361
     362
     363
     364/**
     365 * This function is supposed to be called during post_config to
     366 * initialize mutex and socache instance associated with an
     367 * mgs_cache_t.
     368 *
     369 * @param cache the mod_gnutls cache structure
     370 *
     371 * @param cache_name name for socache initialization
     372 *
     373 * @param mutex_name name to pass to ap_global_mutex_create(), must
     374 * have been registered during pre_config.
     375 *
     376 * @param server server for logging purposes
     377 *
     378 * @param pconf memory pool for server configuration
     379 */
     380static apr_status_t mgs_cache_inst_init(mgs_cache_t cache,
     381                                        const char *cache_name,
     382                                        const char *mutex_name,
     383                                        server_rec *server,
     384                                        apr_pool_t *pconf)
     385{
     386    apr_status_t rv = APR_SUCCESS;
     387
     388    if (cache->mutex == NULL)
     389    {
     390        rv = ap_global_mutex_create(&cache->mutex, NULL,
     391                                    mutex_name,
     392                                    NULL, server, pconf, 0);
     393        ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, server,
     394                     "%s: create mutex", __func__);
     395        if (rv != APR_SUCCESS)
     396            return rv;
     397    }
     398
     399    rv = cache->prov->init(cache->socache, cache_name, NULL, server, pconf);
     400    if (rv != APR_SUCCESS)
     401        ap_log_error(APLOG_MARK, APLOG_CRIT, rv, server,
     402                     "Initializing cache '%s:%s' failed!",
     403                     cache->prov->name, cache->config);
     404    else
     405        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, server,
     406                     "%s: socache '%s:%s' initialized.", __func__,
     407                     cache->prov->name, cache->config);
     408    return rv;
     409}
     410
     411
     412
     413static apr_status_t cleanup_socache(void *data)
     414{
     415    server_rec *s = data;
     416    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
     417        ap_get_module_config(s->module_config, &gnutls_module);
     418    if (sc->cache)
     419    {
     420        ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, s,
     421                     "Cleaning up session cache '%s:%s'",
     422                     sc->cache->prov->name, sc->cache->config);
     423        sc->cache->prov->destroy(sc->cache->socache, s);
     424    }
     425    if (sc->ocsp_cache)
     426    {
     427        ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, s,
     428                     "Cleaning up OCSP cache '%s:%s'",
     429                     sc->ocsp_cache->prov->name, sc->ocsp_cache->config);
     430        sc->ocsp_cache->prov->destroy(sc->ocsp_cache->socache, s);
     431    }
     432    return APR_SUCCESS;
     433}
     434
     435
     436
     437int mgs_cache_post_config(apr_pool_t *pconf, apr_pool_t *ptemp,
     438                          server_rec *s, mgs_srvconf_rec *sc)
     439{
     440    apr_status_t rv = APR_SUCCESS;
     441
     442    /* If the OCSP cache is unconfigured initialize it with
     443     * defaults. */
     444    if (sc->ocsp_cache == NULL)
     445    {
     446        ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s,
     447                     "%s: OCSP cache unconfigured, using '%s:%s'.", __func__,
     448                     DEFAULT_OCSP_CACHE_TYPE, DEFAULT_OCSP_CACHE_CONF);
     449        const char *err = mgs_cache_inst_config(&sc->ocsp_cache, s,
     450                                                DEFAULT_OCSP_CACHE_TYPE,
     451                                                DEFAULT_OCSP_CACHE_CONF,
     452                                                pconf, ptemp);
     453        if (err != NULL)
     454            ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s,
     455                         "%s: Configuring default OCSP cache '%s:%s' failed, "
     456                         "make sure that mod_socache_%s is loaded.", __func__,
     457                         DEFAULT_OCSP_CACHE_TYPE, DEFAULT_OCSP_CACHE_CONF,
     458                         DEFAULT_OCSP_CACHE_TYPE);
     459    }
     460
     461    /* Initialize the OCSP cache first so it's not skipped if the
     462     * session cache is disabled. */
     463    if (sc->ocsp_cache != NULL)
     464    {
     465        /* TODO: Maybe initialize only if explicitly enabled OR at
     466         * least one (virtual) host has OCSP enabled? */
     467        rv = mgs_cache_inst_init(sc->ocsp_cache, MGS_OCSP_CACHE_NAME,
     468                                 MGS_OCSP_CACHE_MUTEX_NAME, s, pconf);
     469        if (rv != APR_SUCCESS)
     470            return HTTP_INSUFFICIENT_STORAGE;
     471    }
     472
     473    /* GnuTLSCache was never explicitly set or is disabled: */
     474    if (sc->cache_enable == GNUTLS_ENABLED_UNSET
     475        || sc->cache_enable == GNUTLS_ENABLED_FALSE)
     476    {
     477        sc->cache_enable = GNUTLS_ENABLED_FALSE;
     478        /* Cache disabled, done. */
     479        return APR_SUCCESS;
     480    }
     481    /* if GnuTLSCacheTimeout was never explicitly set: */
     482    if (sc->cache_timeout == MGS_TIMEOUT_UNSET)
     483        sc->cache_timeout = apr_time_from_sec(MGS_DEFAULT_CACHE_TIMEOUT);
     484
     485    rv = mgs_cache_inst_init(sc->cache, MGS_SESSION_CACHE_NAME,
     486                             MGS_CACHE_MUTEX_NAME, s, pconf);
     487    if (rv != APR_SUCCESS)
     488        return HTTP_INSUFFICIENT_STORAGE;
     489
     490    apr_pool_pre_cleanup_register(pconf, s, cleanup_socache);
     491
     492    return APR_SUCCESS;
     493}
     494
     495int mgs_cache_child_init(apr_pool_t *p, server_rec *server,
     496                         mgs_cache_t cache, const char *mutex_name)
     497{
     498    /* reinit cache mutex */
     499    const char *lockfile = apr_global_mutex_lockfile(cache->mutex);
     500    apr_status_t rv = apr_global_mutex_child_init(&cache->mutex,
     501                                                  lockfile, p);
     502    if (rv != APR_SUCCESS)
     503        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, server,
     504                     "Failed to reinit mutex '%s'", mutex_name);
     505
     506    return rv;
     507}
     508
     509int mgs_cache_session_init(mgs_handle_t * ctxt)
     510{
     511    if (ctxt->sc->cache_enable)
     512    {
     513        gnutls_db_set_retrieve_function(ctxt->session,
     514                                        socache_fetch_session);
     515        gnutls_db_set_remove_function(ctxt->session,
     516                                      socache_delete_session);
     517        gnutls_db_set_store_function(ctxt->session,
     518                                     socache_store_session);
     519        gnutls_db_set_ptr(ctxt->session, ctxt);
     520    }
    521521    return 0;
    522522}
    523523
    524 static int dbm_cache_post_config(apr_pool_t * p, server_rec * s,
    525         mgs_srvconf_rec * sc) {
    526     apr_status_t rv;
    527     apr_dbm_t *dbm;
    528     const char *path1;
    529     const char *path2;
    530 
    531     rv = apr_dbm_open_ex(&dbm, db_type(sc), sc->cache_config,
    532             APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, p);
    533 
    534     if (rv != APR_SUCCESS) {
    535         ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
    536                 "GnuTLS: Cannot create DBM Cache at `%s'",
    537                 sc->cache_config);
    538         return rv;
    539     }
    540 
    541     apr_dbm_close(dbm);
    542 
    543     apr_dbm_get_usednames_ex(p, db_type(sc), sc->cache_config, &path1,
    544             &path2);
    545 
    546     /* The Following Code takes logic directly from mod_ssl's DBM Cache */
    547 #if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
    548     /* Running as Root */
    549     if (path1 && geteuid() == 0) {
    550         if (0 != chown(path1, ap_unixd_config.user_id, -1))
    551             ap_log_error(APLOG_MARK, APLOG_NOTICE, -1, s,
    552                          "GnuTLS: could not chown cache path1 `%s' to uid %d (errno: %d)",
    553                          path1, ap_unixd_config.user_id, errno);
    554         if (path2 != NULL) {
    555             if (0 != chown(path2, ap_unixd_config.user_id, -1))
    556                 ap_log_error(APLOG_MARK, APLOG_NOTICE, -1, s,
    557                              "GnuTLS: could not chown cache path2 `%s' to uid %d (errno: %d)",
    558                              path2, ap_unixd_config.user_id, errno);
    559         }
    560     }
    561 #endif
    562 
    563     return rv;
    564 }
    565 
    566 int mgs_cache_post_config(apr_pool_t * p, server_rec * s,
    567         mgs_srvconf_rec * sc) {
    568 
    569     /* if GnuTLSCache was never explicitly set: */
    570     if (sc->cache_type == mgs_cache_unset)
    571         sc->cache_type = mgs_cache_none;
    572     /* if GnuTLSCacheTimeout was never explicitly set: */
    573     if (sc->cache_timeout == -1)
    574         sc->cache_timeout = apr_time_from_sec(300);
    575 
    576     if (sc->cache_type == mgs_cache_dbm
    577             || sc->cache_type == mgs_cache_gdbm) {
    578         return dbm_cache_post_config(p, s, sc);
    579     }
    580     return 0;
    581 }
    582 
    583 #if HAVE_APR_MEMCACHE
    584 int mgs_cache_child_init(apr_pool_t * p,
    585                          server_rec * s,
    586                          mgs_srvconf_rec * sc)
    587 #else
    588 int mgs_cache_child_init(apr_pool_t * p __attribute__((unused)),
    589                          server_rec * s __attribute__((unused)),
    590                          mgs_srvconf_rec * sc)
    591 #endif
    592 {
    593     if (sc->cache_type == mgs_cache_dbm
    594             || sc->cache_type == mgs_cache_gdbm) {
    595         return 0;
    596     }
    597 #if HAVE_APR_MEMCACHE
    598     else if (sc->cache_type == mgs_cache_memcache) {
    599         return mc_cache_child_init(p, s, sc);
    600     }
    601 #endif
    602     return 0;
    603 }
    604 
    605 #include <assert.h>
    606 
    607 int mgs_cache_session_init(mgs_handle_t * ctxt) {
    608     if (ctxt->sc->cache_type == mgs_cache_dbm
    609             || ctxt->sc->cache_type == mgs_cache_gdbm) {
    610         gnutls_db_set_retrieve_function(ctxt->session,
    611                 dbm_cache_fetch);
    612         gnutls_db_set_remove_function(ctxt->session,
    613                 dbm_cache_delete);
    614         gnutls_db_set_store_function(ctxt->session,
    615                 dbm_cache_store);
    616         gnutls_db_set_ptr(ctxt->session, ctxt);
    617     }
    618 #if HAVE_APR_MEMCACHE
    619     else if (ctxt->sc->cache_type == mgs_cache_memcache) {
    620         gnutls_db_set_retrieve_function(ctxt->session,
    621                 mc_cache_fetch);
    622         gnutls_db_set_remove_function(ctxt->session,
    623                 mc_cache_delete);
    624         gnutls_db_set_store_function(ctxt->session,
    625                 mc_cache_store);
    626         gnutls_db_set_ptr(ctxt->session, ctxt);
    627     }
    628 #endif
    629 
    630     return 0;
    631 }
     524
     525
     526int mgs_cache_status(mgs_cache_t cache, const char *header_title,
     527                     request_rec *r, int flags)
     528{
     529    if (!(flags & AP_STATUS_SHORT))
     530        ap_rprintf(r, "<h3>%s:</h3>\n", header_title);
     531    else
     532        ap_rprintf(r, "%s:\n", header_title);
     533
     534    if (cache->prov->flags & AP_SOCACHE_FLAG_NOTMPSAFE)
     535        apr_global_mutex_lock(cache->mutex);
     536    cache->prov->status(cache->socache, r, flags);
     537    if (cache->prov->flags & AP_SOCACHE_FLAG_NOTMPSAFE)
     538        apr_global_mutex_unlock(cache->mutex);
     539
     540    return OK;
     541}
  • src/gnutls_config.c

    r8a264b0 rea9c699  
    1 /**
     1/*
    22 *  Copyright 2004-2005 Paul Querna
    33 *  Copyright 2008, 2014 Nikos Mavrogiannopoulos
    44 *  Copyright 2011 Dash Shendy
    5  *  Copyright 2015 Thomas Klute
     5 *  Copyright 2015-2018 Fiona Klute
    66 *
    77 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    1616 *  See the License for the specific language governing permissions and
    1717 *  limitations under the License.
    18  *
    1918 */
    2019
     20#include "gnutls_cache.h"
     21#include "gnutls_config.h"
    2122#include "mod_gnutls.h"
     23#include "gnutls_ocsp.h"
     24
    2225#include "apr_lib.h"
     26#include <apr_strings.h>
    2327#include <gnutls/abstract.h>
    2428
     
    8387}
    8488
    85 /* 2048-bit group parameters from SRP specification */
    86 const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n"
    87         "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"
    88         "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"
    89         "KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n"
    90         "dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n"
    91         "YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n"
    92         "Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n"
    93         "-----END DH PARAMETERS-----\n";
    94 
    95 int mgs_load_files(apr_pool_t * p, server_rec * s)
     89
     90
     91/**
     92 * Clean up the various GnuTLS data structures allocated by
     93 * mgs_load_files()
     94 */
     95static apr_status_t mgs_pool_free_credentials(void *arg)
     96{
     97    mgs_srvconf_rec *sc = (mgs_srvconf_rec *) arg;
     98
     99    if (sc->certs)
     100    {
     101        gnutls_certificate_free_credentials(sc->certs);
     102        sc->certs = NULL;
     103    }
     104
     105    if (sc->anon_creds)
     106    {
     107        gnutls_anon_free_server_credentials(sc->anon_creds);
     108        sc->anon_creds = NULL;
     109    }
     110
     111#ifdef ENABLE_SRP
     112    if (sc->srp_creds)
     113    {
     114        gnutls_srp_free_server_credentials(sc->srp_creds);
     115        sc->srp_creds = NULL;
     116    }
     117#endif
     118
     119    if (sc->dh_params)
     120    {
     121        gnutls_dh_params_deinit(sc->dh_params);
     122        sc->dh_params = NULL;
     123    }
     124
     125    for (unsigned int i = 0; i < sc->certs_x509_chain_num; i++)
     126    {
     127        gnutls_pcert_deinit(&sc->certs_x509_chain[i]);
     128        gnutls_x509_crt_deinit(sc->certs_x509_crt_chain[i]);
     129    }
     130
     131    if (sc->privkey_x509)
     132    {
     133        gnutls_privkey_deinit(sc->privkey_x509);
     134        sc->privkey_x509 = NULL;
     135    }
     136
     137    if (sc->ca_list)
     138    {
     139        for (unsigned int i = 0; i < sc->ca_list_size; i++)
     140        {
     141            gnutls_x509_crt_deinit(sc->ca_list[i]);
     142        }
     143        gnutls_free(sc->ca_list);
     144        sc->ca_list = NULL;
     145    }
     146
     147    /* Deinit server priorities only if set from
     148     * sc->priorities_str. Otherwise the server is using the default
     149     * global priority cache, which must not be deinitialized here. */
     150    if (sc->priorities_str && sc->priorities)
     151    {
     152        gnutls_priority_deinit(sc->priorities);
     153        sc->priorities = NULL;
     154    }
     155
     156    return APR_SUCCESS;
     157}
     158
     159int mgs_load_files(apr_pool_t *pconf, apr_pool_t *ptemp, server_rec *s)
    96160{
    97161    apr_pool_t *spool;
     
    100164    int ret;
    101165    mgs_srvconf_rec *sc =
    102         (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
    103                                                  &gnutls_module);
    104 
    105     apr_pool_create(&spool, p);
    106 
    107     sc->cert_pgp = apr_pcalloc(p, sizeof(sc->cert_pgp[0]));
    108     sc->cert_crt_pgp = apr_pcalloc(p, sizeof(sc->cert_crt_pgp[0]));
    109     sc->certs_x509_chain =
    110         apr_pcalloc(p, MAX_CHAIN_SIZE * sizeof(sc->certs_x509_chain[0]));
    111     sc->certs_x509_crt_chain =
    112         apr_pcalloc(p,
    113                     MAX_CHAIN_SIZE * sizeof(sc->certs_x509_crt_chain[0]));
    114 
    115     ret = gnutls_certificate_allocate_credentials(&sc->certs);
    116     if (ret < 0) {
    117         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    118                      "GnuTLS: Failed to initialize" ": (%d) %s", ret,
    119                      gnutls_strerror(ret));
    120         ret = -1;
    121         goto cleanup;
    122     }
    123 
    124     ret = gnutls_anon_allocate_server_credentials(&sc->anon_creds);
    125     if (ret < 0) {
    126         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    127                      "GnuTLS: Failed to initialize" ": (%d) %s", ret,
    128                      gnutls_strerror(ret));
    129         ret = -1;
    130         goto cleanup;
     166        (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
     167                                                 &gnutls_module);
     168
     169    apr_pool_create(&spool, ptemp);
     170
     171    /* Cleanup function for the GnuTLS structures allocated below */
     172    apr_pool_cleanup_register(pconf, sc, mgs_pool_free_credentials,
     173                              apr_pool_cleanup_null);
     174
     175    if (sc->certs == NULL)
     176    {
     177        ret = gnutls_certificate_allocate_credentials(&sc->certs);
     178        if (ret < 0) {
     179            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     180                         "GnuTLS: Failed to initialize" ": (%d) %s", ret,
     181                         gnutls_strerror(ret));
     182            ret = -1;
     183            goto cleanup;
     184        }
     185    }
     186
     187    if (sc->anon_creds == NULL)
     188    {
     189        ret = gnutls_anon_allocate_server_credentials(&sc->anon_creds);
     190        if (ret < 0) {
     191            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     192                         "GnuTLS: Failed to initialize" ": (%d) %s", ret,
     193                         gnutls_strerror(ret));
     194            ret = -1;
     195            goto cleanup;
     196        }
    131197    }
    132198
    133199    /* Load SRP parameters */
    134200#ifdef ENABLE_SRP
    135     ret = gnutls_srp_allocate_server_credentials(&sc->srp_creds);
    136     if (ret < 0) {
    137         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    138                      "GnuTLS: Failed to initialize" ": (%d) %s", ret,
    139                      gnutls_strerror(ret));
    140         ret = -1;
    141         goto cleanup;
    142     }
    143 
    144     if (sc->srp_tpasswd_conf_file != NULL && sc->srp_tpasswd_file != NULL) {
    145         ret = gnutls_srp_set_server_credentials_file
    146             (sc->srp_creds, sc->srp_tpasswd_file,
    147              sc->srp_tpasswd_conf_file);
    148 
    149         if (ret < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) {
    150             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0,
    151                          s,
    152                          "GnuTLS: Host '%s:%d' is missing a "
    153                          "SRP password or conf File!",
    154                          s->server_hostname, s->port);
    155             ret = -1;
    156             goto cleanup;
    157         }
    158     }
    159 #endif
    160 
    161     ret = gnutls_dh_params_init(&sc->dh_params);
    162     if (ret < 0) {
    163             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    164                          "GnuTLS: Failed to initialize"
    165                          ": (%d) %s", ret, gnutls_strerror(ret));
    166             ret = -1;
    167             goto cleanup;
    168     }
    169 
    170     /* Load DH parameters */
    171     if (sc->dh_file) {
    172         if (load_datum_from_file(spool, sc->dh_file, &data) != 0) {
    173             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    174                          "GnuTLS: Error Reading " "DH params '%s'", sc->dh_file);
    175             ret = -1;
    176             goto cleanup;
    177         }
    178 
    179         ret =
    180             gnutls_dh_params_import_pkcs3(sc->dh_params, &data,
    181                                           GNUTLS_X509_FMT_PEM);
    182         if (ret < 0) {
    183             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    184                          "GnuTLS: Failed to Import "
    185                          "DH params '%s': (%d) %s", sc->dh_file, ret,
    186                          gnutls_strerror(ret));
    187             ret = -1;
    188             goto cleanup;
    189         }
    190     } else {
    191         gnutls_datum_t pdata = {
    192             (void *) static_dh_params,
    193             sizeof(static_dh_params)
    194         };
    195 
    196         ret = gnutls_dh_params_import_pkcs3(sc->dh_params, &pdata, GNUTLS_X509_FMT_PEM);
     201    if (sc->srp_creds == NULL)
     202    {
     203        ret = gnutls_srp_allocate_server_credentials(&sc->srp_creds);
    197204        if (ret < 0) {
    198205            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    199                     "GnuTLS: Unable to generate or load DH Params: (%d) %s",
    200                     ret, gnutls_strerror(ret));
     206                         "GnuTLS: Failed to initialize" ": (%d) %s", ret,
     207                        gnutls_strerror(ret));
    201208            ret = -1;
    202209            goto cleanup;
     
    204211    }
    205212
    206     if (sc->x509_cert_file != NULL) {
    207         unsigned int chain_num, i;
    208         unsigned format = GNUTLS_X509_FMT_PEM;
    209 
    210         /* Load X.509 certificate */
    211         if (strncmp(sc->x509_cert_file, "pkcs11:", 7) == 0) {
    212             gnutls_pkcs11_obj_t obj;
    213 
    214             file = sc->x509_cert_file;
    215 
    216             ret = gnutls_pkcs11_obj_init(&obj);
    217             if (ret < 0) {
    218                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    219                              "GnuTLS: Error Initializing PKCS #11 object");
    220                 ret = -1;
    221                 goto cleanup;
    222             }
    223 
    224             gnutls_pkcs11_obj_set_pin_function(obj, pin_callback, sc);
    225 
    226             ret = gnutls_pkcs11_obj_import_url(obj, file, GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
    227             if (ret < 0) {
    228                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    229                              "GnuTLS: Error Importing PKCS #11 object: '%s': %s",
    230                              file, gnutls_strerror(ret));
    231                 ret = -1;
    232                 goto cleanup;
    233             }
    234 
    235             format = GNUTLS_X509_FMT_DER;
    236             ret = gnutls_pkcs11_obj_export2(obj, &data);
    237             if (ret < 0) {
    238                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    239                              "GnuTLS: Error Exporting a PKCS #11 object: '%s': %s",
    240                              file, gnutls_strerror(ret));
    241                 ret = -1;
    242                 goto cleanup;
    243             }
    244 
    245             gnutls_pkcs11_obj_deinit(obj);
    246         } else {
    247             file = ap_server_root_relative(spool, sc->x509_cert_file);
    248 
    249             ret = gnutls_load_file(file, &data);
    250             if (ret < 0) {
    251                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    252                              "GnuTLS: Error Reading Certificate '%s': %s",
    253                              file, gnutls_strerror(ret));
    254                 ret = -1;
    255                 goto cleanup;
    256             }
    257         }
    258 
    259         ret =
    260             gnutls_x509_crt_list_import2(&sc->certs_x509_crt_chain,
    261                                         &chain_num, &data, format,
    262                                         GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED);
    263         gnutls_free(data.data);
    264         sc->certs_x509_chain_num = chain_num;
    265 
    266         if (ret < 0) {
    267             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    268                          "GnuTLS: Failed to Import Certificate Chain '%s': (%d) %s",
    269                          file, ret, gnutls_strerror(ret));
    270             ret = -1;
    271             goto cleanup;
    272         }
    273 
    274         for (i = 0; i < chain_num; i++) {
    275             ret =
    276                 gnutls_pcert_import_x509(&sc->certs_x509_chain[i],
    277                                          sc->certs_x509_crt_chain[i], 0);
    278             if (ret < 0) {
    279                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    280                              "GnuTLS: Failed to Import pCertificate '%s': (%d) %s",
    281                              file, ret, gnutls_strerror(ret));
    282                 ret = -1;
    283                 goto cleanup;
    284             }
    285         }
    286         sc->certs_x509_chain_num = chain_num;
    287     }
    288 
    289     if (sc->x509_key_file) {
    290         ret = gnutls_privkey_init(&sc->privkey_x509);
    291         if (ret < 0) {
    292             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    293                          "GnuTLS: Failed to initialize: (%d) %s", ret,
    294                          gnutls_strerror(ret));
    295             ret = -1;
    296             goto cleanup;
    297         }
    298 
    299         if (gnutls_url_is_supported(sc->x509_key_file) != 0) {
    300             file = sc->x509_key_file;
    301 
    302             gnutls_privkey_set_pin_function(sc->privkey_x509, pin_callback,
    303                                             sc);
    304 
    305             ret = gnutls_privkey_import_url(sc->privkey_x509, file, 0);
    306 
    307             if (ret < 0) {
    308                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    309                              "GnuTLS: Failed to Import Private Key URL '%s': (%d) %s",
    310                              file, ret, gnutls_strerror(ret));
    311                 ret = -1;
    312                 goto cleanup;
    313             }
    314         } else {
    315             file = ap_server_root_relative(spool, sc->x509_key_file);
    316 
    317             if (load_datum_from_file(spool, file, &data) != 0) {
    318                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    319                              "GnuTLS: Error Reading Private Key '%s'",
    320                              file);
    321                 ret = -1;
    322                 goto cleanup;
    323             }
    324 
    325             ret =
    326                 gnutls_privkey_import_x509_raw(sc->privkey_x509, &data,
    327                                                GNUTLS_X509_FMT_PEM, sc->pin,
    328                                                0);
    329 
    330             if (ret < 0) {
    331                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    332                              "GnuTLS: Failed to Import Private Key '%s': (%d) %s",
    333                              file, ret, gnutls_strerror(ret));
    334                 ret = -1;
    335                 goto cleanup;
    336             }
    337         }
    338     }
    339 
    340     /* Load the X.509 CA file */
    341     if (sc->x509_ca_file) {
    342         if (load_datum_from_file(spool, sc->x509_ca_file, &data) != 0) {
    343             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    344                          "GnuTLS: Error Reading " "Client CA File '%s'",
    345                          sc->x509_ca_file);
    346             ret = -1;
    347             goto cleanup;
    348         }
    349 
    350         ret = gnutls_x509_crt_list_import2(&sc->ca_list, &sc->ca_list_size,
    351                                          &data, GNUTLS_X509_FMT_PEM, 0);
    352         if (ret < 0) {
    353             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    354                          "GnuTLS: Failed to load "
    355                          "Client CA File '%s': (%d) %s", sc->x509_ca_file,
    356                          ret, gnutls_strerror(ret));
    357             ret = -1;
    358             goto cleanup;
    359         }
    360     }
    361 
    362     if (sc->pgp_cert_file) {
    363         if (load_datum_from_file(spool, sc->pgp_cert_file, &data) != 0) {
    364             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    365                          "GnuTLS: Error Reading " "Certificate '%s'",
    366                          sc->pgp_cert_file);
    367             ret = -1;
    368             goto cleanup;
    369         }
    370 
    371         ret = gnutls_openpgp_crt_init(&sc->cert_crt_pgp[0]);
    372         if (ret < 0) {
    373             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    374                          "GnuTLS: Failed to Init "
    375                          "PGP Certificate: (%d) %s", ret,
    376                          gnutls_strerror(ret));
    377             ret = -1;
    378             goto cleanup;
    379         }
    380 
    381         ret =
    382             gnutls_openpgp_crt_import(sc->cert_crt_pgp[0], &data,
    383                                       GNUTLS_OPENPGP_FMT_BASE64);
    384         if (ret < 0) {
    385             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    386                          "GnuTLS: Failed to Import "
    387                          "PGP Certificate: (%d) %s", ret,
    388                          gnutls_strerror(ret));
    389             ret = -1;
    390             goto cleanup;
    391         }
    392 
    393         ret =
    394             gnutls_pcert_import_openpgp(sc->cert_pgp, sc->cert_crt_pgp[0],
    395                                         0);
    396         if (ret < 0) {
    397             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    398                          "GnuTLS: Failed to Import "
    399                          "PGP pCertificate: (%d) %s", ret,
    400                          gnutls_strerror(ret));
    401             ret = -1;
    402             goto cleanup;
    403         }
    404     }
    405 
    406     /* Load the PGP key file */
    407     if (sc->pgp_key_file) {
    408         if (load_datum_from_file(spool, sc->pgp_key_file, &data) != 0) {
    409             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    410                          "GnuTLS: Error Reading " "Private Key '%s'",
    411                          sc->pgp_key_file);
    412             ret = -1;
    413             goto cleanup;
    414         }
    415 
    416         ret = gnutls_privkey_init(&sc->privkey_pgp);
    417         if (ret < 0) {
    418             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    419                          "GnuTLS: Failed to initialize"
    420                          ": (%d) %s", ret, gnutls_strerror(ret));
    421             ret = -1;
    422             goto cleanup;
    423         }
    424 
    425 #if GNUTLS_VERSION_NUMBER < 0x030312
    426         /* GnuTLS versions before 3.3.12 contain a bug in
    427          * gnutls_privkey_import_openpgp_raw which frees data that is
    428          * accessed when the key is used, leading to segfault. Loading
    429          * the key into a gnutls_openpgp_privkey_t and then assigning
    430          * it to the gnutls_privkey_t works around the bug, hence this
    431          * chain of gnutls_openpgp_privkey_init,
    432          * gnutls_openpgp_privkey_import and
    433          * gnutls_privkey_import_openpgp. */
    434         ret = gnutls_openpgp_privkey_init(&sc->privkey_pgp_internal);
    435         if (ret != 0) {
    436             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    437                          "GnuTLS: Failed to initialize "
    438                          "PGP Private Key '%s': (%d) %s",
    439                          sc->pgp_key_file, ret, gnutls_strerror(ret));
    440             ret = -1;
    441             goto cleanup;
    442         }
    443 
    444         ret = gnutls_openpgp_privkey_import(sc->privkey_pgp_internal, &data,
    445                                             GNUTLS_OPENPGP_FMT_BASE64, NULL, 0);
    446         if (ret != 0) {
    447             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    448                          "GnuTLS: Failed to Import "
    449                          "PGP Private Key '%s': (%d) %s",
    450                          sc->pgp_key_file, ret, gnutls_strerror(ret));
    451             ret = -1;
    452             goto cleanup;
    453         }
    454 
    455         ret = gnutls_privkey_import_openpgp(sc->privkey_pgp,
    456                                             sc->privkey_pgp_internal, 0);
    457         if (ret != 0)
     213    if (sc->srp_tpasswd_conf_file != NULL && sc->srp_tpasswd_file != NULL)
     214    {
     215        ret = gnutls_srp_set_server_credentials_file
     216            (sc->srp_creds, sc->srp_tpasswd_file,
     217             sc->srp_tpasswd_conf_file);
     218
     219        if (ret < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) {
     220            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     221                         "GnuTLS: Host '%s:%d' is missing a "
     222                         "SRP password or conf File!",
     223                         s->server_hostname, s->port);
     224            ret = -1;
     225            goto cleanup;
     226        }
     227    }
     228#endif
     229
     230    /* Load user provided DH parameters, if any */
     231    if (sc->dh_file)
     232    {
     233        if (sc->dh_params == NULL)
    458234        {
     235            ret = gnutls_dh_params_init(&sc->dh_params);
     236            if (ret < 0) {
     237                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     238                             "GnuTLS: Failed to initialize"
     239                             ": (%d) %s", ret, gnutls_strerror(ret));
     240                ret = -1;
     241                goto cleanup;
     242            }
     243        }
     244
     245        if (load_datum_from_file(spool, sc->dh_file, &data) != 0) {
    459246            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    460                          "GnuTLS: Failed to assign PGP Private Key '%s' "
    461                          "to gnutls_privkey_t structure: (%d) %s",
    462                          sc->pgp_key_file, ret, gnutls_strerror(ret));
    463             ret = -1;
    464             goto cleanup;
    465         }
    466 #else
    467         ret = gnutls_privkey_import_openpgp_raw(sc->privkey_pgp, &data,
    468                                                 GNUTLS_OPENPGP_FMT_BASE64,
    469                                                 NULL, NULL);
    470         if (ret != 0)
    471         {
     247                         "GnuTLS: Error Reading " "DH params '%s'", sc->dh_file);
     248            ret = -1;
     249            goto cleanup;
     250        }
     251
     252        ret =
     253            gnutls_dh_params_import_pkcs3(sc->dh_params, &data,
     254                                          GNUTLS_X509_FMT_PEM);
     255        if (ret < 0) {
    472256            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    473257                         "GnuTLS: Failed to Import "
    474                          "PGP Private Key '%s': (%d) %s",
    475                          sc->pgp_key_file, ret, gnutls_strerror(ret));
    476             ret = -1;
    477             goto cleanup;
    478         }
    479 #endif
    480     }
    481 
    482     /* Load the keyring file */
    483     if (sc->pgp_ring_file) {
    484         if (load_datum_from_file(spool, sc->pgp_ring_file, &data) != 0) {
    485             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    486                          "GnuTLS: Error Reading " "Keyring File '%s'",
    487                          sc->pgp_ring_file);
    488             ret = -1;
    489             goto cleanup;
    490         }
    491 
    492         ret = gnutls_openpgp_keyring_init(&sc->pgp_list);
    493         if (ret < 0) {
    494             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    495                          "GnuTLS: Failed to initialize"
    496                          "keyring: (%d) %s", ret, gnutls_strerror(ret));
    497             ret = -1;
    498             goto cleanup;
    499         }
    500 
    501         ret = gnutls_openpgp_keyring_import(sc->pgp_list, &data,
    502                                            GNUTLS_OPENPGP_FMT_BASE64);
    503         if (ret < 0) {
    504             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    505                          "GnuTLS: Failed to load "
    506                          "Keyring File '%s': (%d) %s", sc->pgp_ring_file,
    507                          ret, gnutls_strerror(ret));
    508             ret = -1;
    509             goto cleanup;
    510         }
    511     }
    512 
    513     if (sc->priorities_str) {
     258                         "DH params '%s': (%d) %s", sc->dh_file, ret,
     259                         gnutls_strerror(ret));
     260            ret = -1;
     261            goto cleanup;
     262        }
     263    }
     264
     265    if (sc->x509_cert_file != NULL && sc->certs_x509_crt_chain == NULL)
     266    {
     267        sc->certs_x509_chain =
     268            apr_pcalloc(pconf,
     269                        MAX_CHAIN_SIZE * sizeof(sc->certs_x509_chain[0]));
     270        sc->certs_x509_crt_chain =
     271            apr_pcalloc(pconf,
     272                        MAX_CHAIN_SIZE * sizeof(sc->certs_x509_crt_chain[0]));
     273        unsigned int chain_num = MAX_CHAIN_SIZE;
     274        unsigned format = GNUTLS_X509_FMT_PEM;
     275
     276        /* Load X.509 certificate */
     277        if (strncmp(sc->x509_cert_file, "pkcs11:", 7) == 0) {
     278            gnutls_pkcs11_obj_t obj;
     279
     280            file = sc->x509_cert_file;
     281
     282            ret = gnutls_pkcs11_obj_init(&obj);
     283            if (ret < 0) {
     284                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     285                             "GnuTLS: Error Initializing PKCS #11 object");
     286                ret = -1;
     287                goto cleanup;
     288            }
     289
     290            gnutls_pkcs11_obj_set_pin_function(obj, pin_callback, sc);
     291
     292            ret = gnutls_pkcs11_obj_import_url(obj, file,
     293                                               GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
     294            if (ret < 0) {
     295                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     296                             "GnuTLS: Error Importing PKCS #11 object: "
     297                             "'%s': %s",
     298                             file, gnutls_strerror(ret));
     299                ret = -1;
     300                goto cleanup;
     301            }
     302
     303            format = GNUTLS_X509_FMT_DER;
     304            ret = gnutls_pkcs11_obj_export2(obj, &data);
     305            if (ret < 0) {
     306                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     307                             "GnuTLS: Error Exporting a PKCS #11 object: "
     308                             "'%s': %s",
     309                             file, gnutls_strerror(ret));
     310                ret = -1;
     311                goto cleanup;
     312            }
     313
     314            gnutls_pkcs11_obj_deinit(obj);
     315        } else {
     316            file = ap_server_root_relative(spool, sc->x509_cert_file);
     317
     318            ret = gnutls_load_file(file, &data);
     319            if (ret < 0) {
     320                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     321                             "GnuTLS: Error Reading Certificate '%s': %s",
     322                             file, gnutls_strerror(ret));
     323                ret = -1;
     324                goto cleanup;
     325            }
     326        }
     327
     328        ret = gnutls_x509_crt_list_import(sc->certs_x509_crt_chain,
     329                                          &chain_num, &data, format,
     330                                          GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED);
     331        gnutls_free(data.data);
     332        sc->certs_x509_chain_num = chain_num;
     333
     334        if (ret < 0) {
     335            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     336                         "GnuTLS: Failed to Import Certificate Chain "
     337                         "'%s': (%d) %s",
     338                         file, ret, gnutls_strerror(ret));
     339            ret = -1;
     340            goto cleanup;
     341        }
     342
     343        for (unsigned int i = 0; i < chain_num; i++)
     344        {
     345            ret =
     346                gnutls_pcert_import_x509(&sc->certs_x509_chain[i],
     347                                         sc->certs_x509_crt_chain[i], 0);
     348            if (ret < 0) {
     349                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     350                             "GnuTLS: Failed to Import pCertificate "
     351                             "'%s': (%d) %s",
     352                             file, ret, gnutls_strerror(ret));
     353                ret = -1;
     354                goto cleanup;
     355            }
     356        }
     357        sc->certs_x509_chain_num = chain_num;
     358    }
     359
     360    if (sc->x509_key_file && sc->privkey_x509 == NULL)
     361    {
     362        ret = gnutls_privkey_init(&sc->privkey_x509);
     363        if (ret < 0) {
     364            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     365                         "GnuTLS: Failed to initialize: (%d) %s", ret,
     366                         gnutls_strerror(ret));
     367            ret = -1;
     368            goto cleanup;
     369        }
     370
     371        if (gnutls_url_is_supported(sc->x509_key_file) != 0) {
     372            file = sc->x509_key_file;
     373
     374            gnutls_privkey_set_pin_function(sc->privkey_x509, pin_callback,
     375                                            sc);
     376
     377            ret = gnutls_privkey_import_url(sc->privkey_x509, file, 0);
     378
     379            if (ret < 0) {
     380                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     381                             "GnuTLS: Failed to Import Private Key URL "
     382                             "'%s': (%d) %s",
     383                             file, ret, gnutls_strerror(ret));
     384                ret = -1;
     385                goto cleanup;
     386            }
     387        } else {
     388            file = ap_server_root_relative(spool, sc->x509_key_file);
     389
     390            if (load_datum_from_file(spool, file, &data) != 0) {
     391                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     392                             "GnuTLS: Error Reading Private Key '%s'",
     393                             file);
     394                ret = -1;
     395                goto cleanup;
     396            }
     397
     398            ret =
     399                gnutls_privkey_import_x509_raw(sc->privkey_x509, &data,
     400                                               GNUTLS_X509_FMT_PEM, sc->pin,
     401                                               0);
     402
     403            if (ret < 0) {
     404                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     405                             "GnuTLS: Failed to Import Private Key "
     406                             "'%s': (%d) %s",
     407                             file, ret, gnutls_strerror(ret));
     408                ret = -1;
     409                goto cleanup;
     410            }
     411        }
     412    }
     413
     414    /* Load the X.509 CA file */
     415    if (sc->x509_ca_file)
     416    {
     417        if (load_datum_from_file(spool, sc->x509_ca_file, &data) != 0) {
     418            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     419                         "GnuTLS: Error Reading " "Client CA File '%s'",
     420                         sc->x509_ca_file);
     421            ret = -1;
     422            goto cleanup;
     423        }
     424
     425        ret = gnutls_x509_crt_list_import2(&sc->ca_list, &sc->ca_list_size,
     426                                           &data, GNUTLS_X509_FMT_PEM, 0);
     427        if (ret < 0) {
     428            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     429                         "GnuTLS: Failed to load "
     430                         "Client CA File '%s': (%d) %s", sc->x509_ca_file,
     431                         ret, gnutls_strerror(ret));
     432            ret = -1;
     433            goto cleanup;
     434        }
     435    }
     436
     437    if (sc->priorities_str && sc->priorities == NULL)
     438    {
    514439        const char *err;
    515440        ret = gnutls_priority_init(&sc->priorities, sc->priorities_str, &err);
    516441
    517         if (ret < 0) {
    518             if (ret == GNUTLS_E_INVALID_REQUEST) {
    519                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    520                              "GnuTLS: Syntax error parsing priorities string at: %s",
    521                              err);
    522             } else {
    523                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    524                              "GnuTLS: error parsing priorities string");
    525 
    526             }
    527             ret = -1;
    528             goto cleanup;
    529         }
     442        if (ret < 0) {
     443            if (ret == GNUTLS_E_INVALID_REQUEST) {
     444                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     445                             "GnuTLS: Syntax error parsing priorities string at: %s",
     446                             err);
     447            } else {
     448                ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     449                             "GnuTLS: error parsing priorities string");
     450
     451            }
     452            ret = -1;
     453            goto cleanup;
     454        }
    530455    }
    531456
    532457    ret = 0;
    533   cleanup:
     458 cleanup:
    534459    apr_pool_destroy(spool);
    535460
     
    617542}
    618543
    619 const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy __attribute__((unused)),
    620         const char *arg)
    621 {
    622     mgs_srvconf_rec *sc =
    623         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    624                                                  module_config,
    625                                                  &gnutls_module);
    626 
    627     sc->pgp_cert_file = ap_server_root_relative(parms->pool, arg);
    628 
    629     return NULL;
    630 }
    631 
    632 const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy __attribute__((unused)),
    633         const char *arg) {
    634     mgs_srvconf_rec *sc =
    635         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    636                                                  module_config,
    637                                                  &gnutls_module);
    638 
    639     sc->pgp_key_file = ap_server_root_relative(parms->pool, arg);
    640 
    641     return NULL;
    642 }
    643 
    644544const char *mgs_set_tickets(cmd_parms *parms,
    645545                            void *dummy __attribute__((unused)),
     
    686586#endif
    687587
    688 const char *mgs_set_cache(cmd_parms * parms, void *dummy __attribute__((unused)),
    689         const char *type, const char *arg) {
     588const char *mgs_set_cache(cmd_parms * parms,
     589                          void *dummy __attribute__((unused)),
     590                          const char *type, const char *arg)
     591{
    690592    const char *err;
    691593    mgs_srvconf_rec *sc =
    692         ap_get_module_config(parms->server->module_config,
    693                              &gnutls_module);
    694     if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
    695         return err;
    696     }
    697 
    698     if (strcasecmp("none", type) == 0) {
    699         sc->cache_type = mgs_cache_none;
    700         sc->cache_config = NULL;
    701         return NULL;
    702     } else if (strcasecmp("dbm", type) == 0) {
    703         sc->cache_type = mgs_cache_dbm;
    704     } else if (strcasecmp("gdbm", type) == 0) {
    705         sc->cache_type = mgs_cache_gdbm;
    706     }
    707 #if HAVE_APR_MEMCACHE
    708     else if (strcasecmp("memcache", type) == 0) {
    709         sc->cache_type = mgs_cache_memcache;
    710     }
    711 #endif
    712     else {
    713         return "Invalid Type for GnuTLSCache!";
    714     }
    715 
    716     if (arg == NULL)
    717         return "Invalid argument 2 for GnuTLSCache!";
    718 
    719     if (sc->cache_type == mgs_cache_dbm
    720         || sc->cache_type == mgs_cache_gdbm) {
    721         sc->cache_config = ap_server_root_relative(parms->pool, arg);
    722     } else {
    723         sc->cache_config = apr_pstrdup(parms->pool, arg);
    724     }
    725 
    726     return NULL;
    727 }
    728 
    729 const char *mgs_set_cache_timeout(cmd_parms * parms, void *dummy __attribute__((unused)),
    730         const char *arg) {
    731     int argint;
    732     const char *err;
    733     mgs_srvconf_rec *sc =
    734         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    735                                                  module_config,
    736                                                  &gnutls_module);
    737 
    738     if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
    739         return err;
    740     }
    741 
    742     argint = atoi(arg);
    743 
    744     if (argint < 0) {
    745         return "GnuTLSCacheTimeout: Invalid argument";
    746     } else if (argint == 0) {
    747         sc->cache_timeout = 0;
    748     } else {
    749         sc->cache_timeout = apr_time_from_sec(argint);
    750     }
     594        ap_get_module_config(parms->server->module_config,
     595                             &gnutls_module);
     596    if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY)))
     597        return err;
     598
     599    unsigned char enable = GNUTLS_ENABLED_TRUE;
     600    /* none: disable cache */
     601    if (strcasecmp("none", type) == 0)
     602        enable = GNUTLS_ENABLED_FALSE;
     603
     604    /* Try to split socache "type:config" style configuration */
     605    const char* sep = ap_strchr_c(type, ':');
     606    if (sep)
     607    {
     608        type = apr_pstrmemdup(parms->temp_pool, type, sep - type);
     609        if (arg != NULL)
     610        {
     611            /* No mixing of socache style and legacy config! */
     612            return "GnuTLSCache appears to have a mod_socache style "
     613                "type:config value, but there is a second parameter!";
     614        }
     615        arg = ++sep;
     616    }
     617
     618    mgs_cache_t *cache = NULL;
     619    /* parms->directive->directive contains the directive string */
     620    if (!strcasecmp(parms->directive->directive, "GnuTLSCache"))
     621    {
     622        if (enable == GNUTLS_ENABLED_FALSE)
     623        {
     624            sc->cache_enable = GNUTLS_ENABLED_FALSE;
     625            return NULL;
     626        }
     627        sc->cache_enable = GNUTLS_ENABLED_TRUE;
     628        cache = &sc->cache;
     629    }
     630    else if (!strcasecmp(parms->directive->directive, "GnuTLSOCSPCache"))
     631    {
     632        if (enable == GNUTLS_ENABLED_FALSE)
     633            return "\"GnuTLSOCSPCache none\" is invalid, use "
     634                "\"GnuTLSOCSPStapling off\" if you want to disable "
     635                "OCSP stapling.";
     636        cache = &sc->ocsp_cache;
     637    }
     638    else
     639        return apr_psprintf(parms->temp_pool, "Internal Error: %s "
     640                            "called for unknown directive %s",
     641                            __func__, parms->directive->directive);
     642
     643    return mgs_cache_inst_config(cache, parms->server,
     644                                 type, arg,
     645                                 parms->pool, parms->temp_pool);
     646}
     647
     648const char *mgs_set_timeout(cmd_parms * parms,
     649                            void *dummy __attribute__((unused)),
     650                            const char *arg)
     651{
     652    apr_int64_t argint = apr_atoi64(arg);
     653    /* timeouts cannot be negative */
     654    if (argint < 0)
     655        return apr_psprintf(parms->pool, "%s: Invalid argument",
     656                            parms->directive->directive);
     657
     658    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
     659        ap_get_module_config(parms->server->module_config, &gnutls_module);
     660
     661    if (!strcasecmp(parms->directive->directive, "GnuTLSCacheTimeout"))
     662        sc->cache_timeout = apr_time_from_sec(argint);
     663    else if (!strcasecmp(parms->directive->directive,
     664                         "GnuTLSOCSPCacheTimeout"))
     665        sc->ocsp_cache_time = apr_time_from_sec(argint);
     666    else if (!strcasecmp(parms->directive->directive,
     667                         "GnuTLSOCSPFailureTimeout"))
     668        sc->ocsp_failure_timeout = apr_time_from_sec(argint);
     669    else if (!strcasecmp(parms->directive->directive,
     670                         "GnuTLSOCSPFuzzTime"))
     671        sc->ocsp_fuzz_time = apr_time_from_sec(argint);
     672    else if (!strcasecmp(parms->directive->directive,
     673                         "GnuTLSOCSPSocketTimeout"))
     674        sc->ocsp_socket_timeout = apr_time_from_sec(argint);
     675    else
     676        /* Can't happen unless there's a serious bug in mod_gnutls or Apache */
     677        return apr_psprintf(parms->pool,
     678                            "mod_gnutls: %s called for invalid option '%s'",
     679                            __func__, parms->directive->directive);
    751680
    752681    return NULL;
     
    810739
    811740    sc->x509_ca_file = ap_server_root_relative(parms->pool, arg);
    812 
    813     return NULL;
    814 }
    815 
    816 const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy __attribute__((unused)),
    817         const char *arg) {
    818     mgs_srvconf_rec *sc =
    819         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    820                                                  module_config,
    821                                                  &gnutls_module);
    822 
    823     sc->pgp_ring_file = ap_server_root_relative(parms->pool, arg);
    824741
    825742    return NULL;
     
    950867
    951868    sc->privkey_x509 = NULL;
    952     sc->privkey_pgp = NULL;
     869    sc->anon_creds = NULL;
     870#ifdef ENABLE_SRP
     871    sc->srp_creds = NULL;
     872#endif
     873    sc->certs = NULL;
     874    sc->certs_x509_chain = NULL;
     875    sc->certs_x509_crt_chain = NULL;
    953876    sc->certs_x509_chain_num = 0;
    954877    sc->p11_modules = NULL;
    955878    sc->pin = NULL;
     879
    956880    sc->priorities_str = NULL;
    957     sc->cache_timeout = -1;     /* -1 means "unset" */
    958     sc->cache_type = mgs_cache_unset;
    959     sc->cache_config = NULL;
     881    sc->cache_timeout = MGS_TIMEOUT_UNSET;
     882    sc->cache_enable = GNUTLS_ENABLED_UNSET;
     883    sc->cache = NULL;
    960884    sc->tickets = GNUTLS_ENABLED_UNSET;
    961885    sc->priorities = NULL;
    962886    sc->dh_params = NULL;
     887    sc->dh_file = NULL;
     888    sc->ca_list = NULL;
     889    sc->ca_list_size = 0;
    963890    sc->proxy_enabled = GNUTLS_ENABLED_UNSET;
    964891    sc->export_certificates_size = -1;
     
    970897    sc->proxy_x509_crl_file = NULL;
    971898    sc->proxy_priorities_str = NULL;
     899    sc->proxy_x509_creds = NULL;
     900    sc->anon_client_creds = NULL;
    972901    sc->proxy_priorities = NULL;
     902    sc->proxy_x509_tl = NULL;
     903
     904    sc->ocsp_staple = GNUTLS_ENABLED_UNSET;
     905    sc->ocsp_auto_refresh = GNUTLS_ENABLED_UNSET;
     906    sc->ocsp_check_nonce = GNUTLS_ENABLED_UNSET;
     907    sc->ocsp_response_file = NULL;
     908    sc->ocsp_mutex = NULL;
     909    sc->ocsp_cache = NULL;
     910    sc->ocsp_cache_time = MGS_TIMEOUT_UNSET;
     911    sc->ocsp_failure_timeout = MGS_TIMEOUT_UNSET;
     912    sc->ocsp_fuzz_time = MGS_TIMEOUT_UNSET;
     913    sc->ocsp_socket_timeout = MGS_TIMEOUT_UNSET;
     914
     915    sc->singleton_wd = NULL;
    973916
    974917/* this relies on GnuTLS never changing the gnutls_certificate_request_t enum to define -1 */
     
    993936void *mgs_config_server_merge(apr_pool_t * p, void *BASE, void *ADD)
    994937{
    995     int i;
    996938    char *err = NULL;
    997939    mgs_srvconf_rec *base = (mgs_srvconf_rec *) BASE;
     
    1015957    gnutls_srvconf_merge(p11_modules, NULL);
    1016958    gnutls_srvconf_merge(pin, NULL);
    1017     gnutls_srvconf_merge(pgp_cert_file, NULL);
    1018     gnutls_srvconf_merge(pgp_key_file, NULL);
    1019     gnutls_srvconf_merge(pgp_ring_file, NULL);
    1020959    gnutls_srvconf_merge(dh_file, NULL);
    1021960    gnutls_srvconf_merge(priorities_str, NULL);
     961    gnutls_srvconf_merge(cache_timeout, MGS_TIMEOUT_UNSET);
    1022962
    1023963    gnutls_srvconf_merge(proxy_x509_key_file, NULL);
     
    1028968    gnutls_srvconf_merge(proxy_priorities, NULL);
    1029969
    1030     /* FIXME: the following items are pre-allocated, and should be
    1031      * properly disposed of before assigning in order to avoid leaks;
    1032      * so at the moment, we can't actually have them in the config.
    1033      * what happens during de-allocation? */
    1034     /* TODO: mgs_load_files takes care of most of these now, verify
    1035      * and clean up the following lines */
     970    gnutls_srvconf_merge(ocsp_staple, GNUTLS_ENABLED_UNSET);
     971    gnutls_srvconf_merge(ocsp_auto_refresh, GNUTLS_ENABLED_UNSET);
     972    gnutls_srvconf_merge(ocsp_check_nonce, GNUTLS_ENABLED_UNSET);
     973    gnutls_srvconf_assign(ocsp_response_file);
     974    gnutls_srvconf_merge(ocsp_cache_time, MGS_TIMEOUT_UNSET);
     975    gnutls_srvconf_merge(ocsp_failure_timeout, MGS_TIMEOUT_UNSET);
     976    gnutls_srvconf_merge(ocsp_fuzz_time, MGS_TIMEOUT_UNSET);
     977    gnutls_srvconf_merge(ocsp_socket_timeout, MGS_TIMEOUT_UNSET);
     978
    1036979    gnutls_srvconf_assign(ca_list);
    1037980    gnutls_srvconf_assign(ca_list_size);
    1038     gnutls_srvconf_assign(cert_pgp);
    1039     gnutls_srvconf_assign(cert_crt_pgp);
    1040     gnutls_srvconf_assign(pgp_list);
    1041981    gnutls_srvconf_assign(certs);
    1042982    gnutls_srvconf_assign(anon_creds);
     
    1045985    gnutls_srvconf_assign(certs_x509_crt_chain);
    1046986    gnutls_srvconf_assign(certs_x509_chain_num);
    1047 
    1048     /* how do these get transferred cleanly before the data from ADD
    1049      * goes away? */
    1050     gnutls_srvconf_assign(cert_cn);
    1051     for (i = 0; i < MAX_CERT_SAN; i++)
    1052         gnutls_srvconf_assign(cert_san[i]);
    1053987
    1054988    return sc;
  • src/gnutls_hooks.c

    r8a264b0 rea9c699  
    1 /**
     1/*
    22 *  Copyright 2004-2005 Paul Querna
    33 *  Copyright 2008, 2014 Nikos Mavrogiannopoulos
    44 *  Copyright 2011 Dash Shendy
    55 *  Copyright 2013-2014 Daniel Kahn Gillmor
    6  *  Copyright 2015-2016 Thomas Klute
     6 *  Copyright 2015-2019 Fiona Klute
    77 *
    88 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    1717 *  See the License for the specific language governing permissions and
    1818 *  limitations under the License.
    19  *
    2019 */
    2120
    2221#include "mod_gnutls.h"
     22#include "gnutls_cache.h"
     23#include "gnutls_config.h"
     24#include "gnutls_ocsp.h"
     25#include "gnutls_proxy.h"
     26#include "gnutls_sni.h"
     27#include "gnutls_util.h"
     28#include "gnutls_watchdog.h"
     29
    2330#include "http_vhost.h"
    2431#include "ap_mpm.h"
    25 #include "mod_status.h"
     32#include <mod_status.h>
     33#include <util_mutex.h>
     34#include <apr_escape.h>
     35/* This provides strcmp and related functions */
     36#define APR_WANT_STRFUNC
     37#include <apr_want.h>
    2638
    2739#ifdef ENABLE_MSVA
     
    3345#endif
    3446
    35 #if !USING_2_1_RECENT
    36 extern server_rec *ap_server_conf;
    37 #endif
    38 
    3947#if MOD_GNUTLS_DEBUG
    4048static apr_file_t *debug_log_fp;
     
    4452    ((c->is_proxy == GNUTLS_ENABLED_TRUE) ? "proxy " : "")
    4553
     54/** Key to encrypt session tickets. Must be kept secret. This key is
     55 * generated in the `pre_config` hook and thus constant across
     56 * forks. The problem with this approach is that it does not support
     57 * regular key rotation. */
    4658static gnutls_datum_t session_ticket_key = {NULL, 0};
    4759
     60
     61
    4862static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
    49 /* use side==0 for server and side==1 for client */
     63/** use side==0 for server and side==1 for client */
    5064static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, size_t export_cert_size);
    51 static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, size_t export_cert_size);
     65mgs_srvconf_rec* mgs_find_sni_server(mgs_handle_t *ctxt);
    5266static int mgs_status_hook(request_rec *r, int flags);
    5367#ifdef ENABLE_MSVA
    5468static const char* mgs_x509_construct_uid(request_rec * pool, gnutls_x509_crt_t cert);
    5569#endif
    56 static int load_proxy_x509_credentials(server_rec *s);
    5770
    5871/* Pool Cleanup Function */
    59 apr_status_t mgs_cleanup_pre_config(void *data __attribute__((unused))) {
    60         /* Free all session data */
     72apr_status_t mgs_cleanup_pre_config(void *data __attribute__((unused)))
     73{
     74    /* Free session ticket master key */
     75#if GNUTLS_VERSION_NUMBER >= 0x030400
     76    gnutls_memset(session_ticket_key.data, 0, session_ticket_key.size);
     77#endif
    6178    gnutls_free(session_ticket_key.data);
    6279    session_ticket_key.data = NULL;
    6380    session_ticket_key.size = 0;
    64         /* Deinitialize GnuTLS Library */
    65     gnutls_global_deinit();
     81
     82    /* Deinit default priority setting */
     83    mgs_default_priority_deinit();
    6684    return APR_SUCCESS;
    6785}
     
    110128    }
    111129
    112         /* Initialize GnuTLS Library */
    113     ret = gnutls_global_init();
    114     if (ret < 0) {
    115                 ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, plog, "gnutls_global_init: %s", gnutls_strerror(ret));
    116                 return DONE;
    117     }
    118 
    119130        /* Generate a Session Key */
    120131    ret = gnutls_session_ticket_key_generate(&session_ticket_key);
     
    124135    }
    125136
     137    /* Initialize default priority setting */
     138    ret = mgs_default_priority_init();
     139    if (ret < 0)
     140    {
     141        ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, plog,
     142                      "gnutls_priority_init failed for default '%s': %s (%d)",
     143                      MGS_DEFAULT_PRIORITY, gnutls_strerror(ret), ret);
     144        return DONE;
     145    }
     146
    126147    AP_OPTIONAL_HOOK(status_hook, mgs_status_hook, NULL, NULL, APR_HOOK_MIDDLE);
    127148
    128         /* Register a pool clean-up function */
     149    ap_mutex_register(pconf, MGS_CACHE_MUTEX_NAME, NULL, APR_LOCK_DEFAULT, 0);
     150    ap_mutex_register(pconf, MGS_OCSP_MUTEX_NAME, NULL, APR_LOCK_DEFAULT, 0);
     151    ap_mutex_register(pconf, MGS_OCSP_CACHE_MUTEX_NAME, NULL,
     152                      APR_LOCK_DEFAULT, 0);
     153
     154    /* Register a pool clean-up function */
    129155    apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, apr_pool_cleanup_null);
    130156
     
    132158}
    133159
    134 static int mgs_select_virtual_server_cb(gnutls_session_t session) {
    135 
    136     mgs_handle_t *ctxt = NULL;
    137     mgs_srvconf_rec *tsc = NULL;
     160
     161
     162/**
     163 * Get the list of available protocols for this connection and add it
     164 * to the GnuTLS session. Must run before the client hello function.
     165 */
     166static void prepare_alpn_proposals(mgs_handle_t *ctxt)
     167{
     168    /* Check if any protocol upgrades are available
     169     *
     170     * The "report_all" parameter to ap_get_protocol_upgrades() is 0
     171     * (report only more preferable protocols) because setting it to 1
     172     * doesn't actually report ALL protocols, but only all except the
     173     * current one. This way we can at least list the current one as
     174     * available by appending it without potentially negotiating a
     175     * less preferred protocol. */
     176    const apr_array_header_t *pupgrades = NULL;
     177    apr_status_t ret =
     178        ap_get_protocol_upgrades(ctxt->c, NULL, ctxt->sc->s,
     179                                 /*report_all*/ 0, &pupgrades);
     180    if (ret != APR_SUCCESS)
     181    {
     182        ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, ctxt->c,
     183                      "%s: ap_get_protocol_upgrades() failed, "
     184                      "cannot configure ALPN!", __func__);
     185        return;
     186    }
     187
     188    if (pupgrades == NULL || pupgrades->nelts == 0)
     189    {
     190        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctxt->c,
     191                      "%s: No protocol upgrades available.", __func__);
     192        return;
     193    }
     194
     195    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctxt->c,
     196                  "%s: Found %d protocol upgrade(s) for ALPN: %s",
     197                  __func__, pupgrades->nelts,
     198                  apr_array_pstrcat(ctxt->c->pool, pupgrades, ','));
     199    gnutls_datum_t *alpn_protos =
     200        mgs_str_array_to_datum_array(pupgrades,
     201                                     ctxt->c->pool,
     202                                     pupgrades->nelts + 1);
     203
     204    /* Add the current (default) protocol at the end of the list */
     205    alpn_protos[pupgrades->nelts].data =
     206        (void*) apr_pstrdup(ctxt->c->pool, ap_get_protocol(ctxt->c));
     207    alpn_protos[pupgrades->nelts].size =
     208        strlen((char*) alpn_protos[pupgrades->nelts].data);
     209    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctxt->c,
     210                  "%s: Adding current protocol %s to ALPN set.",
     211                  __func__, alpn_protos[pupgrades->nelts].data);
     212
     213    gnutls_alpn_set_protocols(ctxt->session,
     214                              alpn_protos,
     215                              pupgrades->nelts,
     216                              GNUTLS_ALPN_SERVER_PRECEDENCE);
     217}
     218
     219
     220
     221/**
     222 * Check if ALPN selected any protocol upgrade, try to switch if so.
     223 */
     224static int process_alpn_result(mgs_handle_t *ctxt)
     225{
    138226    int ret = 0;
    139 
    140     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    141 
    142     ctxt = gnutls_transport_get_ptr(session);
    143 
    144     /* find the virtual server */
    145     tsc = mgs_find_sni_server(session);
    146 
    147     if (tsc != NULL) {
    148         // Found a TLS vhost based on the SNI from the client; use it instead.
    149         ctxt->sc = tsc;
    150         }
    151 
    152     gnutls_certificate_server_set_request(session, ctxt->sc->client_verify_mode);
     227    gnutls_datum_t alpn_proto;
     228    ret = gnutls_alpn_get_selected_protocol(ctxt->session, &alpn_proto);
     229    if (ret != GNUTLS_E_SUCCESS)
     230    {
     231        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
     232                      "%s: No ALPN result: %s (%d)",
     233                      __func__, gnutls_strerror(ret), ret);
     234        return GNUTLS_E_SUCCESS;
     235    }
     236
     237    apr_array_header_t *client_protos =
     238        apr_array_make(ctxt->c->pool, 1, sizeof(char *));
     239    /* apr_pstrndup to ensure that the protocol is null terminated */
     240    APR_ARRAY_PUSH(client_protos, char *) =
     241        apr_pstrndup(ctxt->c->pool, (char*) alpn_proto.data, alpn_proto.size);
     242    const char *selected =
     243        ap_select_protocol(ctxt->c, NULL, ctxt->sc->s, client_protos);
     244
     245    /* ap_select_protocol() will return NULL if none of the ALPN
     246     * proposals matched. GnuTLS negotiated alpn_proto based on the
     247     * list provided by the server, but the vhost might have changed
     248     * based on SNI. Apache seems to adjust the proposal list to avoid
     249     * such issues though.
     250     *
     251     * GnuTLS will return a fatal "no_application_protocol" alert as
     252     * required by RFC 7301 if the post client hello function returns
     253     * GNUTLS_E_NO_APPLICATION_PROTOCOL. */
     254    if (!selected)
     255    {
     256        ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, ctxt->c,
     257                      "%s: ap_select_protocol() returned NULL! Please "
     258                      "make sure any overlapping vhosts have the same "
     259                      "protocols available.",
     260                      __func__);
     261        return GNUTLS_E_NO_APPLICATION_PROTOCOL;
     262    }
     263
     264    if (strcmp(selected, ap_get_protocol(ctxt->c)) == 0)
     265    {
     266        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
     267                      "%s: Already using protocol '%s', nothing to do.",
     268                      __func__, selected);
     269        return GNUTLS_E_SUCCESS;
     270    }
     271
     272    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ctxt->c,
     273                  "%s: Switching protocol to '%s' based on ALPN.",
     274                  __func__, selected);
     275    apr_status_t status = ap_switch_protocol(ctxt->c, NULL,
     276                                             ctxt->sc->s,
     277                                             selected);
     278    if (status != APR_SUCCESS)
     279    {
     280        ap_log_cerror(APLOG_MARK, APLOG_ERR, status, ctxt->c,
     281                      "%s: Protocol switch to '%s' failed!",
     282                      __func__, selected);
     283        return GNUTLS_E_NO_APPLICATION_PROTOCOL;
     284    }
     285    /* ALPN done! */
     286    return GNUTLS_E_SUCCESS;
     287}
     288
     289
     290
     291/**
     292 * (Re-)Load credentials and priorities for the connection. This is
     293 * meant to be called after virtual host selection in the pre or post
     294 * client hello hook.
     295 */
     296static int reload_session_credentials(mgs_handle_t *ctxt)
     297{
     298    int ret = 0;
     299
     300    gnutls_certificate_server_set_request(ctxt->session,
     301                                          ctxt->sc->client_verify_mode);
    153302
    154303    /* Set x509 credentials */
    155     gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
     304    gnutls_credentials_set(ctxt->session,
     305                           GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
    156306    /* Set Anon credentials */
    157     gnutls_credentials_set(session, GNUTLS_CRD_ANON, ctxt->sc->anon_creds);
     307    gnutls_credentials_set(ctxt->session, GNUTLS_CRD_ANON,
     308                           ctxt->sc->anon_creds);
    158309
    159310#ifdef ENABLE_SRP
    160311        /* Set SRP credentials */
    161312    if (ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) {
    162         gnutls_credentials_set(session, GNUTLS_CRD_SRP, ctxt->sc->srp_creds);
     313        gnutls_credentials_set(ctxt->session, GNUTLS_CRD_SRP,
     314                               ctxt->sc->srp_creds);
    163315    }
    164316#endif
    165317
    166     /* update the priorities - to avoid negotiating a ciphersuite that is not
     318    /* Enable session tickets */
     319    if (session_ticket_key.data != NULL &&
     320        ctxt->sc->tickets == GNUTLS_ENABLED_TRUE)
     321    {
     322        ret = gnutls_session_ticket_enable_server(ctxt->session, &session_ticket_key);
     323        if (ret != GNUTLS_E_SUCCESS)
     324            ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, ctxt->c,
     325                          "gnutls_session_ticket_enable_server failed: %s (%d)",
     326                          gnutls_strerror(ret), ret);
     327    }
     328
     329    /* Update the priorities - to avoid negotiating a ciphersuite that is not
    167330     * enabled on this virtual server. Note that here we ignore the version
    168      * negotiation.
    169      */
    170 
    171     ret = gnutls_priority_set(session, ctxt->sc->priorities);
     331     * negotiation. */
     332    ret = gnutls_priority_set(ctxt->session, ctxt->sc->priorities);
     333
     334    return ret;
     335}
     336
     337
     338
     339/**
     340 * Post client hello hook function for GnuTLS. This function has two
     341 * purposes: Firstly, it acts as a fallback for early_sni_hook(), by
     342 * parsing SNI and selecting a virtual host based on it if
     343 * necessary. Secondly, it calls ALPN processing.
     344 *
     345 * @param session the TLS session
     346 *
     347 * @return zero or a GnuTLS error code, as required by GnuTLS hook
     348 * definition
     349 */
     350static int post_client_hello_hook(gnutls_session_t session)
     351{
     352    int ret = 0;
     353    mgs_handle_t *ctxt = gnutls_session_get_ptr(session);
     354
     355    /* If ctxt->sni_name is set at this point the early_sni_hook()
     356     * function ran, found an SNI server name, selected a virtual
     357     * host, and set up credentials, so we don't need to do that
     358     * again. Otherwise try again, to cover GnuTLS versions < 3.6.3
     359     * and pick up future extensions to gnutls_server_name_get(). */
     360    if (ctxt->sni_name == NULL)
     361    {
     362        /* try to find a virtual host */
     363        mgs_srvconf_rec *tsc = mgs_find_sni_server(ctxt);
     364        if (tsc != NULL)
     365        {
     366            /* Found a TLS vhost based on the SNI, configure the
     367             * connection context. */
     368            ctxt->sc = tsc;
     369        }
     370
     371        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
     372                      "%s: Loading credentials in post client hello hook",
     373                      __func__);
     374        reload_session_credentials(ctxt);
     375    }
     376
     377    ret = process_alpn_result(ctxt);
     378    if (ret != GNUTLS_E_SUCCESS)
     379        return ret;
     380
    172381    /* actually it shouldn't fail since we have checked at startup */
    173382    return ret;
    174 
    175383}
    176384
     
    201409        *privkey = ctxt->sc->privkey_x509;
    202410        return 0;
    203     } else if (gnutls_certificate_type_get(session) == GNUTLS_CRT_OPENPGP) {
    204                 // OPENPGP CERTIFICATE
    205         *pcerts = ctxt->sc->cert_pgp;
    206         *pcert_length = 1;
    207         *privkey = ctxt->sc->privkey_pgp;
    208         return 0;
    209411    } else {
    210412                // UNKNOWN CERTIFICATE
     
    213415}
    214416
    215 /* Read the common name or the alternative name of the certificate.
    216  * We only support a single name per certificate.
    217  *
    218  * Returns negative on error.
     417
     418
     419#if GNUTLS_VERSION_NUMBER >= 0x030506
     420#define HAVE_KNOWN_DH_GROUPS 1
     421#endif
     422#ifdef HAVE_KNOWN_DH_GROUPS
     423/**
     424 * Try to estimate a GnuTLS security parameter based on the given
     425 * private key. Any errors are logged.
     426 *
     427 * @param s The `server_rec` to use for logging
     428 *
     429 * @param key The private key to use
     430 *
     431 * @return `gnutls_sec_param_t` as returned by
     432 * `gnutls_pk_bits_to_sec_param` for the key properties, or
     433 * GNUTLS_SEC_PARAM_UNKNOWN in case of error
    219434 */
    220 static int read_crt_cn(server_rec * s, apr_pool_t * p, gnutls_x509_crt_t cert, char **cert_cn) {
    221 
    222     int rv = 0;
    223     size_t data_len;
    224 
    225 
    226     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    227     *cert_cn = NULL;
    228 
    229     data_len = 0;
    230     rv = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, NULL, &data_len);
    231 
    232     if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
    233         *cert_cn = apr_palloc(p, data_len);
    234         rv = gnutls_x509_crt_get_dn_by_oid(cert,
    235                 GNUTLS_OID_X520_COMMON_NAME,
    236                 0, 0, *cert_cn,
    237                 &data_len);
    238     } else { /* No CN return subject alternative name */
    239         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
    240                 "No common name found in certificate for '%s:%d'. Looking for subject alternative name...",
    241                 s->server_hostname, s->port);
    242         rv = 0;
    243         /* read subject alternative name */
    244         for (int i = 0; !(rv < 0); i++)
    245         {
    246             data_len = 0;
    247             rv = gnutls_x509_crt_get_subject_alt_name(cert, i,
    248                     NULL,
    249                     &data_len,
    250                     NULL);
    251 
    252             if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER
    253                     && data_len > 1) {
    254                 /* FIXME: not very efficient. What if we have several alt names
    255                  * before DNSName?
    256                  */
    257                 *cert_cn = apr_palloc(p, data_len + 1);
    258 
    259                 rv = gnutls_x509_crt_get_subject_alt_name
    260                         (cert, i, *cert_cn, &data_len, NULL);
    261                 (*cert_cn)[data_len] = 0;
    262 
    263                 if (rv == GNUTLS_SAN_DNSNAME)
    264                     break;
    265             }
    266         }
    267     }
    268 
    269     return rv;
    270 }
    271 
    272 static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p,
    273         gnutls_openpgp_crt_t cert, char **cert_cn) {
    274     int rv = 0;
    275     size_t data_len;
    276 
    277 
    278     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    279     *cert_cn = NULL;
    280 
    281     data_len = 0;
    282     rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len);
    283 
    284     if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
    285         *cert_cn = apr_palloc(p, data_len);
    286         rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn,
    287                 &data_len);
    288     } else { /* No CN return subject alternative name */
    289         ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
    290                 "No name found in PGP certificate for '%s:%d'.",
    291                 s->server_hostname, s->port);
    292     }
    293 
    294     return rv;
    295 }
    296 
    297 int mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog __attribute__((unused)), apr_pool_t * ptemp __attribute__((unused)), server_rec * base_server) {
    298 
     435static gnutls_sec_param_t sec_param_from_privkey(server_rec *server,
     436                                                 gnutls_privkey_t key)
     437{
     438    unsigned int bits = 0;
     439    int pk_algo = gnutls_privkey_get_pk_algorithm(key, &bits);
     440    if (pk_algo < 0)
     441    {
     442        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server,
     443                     "%s: Could not get private key parameters: %s (%d)",
     444                     __func__, gnutls_strerror(pk_algo), pk_algo);
     445        return GNUTLS_SEC_PARAM_UNKNOWN;
     446    }
     447    return gnutls_pk_bits_to_sec_param(pk_algo, bits);
     448}
     449#else
     450/** ffdhe2048 DH group as defined in RFC 7919, Appendix A.1. This is
     451 * the default DH group if mod_gnutls is compiled agains a GnuTLS
     452 * version that does not provide known DH groups based on security
     453 * parameters (before 3.5.6). */
     454static const char FFDHE2048_PKCS3[] =
     455    "-----BEGIN DH PARAMETERS-----\n"
     456    "MIIBDAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n"
     457    "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n"
     458    "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n"
     459    "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n"
     460    "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n"
     461    "ssbzSibBsu/6iGtCOGEoXJf//////////wIBAgICAQA=\n"
     462    "-----END DH PARAMETERS-----\n";
     463const gnutls_datum_t default_dh_params = {
     464    (void *) FFDHE2048_PKCS3,
     465    sizeof(FFDHE2048_PKCS3)
     466};
     467#endif
     468
     469
     470
     471/**
     472 * Configure the default DH groups to use for the given server. When
     473 * compiled against GnuTLS version 3.5.6 or newer the known DH group
     474 * matching the GnuTLS security parameter estimated from the private
     475 * key is used. Otherwise the ffdhe2048 DH group as defined in RFC
     476 * 7919, Appendix A.1 is the default.
     477 *
     478 * @param server the host to configure
     479 *
     480 * @return `OK` on success, `HTTP_UNAUTHORIZED` otherwise
     481 */
     482static int set_default_dh_param(server_rec *server)
     483{
     484    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
     485        ap_get_module_config(server->module_config, &gnutls_module);
     486
     487#ifdef HAVE_KNOWN_DH_GROUPS
     488    gnutls_sec_param_t seclevel = GNUTLS_SEC_PARAM_UNKNOWN;
     489    if (sc->privkey_x509)
     490    {
     491        seclevel = sec_param_from_privkey(server, sc->privkey_x509);
     492        ap_log_error(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, server,
     493                     "%s: GnuTLS security param estimated based on "
     494                     "private key '%s': %s",
     495                     __func__, sc->x509_key_file,
     496                     gnutls_sec_param_get_name(seclevel));
     497    }
     498
     499    if (seclevel == GNUTLS_SEC_PARAM_UNKNOWN)
     500        seclevel = GNUTLS_SEC_PARAM_MEDIUM;
     501    ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, server,
     502                 "%s: Setting DH params for security level '%s'.",
     503                 __func__, gnutls_sec_param_get_name(seclevel));
     504
     505    int ret = gnutls_certificate_set_known_dh_params(sc->certs, seclevel);
     506    if (ret < 0)
     507    {
     508        ap_log_error(APLOG_MARK, APLOG_EMERG, APR_EGENERAL, server,
     509                     "%s: setting known DH params failed: %s (%d)",
     510                     __func__, gnutls_strerror(ret), ret);
     511        return HTTP_UNAUTHORIZED;
     512    }
     513    ret = gnutls_anon_set_server_known_dh_params(sc->anon_creds, seclevel);
     514    if (ret < 0)
     515    {
     516        ap_log_error(APLOG_MARK, APLOG_EMERG, APR_EGENERAL, server,
     517                     "%s: setting known DH params failed: %s (%d)",
     518                     __func__, gnutls_strerror(ret), ret);
     519        return HTTP_UNAUTHORIZED;
     520    }
     521#else
     522    int ret = gnutls_dh_params_init(&sc->dh_params);
     523    if (ret < 0)
     524    {
     525        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, server,
     526                     "%s: Failed to initialize DH params structure: "
     527                     "%s (%d)", __func__, gnutls_strerror(ret), ret);
     528        return HTTP_UNAUTHORIZED;
     529    }
     530    ret = gnutls_dh_params_import_pkcs3(sc->dh_params, &default_dh_params,
     531                                        GNUTLS_X509_FMT_PEM);
     532    if (ret < 0)
     533    {
     534        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, server,
     535                     "%s: Failed to import default DH params: %s (%d)",
     536                     __func__, gnutls_strerror(ret), ret);
     537        return HTTP_UNAUTHORIZED;
     538    }
     539
     540    gnutls_certificate_set_dh_params(sc->certs, sc->dh_params);
     541    gnutls_anon_set_server_dh_params(sc->anon_creds, sc->dh_params);
     542#endif
     543
     544    return OK;
     545}
     546
     547
     548
     549/**
     550 * Post config hook.
     551 *
     552 * Must return OK or DECLINED on success, something else on
     553 * error. These codes are defined in Apache httpd.h along with the
     554 * HTTP status codes, so I'm going to use HTTP error codes both for
     555 * fun (and to avoid conflicts).
     556 */
     557int mgs_hook_post_config(apr_pool_t *pconf,
     558                         apr_pool_t *plog __attribute__((unused)),
     559                         apr_pool_t *ptemp,
     560                         server_rec *base_server)
     561{
    299562    int rv;
    300563    server_rec *s;
    301     gnutls_dh_params_t dh_params = NULL;
    302564    mgs_srvconf_rec *sc;
    303565    mgs_srvconf_rec *sc_base;
     
    316578
    317579
    318     rv = mgs_cache_post_config(p, s, sc_base);
    319     if (rv != 0) {
     580    rv = mgs_cache_post_config(pconf, ptemp, s, sc_base);
     581    if (rv != APR_SUCCESS)
     582    {
    320583        ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s,
    321                 "GnuTLS: Post Config for GnuTLSCache Failed."
    322                 " Shutting Down.");
    323         exit(-1);
     584                     "Post config for cache failed.");
     585        return HTTP_INSUFFICIENT_STORAGE;
     586    }
     587
     588    if (sc_base->ocsp_mutex == NULL)
     589    {
     590        rv = ap_global_mutex_create(&sc_base->ocsp_mutex, NULL,
     591                                    MGS_OCSP_MUTEX_NAME, NULL,
     592                                    base_server, pconf, 0);
     593        if (rv != APR_SUCCESS)
     594            return rv;
    324595    }
    325596
     
    344615                rv = gnutls_pkcs11_add_provider(p11_module, NULL);
    345616                if (rv != GNUTLS_E_SUCCESS)
    346                     ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     617                    ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EGENERAL, s,
    347618                                 "GnuTLS: Loading PKCS #11 provider module %s "
    348619                                 "failed: %s (%d).",
    349620                                 p11_module, gnutls_strerror(rv), rv);
     621                else
     622                    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
     623                                 "%s: PKCS #11 provider module %s loaded.",
     624                                 __func__, p11_module);
    350625            }
    351626        }
    352627    }
    353628
    354     for (s = base_server; s; s = s->next) {
     629    sc_base->singleton_wd =
     630        mgs_new_singleton_watchdog(base_server, MGS_SINGLETON_WATCHDOG, pconf);
     631
     632    for (s = base_server; s; s = s->next)
     633    {
    355634        sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
    356         sc->cache_type = sc_base->cache_type;
    357         sc->cache_config = sc_base->cache_config;
    358         sc->cache_timeout = sc_base->cache_timeout;
    359 
    360         rv = mgs_load_files(p, s);
    361         if (rv != 0) {
    362             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    363                 "GnuTLS: Loading required files failed."
    364                 " Shutting Down.");
    365             exit(-1);
    366         }
     635        sc->s = s;
     636        sc->cache_enable = sc_base->cache_enable;
     637        sc->cache = sc_base->cache;
     638        if (sc->cache_timeout == MGS_TIMEOUT_UNSET)
     639            sc->cache_timeout = sc_base->cache_timeout;
     640        sc->ocsp_cache = sc_base->ocsp_cache;
     641
     642        sc->singleton_wd = sc_base->singleton_wd;
    367643
    368644        /* defaults for unset values: */
     
    370646            sc->enabled = GNUTLS_ENABLED_FALSE;
    371647        if (sc->tickets == GNUTLS_ENABLED_UNSET)
    372             sc->tickets = GNUTLS_ENABLED_TRUE;
     648        {
     649            /* GnuTLS 3.6.4 introduced automatic master key rotation */
     650            if (gnutls_check_version_numeric(3, 6, 4))
     651                sc->tickets = GNUTLS_ENABLED_TRUE;
     652            else
     653                sc->tickets = GNUTLS_ENABLED_FALSE;
     654        }
    373655        if (sc->export_certificates_size < 0)
    374656            sc->export_certificates_size = 0;
     
    378660            sc->client_verify_method = mgs_cvm_cartel;
    379661
     662        // TODO: None of the stuff below needs to be done if
     663        // sc->enabled == GNUTLS_ENABLED_FALSE, we could just continue
     664        // to the next host.
     665
     666        /* Load certificates and stuff (includes parsing priority) */
     667        rv = mgs_load_files(pconf, ptemp, s);
     668        if (rv != 0) {
     669            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     670                         "%s: Loading credentials failed!", __func__);
     671            return HTTP_NOT_FOUND;
     672        }
     673
     674        sc->ocsp_mutex = sc_base->ocsp_mutex;
     675        /* init OCSP configuration unless explicitly disabled */
     676        if (sc->enabled && sc->ocsp_staple != GNUTLS_ENABLED_FALSE)
     677        {
     678            const char *err = mgs_ocsp_configure_stapling(pconf, ptemp, s);
     679            if (err != NULL)
     680            {
     681                /* If OCSP stapling is enabled only by default ignore
     682                 * error and disable stapling */
     683                if (sc->ocsp_staple == GNUTLS_ENABLED_UNSET)
     684                {
     685                    ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, s,
     686                                 "Cannnot enable OCSP stapling for "
     687                                 "host '%s:%d': %s",
     688                                 s->server_hostname, s->addrs->host_port, err);
     689                    sc->ocsp_staple = GNUTLS_ENABLED_FALSE;
     690                }
     691                /* If OCSP stapling is explicitly enabled this is a
     692                 * critical error. */
     693                else
     694                {
     695                    ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EINVAL, s,
     696                                 "OCSP stapling configuration failed for "
     697                                 "host '%s:%d': %s",
     698                                 s->server_hostname, s->addrs->host_port, err);
     699                    return HTTP_INTERNAL_SERVER_ERROR;
     700                }
     701            }
     702            else
     703            {
     704                /* Might already be set */
     705                sc->ocsp_staple = GNUTLS_ENABLED_TRUE;
     706                /* Set up stapling */
     707                rv = mgs_ocsp_enable_stapling(pconf, ptemp, s);
     708                if (rv != OK && rv != DECLINED)
     709                    return rv;
     710            }
     711        }
     712
    380713        /* Check if the priorities have been set */
    381714        if (sc->priorities == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
    382             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    383                     "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!",
    384                     s->server_hostname, s->port);
    385             exit(-1);
    386         }
    387 
    388         /* Check if DH params have been set per host */
     715            ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
     716                         "No GnuTLSPriorities directive for host '%s:%d', "
     717                         "using default '%s'.",
     718                         s->server_hostname, s->addrs->host_port,
     719                         MGS_DEFAULT_PRIORITY);
     720            sc->priorities = mgs_get_default_prio();
     721        }
     722
     723        /* Set host DH params from user configuration or defaults */
    389724        if (sc->dh_params != NULL) {
    390725            gnutls_certificate_set_dh_params(sc->certs, sc->dh_params);
    391726            gnutls_anon_set_server_dh_params(sc->anon_creds, sc->dh_params);
    392         } else if (dh_params) {
    393             gnutls_certificate_set_dh_params(sc->certs, dh_params);
    394             gnutls_anon_set_server_dh_params(sc->anon_creds, dh_params);
     727        } else {
     728            rv = set_default_dh_param(s);
     729            if (rv != OK)
     730                return rv;
    395731        }
    396732
     
    411747
    412748        if ((sc->certs_x509_chain == NULL || sc->certs_x509_chain_num < 1) &&
    413             sc->cert_pgp == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
     749            sc->enabled == GNUTLS_ENABLED_TRUE) {
    414750                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    415751                                                "GnuTLS: Host '%s:%d' is missing a Certificate File!",
    416                                                 s->server_hostname, s->port);
    417             exit(-1);
     752                                                s->server_hostname, s->addrs->host_port);
     753            return HTTP_UNAUTHORIZED;
    418754        }
    419755        if (sc->enabled == GNUTLS_ENABLED_TRUE &&
    420             ((sc->certs_x509_chain_num > 0 && sc->privkey_x509 == NULL) ||
    421              (sc->cert_crt_pgp[0] != NULL && sc->privkey_pgp == NULL))) {
     756            (sc->certs_x509_chain_num > 0 && sc->privkey_x509 == NULL))
     757        {
    422758                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    423759                                                "GnuTLS: Host '%s:%d' is missing a Private Key File!",
    424                                                 s->server_hostname, s->port);
    425             exit(-1);
    426         }
    427 
    428         if (sc->enabled == GNUTLS_ENABLED_TRUE) {
    429             rv = -1;
    430             if (sc->certs_x509_chain_num > 0) {
    431                 rv = read_crt_cn(s, p, sc->certs_x509_crt_chain[0], &sc->cert_cn);
    432             }
    433             if (rv < 0 && sc->cert_pgp != NULL) {
    434                 rv = read_pgpcrt_cn(s, p, sc->cert_crt_pgp[0], &sc->cert_cn);
    435                         }
    436 
    437             if (rv < 0) {
    438                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    439                                                         "GnuTLS: Cannot find a certificate for host '%s:%d'!",
    440                                                         s->server_hostname, s->port);
    441                 sc->cert_cn = NULL;
    442                 continue;
    443             }
     760                                                s->server_hostname, s->addrs->host_port);
     761            return HTTP_UNAUTHORIZED;
    444762        }
    445763
    446764        if (sc->enabled == GNUTLS_ENABLED_TRUE
    447765            && sc->proxy_enabled == GNUTLS_ENABLED_TRUE
    448             && load_proxy_x509_credentials(s) != APR_SUCCESS)
     766            && load_proxy_x509_credentials(pconf, ptemp, s) != APR_SUCCESS)
    449767        {
    450768            ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    451769                         "%s: loading proxy credentials for host "
    452770                         "'%s:%d' failed, exiting!",
    453                          __func__, s->server_hostname, s->port);
    454             exit(-1);
    455         }
    456     }
    457 
    458 
    459     ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION);
     771                         __func__, s->server_hostname, s->addrs->host_port);
     772            return HTTP_PROXY_AUTHENTICATION_REQUIRED;
     773        }
     774    }
     775
     776
     777    ap_add_version_component(pconf, "mod_gnutls/" MOD_GNUTLS_VERSION);
    460778
    461779    {
    462780        const char* libvers = gnutls_check_version(NULL);
    463781        char* gnutls_version = NULL;
    464         if(libvers && (gnutls_version = apr_psprintf(p, "GnuTLS/%s", libvers))) {
    465             ap_add_version_component(p, gnutls_version);
     782        if(libvers && (gnutls_version = apr_psprintf(pconf, "GnuTLS/%s", libvers))) {
     783            ap_add_version_component(pconf, gnutls_version);
    466784        } else {
    467785            // In case we could not create the above string go for the static version instead
    468             ap_add_version_component(p, "GnuTLS/" GNUTLS_VERSION "-static");
     786            ap_add_version_component(pconf, "GnuTLS/" GNUTLS_VERSION "-static");
    469787        }
    470788    }
     
    473791}
    474792
    475 void mgs_hook_child_init(apr_pool_t * p, server_rec *s) {
     793void mgs_hook_child_init(apr_pool_t *p, server_rec *s)
     794{
    476795    apr_status_t rv = APR_SUCCESS;
    477     mgs_srvconf_rec *sc =
    478         (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
     796    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
     797        ap_get_module_config(s->module_config, &gnutls_module);
    479798
    480799    _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
     800
    481801    /* if we use PKCS #11 reinitialize it */
    482 
    483802    if (mgs_pkcs11_reinit(s) < 0) {
    484803            ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
     
    487806    }
    488807
    489     if (sc->cache_type != mgs_cache_none) {
    490         rv = mgs_cache_child_init(p, s, sc);
    491         if (rv != APR_SUCCESS) {
     808    if (sc->cache_enable == GNUTLS_ENABLED_TRUE)
     809    {
     810        rv = mgs_cache_child_init(p, s, sc->cache, MGS_CACHE_MUTEX_NAME);
     811        if (rv != APR_SUCCESS)
    492812            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
    493                     "GnuTLS: Failed to run Cache Init");
    494         }
    495     }
     813                    "Child init for session cache failed!");
     814    }
     815
     816    if (sc->ocsp_cache != NULL)
     817    {
     818        rv = mgs_cache_child_init(p, s, sc->ocsp_cache,
     819                                  MGS_OCSP_CACHE_MUTEX_NAME);
     820        if (rv != APR_SUCCESS)
     821            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
     822                    "Child init for OCSP cache failed!");
     823    }
     824
     825    /* reinit OCSP request mutex */
     826    const char *lockfile = apr_global_mutex_lockfile(sc->ocsp_mutex);
     827    rv = apr_global_mutex_child_init(&sc->ocsp_mutex, lockfile, p);
     828    if (rv != APR_SUCCESS)
     829        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
     830                     "Failed to reinit mutex '" MGS_OCSP_MUTEX_NAME "'.");
     831
    496832    /* Block SIGPIPE Signals */
    497833    rv = apr_signal_block(SIGPIPE);
     
    539875}
    540876
    541 #define MAX_HOST_LEN 255
    542 
    543 #if USING_2_1_RECENT
     877
    544878
    545879typedef struct {
     
    554888 * @param x vhost callback record
    555889 * @param s server record
     890 * @param tsc mod_gnutls server data for `s`
     891 *
    556892 * @return true if a match, false otherwise
    557893 *
    558894 */
    559 int check_server_aliases(vhost_cb_rec *x, server_rec * s, mgs_srvconf_rec *tsc) {
    560         apr_array_header_t *names;
    561         int rv = 0;
    562         char ** name;
    563 
    564         /* Check ServerName First! */
    565         if(apr_strnatcasecmp(x->sni_name, s->server_hostname) == 0) {
    566                 // We have a match, save this server configuration
    567                 x->sc = tsc;
    568                 rv = 1;
    569         /* Check any ServerAlias directives */
    570         } else if(s->names->nelts) {
    571                 names = s->names;
    572                 name = (char **)names->elts;
    573                 for (int i = 0; i < names->nelts; ++i)
     895int check_server_aliases(vhost_cb_rec *x, server_rec * s, mgs_srvconf_rec *tsc)
     896{
     897    apr_array_header_t *names;
     898    int rv = 0;
     899    char ** name;
     900
     901    /* Check ServerName First! */
     902    if (strcasecmp(x->sni_name, s->server_hostname) == 0) {
     903        // We have a match, save this server configuration
     904        x->sc = tsc;
     905        rv = 1;
     906        /* Check any ServerAlias directives */
     907    } else if(s->names->nelts) {
     908        names = s->names;
     909        name = (char **) names->elts;
     910        for (int i = 0; i < names->nelts; ++i)
    574911        {
    575                         if (!name[i]) { continue; }
    576                                 if (apr_strnatcasecmp(x->sni_name, name[i]) == 0) {
    577                                         // We have a match, save this server configuration
    578                                         x->sc = tsc;
    579                                         rv = 1;
    580                         }
    581                 }
    582         /* Wild any ServerAlias Directives */
    583         } else if(s->wild_names->nelts) {
    584                 names = s->wild_names;
    585         name = (char **)names->elts;
    586                 for (int i = 0; i < names->nelts; ++i)
     912            if (!name[i])
     913                continue;
     914            if (strcasecmp(x->sni_name, name[i]) == 0)
     915            {
     916                // We have a match, save this server configuration
     917                x->sc = tsc;
     918                rv = 1;
     919            }
     920        }
     921        /* ServerAlias directives may contain wildcards, check those last. */
     922    } else if(s->wild_names->nelts) {
     923        names = s->wild_names;
     924        name = (char **) names->elts;
     925        for (int i = 0; i < names->nelts; ++i)
    587926        {
    588                         if (!name[i]) { continue; }
    589                                 if(apr_fnmatch(name[i], x->sni_name ,
    590                                                                 APR_FNM_CASE_BLIND|
    591                                                                 APR_FNM_PERIOD|
    592                                                                 APR_FNM_PATHNAME|
    593                                                                 APR_FNM_NOESCAPE) == APR_SUCCESS) {
    594                                 x->sc = tsc;
    595                                 rv = 1;
    596                         }
    597                 }
    598         }
    599         return rv;
    600 }
    601 
    602 static int vhost_cb(void *baton, conn_rec * conn __attribute__((unused)), server_rec * s) {
     927            if (!name[i])
     928                continue;
     929            if (ap_strcasecmp_match(x->sni_name, name[i]) == 0)
     930            {
     931                x->sc = tsc;
     932                rv = 1;
     933            }
     934        }
     935    }
     936    return rv;
     937}
     938
     939static int vhost_cb(void *baton, conn_rec *conn, server_rec * s)
     940{
    603941    mgs_srvconf_rec *tsc;
    604942    vhost_cb_rec *x = baton;
     
    609947            &gnutls_module);
    610948
    611     if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) {
     949    if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
    612950        return 0;
    613951    }
     
    618956        ret = gnutls_x509_crt_check_hostname(tsc->certs_x509_crt_chain[0], s->server_hostname);
    619957        if (0 == ret)
    620             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
    621                          "GnuTLS: the certificate doesn't match requested hostname "
    622                          "'%s'", s->server_hostname);
     958            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, conn,
     959                          "GnuTLS: the certificate doesn't match requested "
     960                          "hostname '%s'", s->server_hostname);
    623961    } else {
    624         ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
    625                      "GnuTLS: SNI request for '%s' but no X.509 certs available at all",
    626                      s->server_hostname);
     962        ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, conn,
     963                      "GnuTLS: SNI request for '%s' but no X.509 certs "
     964                      "available at all",
     965                      s->server_hostname);
    627966    }
    628967        return check_server_aliases(x, s, tsc);
    629968}
    630 #endif
    631 
    632 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
     969
     970/**
     971 * Get SNI data from GnuTLS (if any) and search for a matching virtual
     972 * host configuration. This method is called from the post client
     973 * hello function.
     974 *
     975 * @param ctxt the mod_gnutls connection handle
     976 *
     977 * @return either the matching mod_gnutls server config, or `NULL`
     978 */
     979mgs_srvconf_rec *mgs_find_sni_server(mgs_handle_t *ctxt)
    633980{
    634     int rv;
    635     unsigned int sni_type;
    636     size_t data_len = MAX_HOST_LEN;
    637     char sni_name[MAX_HOST_LEN];
    638     mgs_handle_t *ctxt;
    639 #if USING_2_1_RECENT
    640     vhost_cb_rec cbx;
    641 #else
    642     server_rec *s;
    643     mgs_srvconf_rec *tsc;
    644 #endif
    645 
    646     if (session == NULL)
    647         return NULL;
    648 
    649     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    650     ctxt = gnutls_transport_get_ptr(session);
    651 
    652     rv = gnutls_server_name_get(ctxt->session, sni_name,
    653             &data_len, &sni_type, 0);
    654 
    655     if (rv != 0) {
    656         return NULL;
    657     }
    658 
    659     if (sni_type != GNUTLS_NAME_DNS) {
    660         ap_log_error(APLOG_MARK, APLOG_CRIT, 0,
    661                 ctxt->c->base_server,
    662                 "GnuTLS: Unknown type '%d' for SNI: "
    663                 "'%s'", sni_type, sni_name);
    664         return NULL;
    665     }
    666 
    667     /**
    668      * Code in the Core already sets up the c->base_server as the base
    669      * for this IP/Port combo.  Trust that the core did the 'right' thing.
    670      */
    671 #if USING_2_1_RECENT
    672     cbx.ctxt = ctxt;
    673     cbx.sc = NULL;
    674     cbx.sni_name = sni_name;
    675 
    676     rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
     981    if (ctxt->sni_name == NULL)
     982    {
     983        const char *sni_name = mgs_server_name_get(ctxt);
     984        if (sni_name != NULL)
     985            ctxt->sni_name = sni_name;
     986        else
     987            return NULL;
     988    }
     989
     990    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
     991                  "%s: client requested server '%s'.",
     992                  __func__, ctxt->sni_name);
     993
     994    /* Search for vhosts matching connection parameters and the
     995     * SNI. If a match is found, cbx.sc will contain the mod_gnutls
     996     * server config for the vhost. */
     997    vhost_cb_rec cbx = {
     998        .ctxt = ctxt,
     999        .sc = NULL,
     1000        .sni_name = ctxt->sni_name
     1001    };
     1002    int rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
    6771003    if (rv == 1) {
    6781004        return cbx.sc;
    6791005    }
    680 #else
    681     for (s = ap_server_conf; s; s = s->next) {
    682 
    683         tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config,
    684                                                        &gnutls_module);
    685 
    686         if (tsc->enabled != GNUTLS_ENABLED_TRUE) { continue; }
    687 
    688         if(check_server_aliases(x, s, tsc)) {
    689             return tsc;
    690         }
    691     }
     1006    return NULL;
     1007}
     1008
     1009
     1010
     1011#ifdef ENABLE_EARLY_SNI
     1012/**
     1013 * Pre client hello hook function for GnuTLS that implements early SNI
     1014 * processing using `gnutls_ext_raw_parse()` (available since GnuTLS