Changeset 19e80a5 in mod_gnutls


Ignore:
Timestamp:
Jan 28, 2019, 2:50:38 PM (8 weeks ago)
Author:
Fiona Klute <fiona.klute@…>
Branches:
debian/master
Children:
102aa67
Parents:
0931b35 (diff), ea9c699 (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:

Update upstream source from tag 'upstream/0.9.0'

Update to upstream version '0.9.0'
with Debian dir 619b546038886b240d2c8e61ee1a1b13ce0867d7

Files:
43 added
10 deleted
68 edited
2 moved

Legend:

Unmodified
Added
Removed
  • CHANGELOG

    r0931b35 r19e80a5  
     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
    140** Version 0.8.4 (2018-04-13)
    241- Support Apache HTTPD 2.4.33 API for proxy TLS connections
  • Makefile.am

    r0931b35 r19e80a5  
    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
    10 AM_DISTCHECK_CONFIGURE_FLAGS = "--enable-vpath-install"
     9AM_DISTCHECK_CONFIGURE_FLAGS = "--enable-vpath-install" \
     10        "SOFTHSM_LIB='$(SOFTHSM_LIB)'"
    1111DISTCLEANFILES = config.nice
    1212MOSTLYCLEANFILES = $(DX_CLEANFILES)
  • configure.ac

    r0931b35 r19e80a5  
    1 AC_INIT(mod_gnutls, 0.8.4)
     1AC_INIT(mod_gnutls, 0.9.0)
    22OOO_CONFIG_NICE(config.nice)
    33MOD_GNUTLS_VERSION=AC_PACKAGE_VERSION
     
    3030    AC_MSG_ERROR([*** Apache version $AP_VERSION not found!])
    3131)
     32
     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        ], [])
    3247
    3348PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 3.3.0])
     
    5267AC_SEARCH_LIBS([gnutls_srp_server_get_username], [gnutls], [], [use_srp="no"])
    5368
    54 SRP_CFLAGS=""
     69GNUTLS_FEAT_CFLAGS=""
    5570if test "$use_srp" != "no"; then
    56         SRP_CFLAGS="-DENABLE_SRP=1"
    57 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)
    5888
    5989AC_ARG_ENABLE(strict,
     
    127157dnl Enable test namespaces? Default is "yes".
    128158AC_ARG_ENABLE(test-namespaces,
    129         AS_HELP_STRING([--disable-test-namespaces], [Disable use of network \
    130         namespaces to run tests in parallel (some architectures might not \
    131         support it)]),
     159        AS_HELP_STRING([--disable-test-namespaces], [Disable use of \
     160        namespaces for tests (limits parallelization)]),
    132161        [use_netns=$enableval], [use_netns=yes])
    133162
    134 # Check if "unshare" is available and has permission to create network
    135 # and user namespaces
     163# Check if "unshare" is available and has permission to create
     164# network, IPC, and user namespaces
    136165AC_PATH_PROG([UNSHARE], [unshare], [no])
    137166AS_IF([test "${UNSHARE}" != "no"],
    138167      [
    139         AC_MSG_CHECKING([for permission to create network and user namespaces])
    140         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 \
    141170                "ip link set up lo && ip addr show" >&AS_MESSAGE_LOG_FD 2>&1],
    142171              [unshare_works="yes"], [unshare_works="no"])
     
    177206AC_MSG_RESULT($use_msva)
    178207
    179 have_apr_memcache=0
    180 CHECK_APR_MEMCACHE([have_apr_memcache=1], [have_apr_memcache=0])
    181 AC_SUBST(have_apr_memcache)
    182 
    183208# Building documentation requires pandoc, which in turn needs pdflatex
    184209# to build PDF output.
     
    188213        AC_PATH_PROG([PDFLATEX], [pdflatex], [no])
    189214        if test "$PDFLATEX" != "no"; then
    190                 build_doc=yes
     215                build_doc="html, manual page, pdf"
    191216        else
    192                 build_doc="html only"
     217                build_doc="html, manual page"
    193218        fi
    194219else
     
    213238AC_PATH_PROGS([HTTP_CLI], [curl wget], [no])
    214239
    215 MODULE_CFLAGS="${LIBGNUTLS_CFLAGS} ${SRP_CFLAGS} ${MSVA_CFLAGS} ${APR_MEMCACHE_CFLAGS} ${APXS_CFLAGS} ${AP_INCLUDES} ${APR_INCLUDES} ${APU_INCLUDES} ${STRICT_CFLAGS}"
    216 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}"
    217242
    218243AC_PATH_PROGS([SOFTHSM], [softhsm2-util softhsm], [no])
     
    241266                      "[::1] 127.0.0.1". Note that IPv6 addresses must be \
    242267                      enclosed in square brackets.])
    243 AM_SUBST_NOTMAKE(TEST_IP)
    244268
    245269: ${TEST_LOCK_WAIT:="30"}
     
    285309DX_RTF_FEATURE(OFF)
    286310DX_XML_FEATURE(OFF)
    287 DX_PDF_FEATURE(ON)
     311DX_PDF_FEATURE(OFF)
    288312DX_PS_FEATURE(OFF)
    289313DX_INIT_DOXYGEN([mod_gnutls], [doc/doxygen.conf], [doc/api])
     
    292316                        doc/Makefile doc/doxygen.conf include/mod_gnutls.h \
    293317                        test/proxy_backend.conf test/ocsp_server.conf \
     318                        test/apache-conf/early_sni.conf \
    294319                        test/apache-conf/listen.conf \
    295320                        test/apache-conf/netns.conf])
     
    306331echo "   * SRP Authentication:  ${use_srp}"
    307332echo "   * MSVA Client Verification:    ${use_msva}"
     333echo "   * Early SNI:                   ${early_sni}"
    308334echo "   * Build documentation: ${build_doc}"
    309335echo ""
  • doc/Makefile.am

    r0931b35 r19e80a5  
    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/doxygen.conf.in

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

    r0931b35 r19e80a5  
    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
     
    7192Configure TLS Session Cache
    7293
    73     GnuTLSCache [dbm|gdbm|memcache|none] [PATH|SERVERLIST|-]
     94    GnuTLSCache (shmcb|dbm|memcache|...|none)[:PARAMETERS]
    7495
    7596Default: `GnuTLSCache none`\
    7697Context: server config
    7798
    78 This directive configures the TLS Session Cache for `mod_gnutls`.
    79 This could be shared between machines of different architectures. If a
    80 DBM cache is used, access is serialized using the `gnutls-cache`
    81 mutex. Which DBM types are available is part of the APR (Apache
    82 Portable Runtime) compile time configuration.
    83 
    84 `dbm` (Requires Berkeley DBM)
    85 :   Uses the Berkeley DB backend of APR DBM to cache TLS Session
    86         data.
    87 
    88         The argument is a relative or absolute path to be used as
    89     the DBM Cache file. This is compatible with most operating
    90     systems.
    91 
    92 `gdbm` (Requires GDBM)
    93 :   Uses the GDBM backend of APR DBM to cache TLS Session data.
    94 
    95     The argument is a relative or absolute path to be used as the DBM
    96     Cache file.
     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`
    97124
    98125`memcache`
    99 :   Uses memcached server(s) to cache TLS Session data.
    100 
    101     The argument is a space separated list of servers. If no port
    102     number is supplied, the default of 11211 is used.  This can be
    103     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`
    104131
    105132`none`
    106 :   Turns off all caching of TLS Sessions.
    107 
    108     This can significantly reduce the performance of `mod_gnutls` since
    109     even followup connections by a client must renegotiate parameters
    110     instead of reusing old ones.  This is the default, since it
    111     requires no configuration.
     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.
    112144
    113145### GnuTLSCacheTimeout
     
    118150
    119151Default: `GnuTLSCacheTimeout 300`\
    120 Context: server config
    121 
    122 Sets the timeout for TLS Session Cache entries expiration. This value
    123 is also used for OCSP responses if they do not contain a `nextUpdate`
    124 time.
     152Context: server config, virtual host
     153
     154Sets the expiration timeout for cached TLS sessions.
    125155
    126156### GnuTLSSessionTickets
     
    130160    GnuTLSSessionTickets [on|off]
    131161
    132 Default: `off`\
    133 Context: server config, virtual host
    134 
    135 To avoid storing data for TLS session resumption the server can
    136 provide clients with tickets, to use on return. Tickets are an
    137 alternative to using a session cache, mostly used for busy servers
    138 with limited storage. For a pool of servers this option is not
    139 recommended since the tickets are bound to the issuing server only.
     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.
    140171
    141172If this option is set in the global configuration, virtual hosts
    142173without a `GnuTLSSessionTickets` setting will use the global setting.
    143174
    144 *Warning:* Currently the master key that protects the tickets is
    145 generated only on server start, and there is no mechanism to roll over
    146 the key. If session tickets are enabled it is highly recommened to
    147 restart the server regularly to protect past sessions in case an
    148 attacker gains access to server memory.
     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.
    149182
    150183### GnuTLSClientVerify
     
    204237    GnuTLSPriorities NORMAL:+CIPHER_0:+CIPHER_1:...:+CIPHER_N
    205238
    206 Default: *none*\
    207 Context: server config, virtual host
    208 
    209 Takes a colon separated list of protocol version, ciphers, key
    210 exchange methods message authentication codes, and compression methods
    211 to enable. The allowed keywords are specified in the
    212 `gnutls_priority_init()` function of GnuTLS.
    213 
    214 Please refer to [the GnuTLS documentation](https://gnutls.org/manual/html_node/Priority-Strings.html#Priority-Strings)
    215 for details. A few commonly used sets are listed below, note that
    216 their exact meaning may change with GnuTLS versions.
    217 
    218 `PERFORMANCE`
    219 :   A list with all the secure cipher combinations sorted in terms of
    220     performance.
    221 
    222 `NORMAL`
    223 :   A list with all the secure cipher combinations sorted
    224     with respect to security margin (subjective term).
    225 
    226 `SECURE128`
    227 :   A list with all the secure cipher suites that offer a security level
    228     of 128-bit or more.
    229 
    230 `PFS`
    231 :   Only cipher suites offering perfect forward secrecy (ECDHE and DHE),
    232     sorted by security margin.
    233 
    234 You can add or remove algorithms using the `+` and `!` prefixes
    235 respectively. For example, in order to use the `NORMAL` set but
    236 disable TLS 1.0 and 1.1 you can use the string
    237 `NORMAL:!VERS-TLS1.0:!VERS-TLS1.1`.
    238 
    239 You can find a list of all supported Ciphers, Versions, MACs, etc.  by
    240 running `gnutls-cli --list`.
     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`.
    241248
    242249### GnuTLSP11Module
     
    289296server and the client to CGI scripts via the `SSL_SERVER_CERT` and
    290297`SSL_CLIENT_CERT` environment variables. The exported certificates
    291 will be PEM-encoded (if X.509) or ASCII-armored (if OpenPGP) up to the
    292 size given.  The type of the certificate will be exported in
    293 `SSL_SERVER_CERT_TYPE` and `SSL_CLIENT_CERT_TYPE`.
     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`.
    294301
    295302SIZE should be an integer number of bytes, or may be written with a
    296303trailing `K` to indicate kibibytes.  `off` means the same thing as
    297304`0`, in which case the certificates will not be exported to the
    298 environment.  `on` is an alias for `16K`. If a non-zero size is
     305environment. `on` is an alias for `16K`. If a non-zero size is
    299306specified for this directive, but a certificate is too large to fit in
    300307the buffer, then the corresponding environment variable will contain
     
    309316### GnuTLSCertificateFile
    310317
    311 Set to the PEM Encoded Server Certificate
     318Set the PEM encoded server certificate or certificate chain
    312319
    313320    GnuTLSCertificateFile FILEPATH
     
    316323Context: server config, virtual host
    317324
    318 Takes an absolute or relative path to a PEM-encoded X.509 certificate to
    319 use as this Server's End Entity (EE) certificate. If you need to supply
    320 certificates for intermediate Certificate Authorities (iCAs), they
    321 should be listed in sequence in the file, from EE to the iCA closest to
    322 the root CA. Optionally, you can also include the root CA's certificate
    323 as the last certificate in the list.
    324 
    325 Since version 0.7 this can be a PKCS #11 URL.
     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
    326342
    327343### GnuTLSKeyFile
     
    357373as a Certificate Authority with Client Certificate Authentication.
    358374This file may contain a list of trusted authorities.
    359 
    360 OpenPGP Certificate Authentication
    361 ----------------------------------
    362 
    363 *Warning:* OpenPGP support has been deprecated in GnuTLS since version
    364 3.5.9 and will be removed completely. Consequently, OpenPGP support in
    365 `mod_gnutls` is deprecated as well and will be removed in a future
    366 release.
    367 
    368 ### GnuTLSPGPCertificateFile
    369 
    370 Set to a base64 Encoded Server OpenPGP Certificate
    371 
    372     GnuTLSPGPCertificateFile FILEPATH
    373 
    374 Default: *none*\
    375 Context: server config, virtual host
    376 
    377 Takes an absolute or relative path to a base64 Encoded OpenPGP
    378 Certificate to use as this Server's Certificate.
    379 
    380 ### GnuTLSPGPKeyFile
    381 
    382 Set to the Server OpenPGP Secret Key
    383 
    384     GnuTLSPGPKeyFile FILEPATH
    385 
    386 Default: *none*\
    387 Context: server config, virtual host
    388 
    389 Takes an absolute or relative path to the Server Private Key. This key
    390 cannot currently be password protected.
    391 
    392 **Security Warning:**\
    393  This private key must be protected. It is read while Apache is still
    394 running as root, and does not need to be readable by the nobody or
    395 apache user.
    396 
    397 ### GnuTLSPGPKeyringFile
    398 
    399 Set to a base64 Encoded key ring
    400 
    401     GnuTLSPGPKeyringFile FILEPATH
    402 
    403 Default: *none*\
    404 Context: server config, virtual host
    405 
    406 Takes an absolute or relative path to a base64 Encoded Certificate
    407 list (key ring) to use as a means of verification of Client
    408 Certificates.  This file should contain a list of trusted signers.
    409375
    410376SRP Authentication
     
    531497    GnuTLSProxyPriorities NORMAL:+CIPHER_0:+CIPHER_1:...:+CIPHER_N
    532498
    533 Default: *none*\
    534 Context: server config, virtual host
    535 
    536 This option is used to set the allowed ciphers, key exchange
    537 algorithms, MACs and compression methods for proxy connections. It
    538 takes the same parameters as `GnuTLSPriorities`. Required if
    539 `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).
    540507
    541508OCSP Stapling Configuration
     
    548515    GnuTLSOCSPStapling [On|Off]
    549516
    550 Default: *off*\
     517Default: *on* if requirements are met, *off* otherwise\
    551518Context: server config, virtual host
    552519
    553520OCSP stapling, formally known as the TLS Certificate Status Request
    554 extension, allows the server to provide the client with an OCSP
    555 response for its certificate during the handshake. This way the client
    556 does not have to send an OCSP request to the CA to check the
    557 certificate status, which offers privacy and performance advantages.
     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.
    558527
    559528Using OCSP stapling has a few requirements:
    560529
    561 * Caching OCSP responses requires a cache, so `GnuTLSCache` must not
    562   be `none`.
    563530* `GnuTLSCertificateFile` must contain the issuer CA certificate in
    564531  addition to the server certificate so responses can be verified.
    565 * The certificate must either contain an OCSP access URI using HTTP,
    566   or `GnuTLSOCSPResponseFile` must be set.
     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.
    567542
    568543OCSP 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`.
    569602
    570603### GnuTLSOCSPCheckNonce
     
    641674request.
    642675
     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
    643690### GnuTLSOCSPSocketTimeout
    644691
     
    666713======================
    667714
    668 Simple Standard TLS Example
    669 ---------------------------
    670 
    671 The following is an example of simple TLS hosting, using one IP
    672 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:
    673753
    674754     # Load the module into Apache.
    675755     LoadModule gnutls_module modules/mod_gnutls.so
    676      GnuTLSCache gdbm /var/cache/www-tls-cache
    677      GnuTLSCacheTimeout 500
    678 
    679      # Without SNI you need one IP Address per-site.
     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
     770     </VirtualHost>
     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
     778     </VirtualHost>
     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
     790     </VirtualHost>
     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.
     799
     800     # Load the module into Apache.
     801     LoadModule gnutls_module modules/mod_gnutls.so
     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.
    680809     Listen 192.0.2.1:443
    681810     Listen 192.0.2.2:443
    682811     Listen 192.0.2.3:443
    683      Listen 192.0.2.4:443
    684812
    685813     <VirtualHost 192.0.2.1:443>
     
    703831
    704832     <VirtualHost 192.0.2.3:443>
    705          # This server enables SRP, OpenPGP and X.509 authentication.
     833         # This server enables SRP and X.509 authentication.
    706834         GnuTLSEnable on
    707          GnuTLSPriorities NORMAL:+SRP:+SRP-RSA:+SRP-DSS:+CTYPE-OPENPGP
     835         GnuTLSPriorities NORMAL:+SRP:+SRP-RSA:+SRP-DSS
    708836         DocumentRoot /www/site3.example.com/html
    709837         ServerName site3.example.com:443
     
    711839         GnuTLSKeyFile conf/tls/site3.key
    712840         GnuTLSClientVerify ignore
    713          GnuTLSPGPCertificateFile conf/tls/site3.pub.asc
    714          GnuTLSPGPKeyFile conf/tls/site3.sec.asc
    715841         GnuTLSSRPPasswdFile conf/tls/tpasswd.site3
    716842         GnuTLSSRPPasswdConfFile conf/tls/tpasswd.site3.conf
    717843     </VirtualHost>
    718844
    719      <VirtualHost 192.0.2.4:443>
    720          GnuTLSEnable on
    721          # %COMPAT disables some security features to enable maximum
    722          # compatibility with clients. Don't use this if you need strong
    723          # security.
    724          GnuTLSPriorities NORMAL:%COMPAT
    725          DocumentRoot /www/site4.example.com/html
    726          ServerName site4.example.com:443
    727          GnuTLSCertificateFile conf/tls/site4.crt
    728          GnuTLSKeyFile conf/tls/site4.key
    729      </VirtualHost>
    730 
    731 Server Name Indication Example
    732 ------------------------------
    733 
    734 `mod_gnutls` supports "Server Name Indication", as specified in
    735 [RFC 6066, Section 3](https://tools.ietf.org/html/rfc6066#section-3). This
    736 allows hosting many TLS websites with a single IP address. All recent
    737 browsers support this standard. Here is an example using SNI:
     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.
    738853
    739854     # Load the module into Apache.
    740855     LoadModule gnutls_module modules/mod_gnutls.so
    741 
    742      # SNI allows hosting multiple sites using one IP address. This
    743      # could also be 'Listen *:443', just like '*:80' is common for
    744      # non-HTTPS
    745      Listen 198.51.100.1:443
     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
    746860
    747861     <VirtualHost _default_:443>
    748          GnuTLSEnable on
    749          GnuTLSSessionTickets on
    750          GnuTLSPriorities NORMAL
    751          DocumentRoot /www/site1.example.com/html
    752          ServerName site1.example.com:443
    753          GnuTLSCertificateFile conf/tls/site1.crt
    754          GnuTLSKeyFile conf/tls/site1.key
    755      </VirtualHost>
    756 
    757      <VirtualHost _default_:443>
    758          GnuTLSEnable on
    759          GnuTLSPriorities NORMAL
    760          DocumentRoot /www/site2.example.com/html
    761          ServerName site2.example.com:443
    762          GnuTLSCertificateFile conf/tls/site2.crt
    763          GnuTLSKeyFile conf/tls/site2.key
    764      </VirtualHost>
    765 
    766      <VirtualHost _default_:443>
    767          GnuTLSEnable on
    768          GnuTLSPriorities NORMAL
    769          DocumentRoot /www/site3.example.com/html
    770          ServerName site3.example.com:443
    771          GnuTLSCertificateFile conf/tls/site3.crt
    772          GnuTLSKeyFile conf/tls/site3.key
    773      </VirtualHost>
    774 
    775      <VirtualHost _default_:443>
    776          GnuTLSEnable on
    777          GnuTLSPriorities NORMAL
    778          DocumentRoot /www/site4.example.com/html
    779          ServerName site4.example.com:443
    780          GnuTLSCertificateFile conf/tls/site4.crt
    781          GnuTLSKeyFile conf/tls/site4.key
    782      </VirtualHost>
    783 
    784 OCSP Stapling Example
    785 ---------------------
    786 
    787 This example uses an X.509 server certificate. The server will fetch
    788 OCSP responses from the responder listed in the certificate and store
    789 them im a memcached cache shared with another server.
    790 
    791      # Load the module into Apache.
    792      LoadModule gnutls_module modules/mod_gnutls.so
    793      GnuTLSCache memcache "192.0.2.1:11211 192.0.2.2:11211"
    794      GnuTLSCacheTimeout 600
    795 
    796      Listen 192.0.2.1:443
    797 
    798      <VirtualHost _default_:443>
    799          GnuTLSEnable          On
    800          GnuTLSPriorities      NORMAL
    801          DocumentRoot          /www/site1.example.com/html
    802          ServerName            site1.example.com:443
    803          GnuTLSCertificateFile conf/tls/site1.crt
    804          GnuTLSKeyFile         conf/tls/site1.key
    805          GnuTLSPriorities      NORMAL
    806          GnuTLSOCSPStapling    On
     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
    807872     </VirtualHost>
    808873
     
    9381003------------------
    9391004
    940 The PEM-encoded (X.509) or ASCII-armored (OpenPGP) server certificate
    941 (see the `GnuTLSExportCertificates` directive).
     1005The PEM-encoded (X.509) server certificate (see the
     1006`GnuTLSExportCertificates` directive).
    9421007
    9431008`SSL_SERVER_CERT_TYPE`
    9441009----------------------
    9451010
    946 The certificate type can be `X.509` or `OPENPGP`.
     1011The certificate type will be `X.509`.
    9471012
    9481013`SSL_CLIENT_CERT`
    9491014------------------
    9501015
    951 The PEM-encoded (X.509) or ASCII-armored (OpenPGP) client certificate
    952 (see the `GnuTLSExportCertificates` directive).
     1016PEM-encoded (X.509) client certificate, if any (see the
     1017`GnuTLSExportCertificates` directive).
    9531018
    9541019`SSL_CLIENT_CERT_TYPE`
    9551020----------------------
    9561021
    957 The certificate type can be `X.509` or `OPENPGP`.
     1022The certificate type will be `X.509`, if any.
  • include/mod_gnutls.h.in

    r0931b35 r19e80a5  
    2626#include "http_log.h"
    2727#include "apr_buckets.h"
    28 #include "apr_strings.h"
    2928#include "apr_tables.h"
    3029#include "ap_release.h"
    31 #include "apr_fnmatch.h"
    3230/* GnuTLS Library Headers */
    3331#include <gnutls/gnutls.h>
    3432#include <gnutls/abstract.h>
    35 #include <gnutls/openpgp.h>
    3633#include <gnutls/x509.h>
    3734
    3835#ifndef __mod_gnutls_h_inc
    3936#define __mod_gnutls_h_inc
    40 
    41 #define HAVE_APR_MEMCACHE    @have_apr_memcache@
    4237
    4338extern module AP_MODULE_DECLARE_DATA gnutls_module;
     
    5651#define MOD_GNUTLS_DEBUG @OOO_MAINTAIN@
    5752
    58 /* mod_gnutls Cache Types */
    59 typedef enum {
    60         /* No Cache */
    61     mgs_cache_none,
    62         /* Use Old Berkley DB */
    63     mgs_cache_dbm,
    64         /* Use Gnu's version of Berkley DB */
    65     mgs_cache_gdbm,
    66 #if HAVE_APR_MEMCACHE
    67         /* Use Memcache */
    68     mgs_cache_memcache,
     53/* Compile support for early SNI? */
     54#if @ENABLE_EARLY_SNI@ == 1
     55#define ENABLE_EARLY_SNI
    6956#endif
    70     mgs_cache_unset
    71 } mgs_cache_e;
     57
     58/** Name of the module-wide singleton watchdog */
     59#define MGS_SINGLETON_WATCHDOG "_mod_gnutls_singleton_"
     60
    7261
    7362/* Internal cache data, defined in gnutls_cache.h */
     
    9382/* The maximum number of certificates to send in a chain */
    9483#define MAX_CHAIN_SIZE 8
    95 /* The maximum number of SANs to read from a x509 certificate */
    96 #define MAX_CERT_SAN 5
    97 
    98 /* Server Configuration Record */
     84
     85/** Server Configuration Record */
    9986typedef struct {
     87    /** Server this mod_gnutls configuration is for */
     88    server_rec* s;
     89
    10090    /* --- Configuration values --- */
    10191        /* Is the module enabled? */
     
    10393        /* Is mod_proxy enabled? */
    10494    int proxy_enabled;
    105         /* A Plain HTTP request */
    106     int non_ssl_request;
    10795
    10896    /* List of PKCS #11 provider modules to load, only valid in the
     
    120108    char *x509_ca_file;
    121109
    122     char *pgp_cert_file;
    123     char *pgp_key_file;
    124     char *pgp_ring_file;
    125 
    126110    char *dh_file;
    127111
     
    134118        /* Cache timeout value */
    135119    int cache_timeout;
    136         /* Chose Cache Type */
    137     mgs_cache_e cache_type;
    138     const char* cache_config;
     120    /* Enable cache */
     121    unsigned char cache_enable : 2;
    139122    /* Internal cache data */
    140123    mgs_cache_t cache;
     
    142125        /* GnuTLS uses Session Tickets */
    143126    int tickets;
    144 
    145     /* --- Things initialized at _child_init --- */
    146127
    147128    /* x509 Certificate Structure */
     
    164145     * connections */
    165146    gnutls_anon_client_credentials_t anon_client_creds;
    166         /* Current x509 Certificate CN [Common Name] */
    167     char* cert_cn;
    168         /* Current x509 Certificate SAN [Subject Alternate Name]s*/
    169     char* cert_san[MAX_CERT_SAN];
    170147        /* An x509 Certificate Chain */
    171148    gnutls_pcert_st *certs_x509_chain;
     
    176153        /* Current x509 Certificate Private Key */
    177154    gnutls_privkey_t privkey_x509;
    178 
    179         /* OpenPGP Certificate */
    180     gnutls_pcert_st *cert_pgp;
    181     gnutls_openpgp_crt_t *cert_crt_pgp;
    182 
    183         /* OpenPGP Certificate Private Key */
    184     gnutls_privkey_t privkey_pgp;
    185 #if GNUTLS_VERSION_NUMBER < 0x030312
    186     /* Internal structure for the OpenPGP private key, used in the
    187      * workaround for a bug in gnutls_privkey_import_openpgp_raw that
    188      * frees memory that is still needed. DO NOT USE for any other
    189      * purpose. */
    190     gnutls_openpgp_privkey_t privkey_pgp_internal;
    191 #endif
    192155
    193156    /* Export full certificates to CGI environment: */
     
    199162        /* A list of CA Certificates */
    200163    gnutls_x509_crt_t *ca_list;
    201         /* OpenPGP Key Ring */
    202     gnutls_openpgp_keyring_t pgp_list;
    203164        /* CA Certificate list size */
    204165    unsigned int ca_list_size;
     
    207168        /* Client Certificate Verification Method */
    208169    mgs_client_verification_method_e client_verify_method;
    209         /* Last Cache timestamp */
    210     apr_time_t last_cache_check;
    211170
    212171    /* Enable OCSP stapling */
    213172    unsigned char ocsp_staple;
     173    /* Automatically refresh cached OCSP response? */
     174    unsigned char ocsp_auto_refresh;
    214175    /* Check nonce in OCSP responses? */
    215176    unsigned char ocsp_check_nonce;
     
    221182    /* Mutex to prevent parallel OCSP requests */
    222183    apr_global_mutex_t *ocsp_mutex;
     184    /* Internal OCSP cache data */
     185    mgs_cache_t ocsp_cache;
    223186    /* Cache timeout for OCSP responses. Note that the nextUpdate
    224187     * field of the response takes precedence if shorter. */
     
    226189    /* If an OCSP request fails wait this long before trying again. */
    227190    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;
    228198    /* Socket timeout for OCSP requests */
    229199    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;
    230204} mgs_srvconf_rec;
    231205
     
    236210} mgs_char_buffer_t;
    237211
    238 /* GnuTLS Handle */
     212/** GnuTLS connection handle */
    239213typedef struct {
    240214        /* Server configuration record */
     
    248222        /* GnuTLS Session handle */
    249223    gnutls_session_t session;
     224    /** Server name requested via SNI if any, or NULL. */
     225    const char *sni_name;
    250226        /* module input status */
    251227    apr_status_t input_rc;
     
    274250        /* Output length */
    275251    apr_size_t output_length;
    276         /* General Status */
     252    /** Connection status: 0 before (re-)handshake, 1 when up, -1 on
     253     * error (checks use status < 0 or status > 0) */
    277254    int status;
    278255} mgs_handle_t;
     
    286263
    287264/* Proxy Support */
    288 /** mod_proxy adds a note with this key to the connection->notes table
    289  * for client connections */
    290 #define PROXY_SNI_NOTE "proxy-request-hostname"
    291265/* An optional function which returns non-zero if the given connection
    292266is using SSL/TLS. */
     
    398372                             const char *arg);
    399373
    400 const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy,
    401                                         const char *arg);
    402 
    403 const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy,
    404                              const char *arg);
    405 
    406 const char *mgs_set_cache(cmd_parms * parms, void *dummy,
    407                           const char *type, const char* arg);
    408 
    409374const char *mgs_set_timeout(cmd_parms *parms, void *dummy, const char *arg);
    410375
     
    425390
    426391const char *mgs_set_srk_pin(cmd_parms * parms, void *dummy,
    427                                    const char *arg);
    428 
    429 const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy,
    430392                                   const char *arg);
    431393
     
    446408void *mgs_config_dir_create(apr_pool_t *p, char *dir);
    447409
    448 mgs_srvconf_rec* mgs_find_sni_server(gnutls_session_t session);
    449 
    450410const char *mgs_store_cred_path(cmd_parms * parms,
    451411                                void *dummy __attribute__((unused)),
     
    474434int mgs_hook_fixups(request_rec *r);
    475435
     436/** Post request hook, checks if TLS connection and vhost match */
     437int mgs_req_vhost_check(request_rec *r);
     438
    476439int mgs_hook_authz(request_rec *r);
    477440
  • src/Makefile.am

    r0931b35 r19e80a5  
    77
    88mod_gnutls_la_SOURCES = mod_gnutls.c gnutls_io.c gnutls_cache.c \
    9         gnutls_config.c gnutls_hooks.c gnutls_ocsp.c gnutls_util.c
     9        gnutls_config.c gnutls_hooks.c gnutls_ocsp.c gnutls_proxy.c \
     10        gnutls_sni.c gnutls_util.c gnutls_watchdog.c
    1011mod_gnutls_la_CFLAGS = -Wall ${MODULE_CFLAGS}
    1112mod_gnutls_la_LDFLAGS = -module -avoid-version ${MODULE_LIBS}
    12 noinst_HEADERS = gnutls_cache.h gnutls_config.h gnutls_ocsp.h gnutls_util.h
     13noinst_HEADERS = gnutls_cache.h gnutls_config.h gnutls_ocsp.h \
     14        gnutls_proxy.h gnutls_sni.h gnutls_util.h gnutls_watchdog.h
    1315
    1416apmodpkglib_LTLIBRARIES = mod_gnutls.la
  • src/gnutls_cache.c

    r0931b35 r19e80a5  
    33 *  Copyright 2008 Nikos Mavrogiannopoulos
    44 *  Copyright 2011 Dash Shendy
    5  *  Copyright 2015-2016 Fiona Klute
     5 *  Copyright 2015-2018 Fiona Klute
    66 *
    77 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2121 * @file gnutls_cache.c
    2222 *
    23  * The signatures of the `(dbm|mc)_cache_...()` functions may be a bit
    24  * confusing: "store" and "expire" take a server_rec, "fetch" an
    25  * mgs_handle_t, and "delete" the `void*` required for a
    26  * `gnutls_db_remove_func`. The first two have matching `..._session`
    27  * functions to fit their respective GnuTLS session cache signatures.
    28  *
    29  * This is because "store", "expire" (dbm only), and "fetch" are also
    30  * needed for the OCSP cache. Their `..._session` variants have been
    31  * created to take care of the session cache specific parts, mainly
    32  * calculating the DB key from the session ID. They have to match the
    33  * appropriate GnuTLS DB function signatures.
    34  *
    35  * Additionally, there are the `mc_cache_(store|fetch)_generic()`
    36  * functions. They exist because memcached requires string keys while
    37  * DBM accepts binary keys, and provide wrappers to turn binary keys
    38  * into hex strings with a `mod_gnutls:` prefix.
    39  *
    40  * To update cached OCSP responses independent of client connections,
    41  * "store" and "expire" have to work without a connection context. On
    42  * the other hand "fetch" does not need to do that, because cached
    43  * OCSP responses will be retrieved for use in client connections.
     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).
    4428 */
    4529
     
    4731#include "mod_gnutls.h"
    4832#include "gnutls_config.h"
    49 
    50 #if HAVE_APR_MEMCACHE
    51 #include "apr_memcache.h"
    52 #endif
    53 
    54 #include "apr_dbm.h"
     33#include "gnutls_ocsp.h"
     34
     35#include <ap_socache.h>
     36#include <apr_strings.h>
     37#include <mod_status.h>
    5538#include <apr_escape.h>
    56 
    57 #include "ap_mpm.h"
    5839#include <util_mutex.h>
    59 
    60 #include <unistd.h>
    61 #include <sys/types.h>
    62 
    63 #if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
    64 #include "unixd.h"
    65 #endif
    6640
    6741/** Default session cache timeout */
    6842#define MGS_DEFAULT_CACHE_TIMEOUT 300
    6943
    70 /** Prefix for keys used with a memcached cache */
    71 #define MC_TAG "mod_gnutls:"
     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
    7252/** Maximum length of the hex string representation of a GnuTLS
    7353 * session ID: two characters per byte, plus one more for `\0` */
     
    7858#endif
    7959
    80 #if MODULE_MAGIC_NUMBER_MAJOR < 20081201
    81 #define ap_unixd_config unixd_config
    82 #endif
    83 
    8460#ifdef APLOG_USE_MODULE
    8561APLOG_USE_MODULE(gnutls);
     
    8763
    8864/**
    89  * Turn a GnuTLS session ID into the key format we use with DBM
     65 * Turn a GnuTLS session ID into the key format we use for
    9066 * caches. Name the Session ID as `server:port.SessionID` to disallow
    9167 * resuming sessions on different servers.
     
    129105}
    130106
    131 #if HAVE_APR_MEMCACHE
     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
    132144
    133145/**
    134  * Turn a GnuTLS session ID into the key format we use with memcached
    135  * caches. Name the Session ID as `server:port.SessionID` to disallow
    136  * resuming sessions on different servers.
    137  *
    138  * @return `0` on success, `-1` on failure
    139  */
    140 static char *mgs_session_id2mc(conn_rec * c, unsigned char *id, int idlen)
    141 {
    142     char sz[GNUTLS_SESSION_ID_STRING_LEN];
    143     apr_status_t rv = apr_escape_hex(sz, id, idlen, 0, NULL);
    144     if (rv != APR_SUCCESS)
    145         return NULL;
    146 
    147     return apr_psprintf(c->pool, MC_TAG "%s:%d.%s",
    148             c->base_server->server_hostname,
    149             c->base_server->port, sz);
    150 }
    151 
    152 /**
    153  * GnuTLS Session Cache using libmemcached
    154  *
    155  */
    156 
    157 /* The underlying apr_memcache system is thread safe... woohoo */
    158 static apr_memcache_t *mc;
    159 
    160 static int mc_cache_child_init(apr_pool_t * p, server_rec * s,
    161         mgs_srvconf_rec * sc) {
    162     apr_status_t rv = APR_SUCCESS;
    163     int thread_limit = 0;
    164     int nservers = 0;
    165     char *cache_config;
    166     char *split;
    167     char *tok;
    168 
    169     ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit);
    170 
    171     /* Find all the servers in the first run to get a total count */
    172     cache_config = apr_pstrdup(p, sc->cache_config);
    173     split = apr_strtok(cache_config, " ", &tok);
    174     while (split) {
    175         nservers++;
    176         split = apr_strtok(NULL, " ", &tok);
    177     }
    178 
    179     rv = apr_memcache_create(p, nservers, 0, &mc);
    180     if (rv != APR_SUCCESS) {
    181         ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    182                      "Failed to create Memcache object of size '%d'.",
    183                      nservers);
    184         return rv;
    185     }
    186 
    187     /* Now add each server to the memcache */
    188     cache_config = apr_pstrdup(p, sc->cache_config);
    189     split = apr_strtok(cache_config, " ", &tok);
    190     while (split) {
    191         apr_memcache_server_t *st;
    192         char *host_str;
    193         char *scope_id;
    194         apr_port_t port;
    195 
    196         rv = apr_parse_addr_port(&host_str, &scope_id, &port,
    197                 split, p);
    198         if (rv != APR_SUCCESS) {
    199             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    200                          "Failed to parse server: '%s'", split);
    201             return rv;
    202         }
    203 
    204         if (host_str == NULL) {
    205             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    206                          "Failed to parse server, "
    207                          "no hostname specified: '%s'", split);
    208             return rv;
    209         }
    210 
    211         if (port == 0) {
    212             port = 11211; /* default port */
    213         }
    214 
    215         /* Should Max Conns be (thread_limit / nservers) ? */
    216         rv = apr_memcache_server_create(p,
    217                 host_str, port,
    218                 0,
    219                 1, thread_limit, 600, &st);
    220         if (rv != APR_SUCCESS) {
    221             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    222                          "Failed to create server: %s:%d",
    223                          host_str, port);
    224             return rv;
    225         }
    226 
    227         rv = apr_memcache_add_server(mc, st);
    228         if (rv != APR_SUCCESS) {
    229             ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    230                          "Failed to add server: %s:%d",
    231                          host_str, port);
    232             return rv;
    233         }
    234 
    235         split = apr_strtok(NULL, " ", &tok);
    236     }
    237     return rv;
    238 }
    239 
    240 static int mc_cache_store(server_rec *s, const char *key,
    241                           gnutls_datum_t data, apr_uint32_t timeout)
    242 {
    243     apr_status_t rv = apr_memcache_set(mc, key, (char *) data.data,
    244                                        data.size, timeout, 0);
    245 
    246     if (rv != APR_SUCCESS)
    247     {
    248         ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
    249                      "error storing key '%s' with %d bytes of data",
    250                      key, data.size);
     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{
     161    mgs_handle_t *ctxt = baton;
     162    gnutls_datum_t dbmkey;
     163
     164    if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    251165        return -1;
    252     }
    253 
    254     return 0;
    255 }
    256 
    257 static int mc_cache_store_generic(server_rec *s, gnutls_datum_t key,
    258                                   gnutls_datum_t data, apr_time_t expiry)
    259 {
    260     apr_uint32_t timeout = apr_time_sec(expiry - apr_time_now());
    261 
    262     apr_pool_t *p;
    263     apr_pool_create(&p, NULL);
    264 
    265     const char *hex = apr_pescape_hex(p, key.data, key.size, 1);
    266     if (hex == NULL)
    267     {
    268         apr_pool_destroy(p);
    269         return -1;
    270     }
    271 
    272     const char *strkey = apr_psprintf(p, MC_TAG "%s", hex);
    273 
    274     int ret = mc_cache_store(s, strkey, data, timeout);
    275 
    276     apr_pool_destroy(p);
    277     return ret;
    278 }
    279 
    280 static int mc_cache_store_session(void *baton, gnutls_datum_t key,
    281                                   gnutls_datum_t data)
    282 {
    283     mgs_handle_t *ctxt = baton;
    284 
    285     const char *strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
    286     if (!strkey)
    287         return -1;
    288 
    289     apr_uint32_t timeout = apr_time_sec(ctxt->sc->cache_timeout);
    290 
    291     return mc_cache_store(ctxt->c->base_server, strkey, data, timeout);
    292 }
    293 
    294 static gnutls_datum_t mc_cache_fetch(conn_rec *c, const char *key)
    295 {
    296     apr_status_t rv = APR_SUCCESS;
    297     char *value;
    298     apr_size_t value_len;
     166
     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{
    299184    gnutls_datum_t data = {NULL, 0};
    300 
    301     rv = apr_memcache_getp(mc, c->pool, key, &value, &value_len, NULL);
    302 
    303     if (rv != APR_SUCCESS)
    304     {
    305 #if MOD_GNUTLS_DEBUG
    306         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c,
    307                       "error fetching key '%s'",
    308                       key);
    309 #endif
    310         return data;
    311     }
    312 
    313     /* TODO: Eliminate this memcpy. gnutls-- */
    314     data.data = gnutls_malloc(value_len);
     185    data.data = gnutls_malloc(SOCACHE_FETCH_BUF_SIZE);
    315186    if (data.data == NULL)
    316187        return data;
    317 
    318     data.size = value_len;
    319     memcpy(data.data, value, value_len);
    320 
    321     return data;
    322 }
    323 
    324 static gnutls_datum_t mc_cache_fetch_generic(mgs_handle_t *ctxt,
    325                                              gnutls_datum_t key)
    326 {
    327     gnutls_datum_t data = {NULL, 0};
    328     const char *hex = apr_pescape_hex(ctxt->c->pool, key.data, key.size, 1);
    329     if (hex == NULL)
    330         return data;
    331 
    332     const char *strkey = apr_psprintf(ctxt->c->pool, MC_TAG "%s", hex);
    333     return mc_cache_fetch(ctxt->c, strkey);
    334 }
    335 
    336 static gnutls_datum_t mc_cache_fetch_session(void *baton, gnutls_datum_t key)
    337 {
    338     mgs_handle_t *ctxt = baton;
    339     gnutls_datum_t data = {NULL, 0};
    340 
    341     const char *strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
    342     if (!strkey)
    343         return data;
    344 
    345     return mc_cache_fetch(ctxt->c, strkey);
    346 }
    347 
    348 static int mc_cache_delete(void *baton, gnutls_datum_t key) {
    349     apr_status_t rv = APR_SUCCESS;
    350     mgs_handle_t *ctxt = baton;
    351     char *strkey = NULL;
    352 
    353     strkey = mgs_session_id2mc(ctxt->c, key.data, key.size);
    354     if (!strkey)
    355         return -1;
    356 
    357     rv = apr_memcache_delete(mc, strkey, 0);
    358 
    359     if (rv != APR_SUCCESS) {
    360         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv,
    361                      ctxt->c->base_server,
    362                      "error deleting key '%s'",
    363                      strkey);
    364         return -1;
    365     }
    366 
    367     return 0;
    368 }
    369 
    370 #endif  /* have_apr_memcache */
    371 
    372 static const char *db_type(mgs_srvconf_rec * sc) {
    373     if (sc->cache_type == mgs_cache_gdbm)
    374         return "gdbm";
    375     else
    376         return "db";
    377 }
    378 
    379 #define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )
    380 
    381 static void dbm_cache_expire(server_rec *s)
    382 {
    383     mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
    384         ap_get_module_config(s->module_config, &gnutls_module);
    385 
    386     apr_status_t rv;
    387     apr_dbm_t *dbm;
    388     apr_datum_t dbmkey;
    389     apr_datum_t dbmval;
    390     apr_time_t dtime;
     188    data.size = SOCACHE_FETCH_BUF_SIZE;
     189
    391190    apr_pool_t *spool;
    392     int total, deleted;
    393 
    394     apr_time_t now = apr_time_now();
    395 
    396     if (now - sc->last_cache_check < (sc->cache_timeout) / 2)
    397         return;
    398 
    399     sc->last_cache_check = now;
    400 
    401     apr_pool_create(&spool, NULL);
    402 
    403     total = 0;
    404     deleted = 0;
    405 
    406     apr_global_mutex_lock(sc->cache->mutex);
    407 
    408     rv = apr_dbm_open_ex(&dbm, db_type(sc),
    409             sc->cache_config, APR_DBM_RWCREATE,
    410             SSL_DBM_FILE_MODE, spool);
    411     if (rv != APR_SUCCESS) {
    412         ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, s,
    413                      "error opening cache '%s'",
    414                      sc->cache_config);
    415         apr_global_mutex_unlock(sc->cache->mutex);
    416         apr_pool_destroy(spool);
    417         return;
    418     }
    419 
    420     apr_dbm_firstkey(dbm, &dbmkey);
    421     while (dbmkey.dptr != NULL) {
    422         apr_dbm_fetch(dbm, dbmkey, &dbmval);
    423         if (dbmval.dptr != NULL
    424                 && dbmval.dsize >= sizeof (apr_time_t)) {
    425             memcpy(&dtime, dbmval.dptr, sizeof (apr_time_t));
    426 
    427             if (now >= dtime) {
    428                 apr_dbm_delete(dbm, dbmkey);
    429                 deleted++;
    430             }
    431             apr_dbm_freedatum(dbm, dbmval);
    432         } else {
    433             apr_dbm_delete(dbm, dbmkey);
    434             deleted++;
    435         }
    436         total++;
    437         apr_dbm_nextkey(dbm, &dbmkey);
    438     }
    439     apr_dbm_close(dbm);
    440 
    441     rv = apr_global_mutex_unlock(sc->cache->mutex);
    442 
    443     ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s,
    444                  "Cleaned up cache '%s'. Deleted %d and left %d",
    445                  sc->cache_config, deleted, total - deleted);
    446 
    447     apr_pool_destroy(spool);
    448 
    449     return;
    450 }
    451 
    452 static gnutls_datum_t dbm_cache_fetch(mgs_handle_t *ctxt, gnutls_datum_t key)
    453 {
    454     gnutls_datum_t data = {NULL, 0};
    455     apr_dbm_t *dbm;
    456     apr_datum_t dbmkey = {(char*) key.data, key.size};
    457     apr_datum_t dbmval;
    458     apr_time_t expiry = 0;
    459     apr_status_t rv;
    460 
    461     /* check if it is time for cache expiration */
    462     dbm_cache_expire(ctxt->c->base_server);
    463 
    464     apr_global_mutex_lock(ctxt->sc->cache->mutex);
    465 
    466     rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
    467             ctxt->sc->cache_config, APR_DBM_READONLY,
    468             SSL_DBM_FILE_MODE, ctxt->c->pool);
    469     if (rv != APR_SUCCESS) {
    470         ap_log_cerror(APLOG_MARK, APLOG_NOTICE, rv, ctxt->c,
    471                       "error opening cache '%s'",
    472                       ctxt->sc->cache_config);
    473         apr_global_mutex_unlock(ctxt->sc->cache->mutex);
    474         return data;
    475     }
    476 
    477     rv = apr_dbm_fetch(dbm, dbmkey, &dbmval);
     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);
    478201
    479202    if (rv != APR_SUCCESS)
    480         goto close_db;
    481 
    482     if (dbmval.dptr == NULL || dbmval.dsize <= sizeof (apr_time_t))
    483         goto cleanup;
    484 
    485     data.size = dbmval.dsize - sizeof (apr_time_t);
    486     /* get data expiration tag */
    487     expiry = *((apr_time_t *) dbmval.dptr);
    488 
    489     data.data = gnutls_malloc(data.size);
    490     if (data.data == NULL)
    491     {
    492         data.size = 0;
    493         goto cleanup;
    494     }
    495 
    496     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, rv, ctxt->c,
    497                   "fetched %" APR_SIZE_T_FMT " bytes from cache",
    498                   dbmval.dsize);
    499 
    500     memcpy(data.data, dbmval.dptr + sizeof (apr_time_t), data.size);
    501 
    502  cleanup:
    503     apr_dbm_freedatum(dbm, dbmval);
    504  close_db:
    505     apr_dbm_close(dbm);
    506     apr_global_mutex_unlock(ctxt->sc->cache->mutex);
    507 
    508     /* cache entry might have expired since last cache cleanup */
    509     if (expiry != 0 && expiry < apr_time_now())
    510     {
     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 */
    511214        gnutls_free(data.data);
    512215        data.data = NULL;
    513216        data.size = 0;
    514         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
    515                       "dropped expired cache data");
    516     }
     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);
    517237
    518238    return data;
    519239}
    520240
    521 static gnutls_datum_t dbm_cache_fetch_session(void *baton, gnutls_datum_t key)
     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)
    522259{
    523260    gnutls_datum_t data = {NULL, 0};
     
    528265        return data;
    529266
    530     return dbm_cache_fetch(ctxt, dbmkey);
    531 }
    532 
    533 static int dbm_cache_store(server_rec *s, gnutls_datum_t key,
    534                            gnutls_datum_t data, apr_time_t expiry)
    535 {
    536     mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
    537         ap_get_module_config(s->module_config, &gnutls_module);
    538 
    539     apr_dbm_t *dbm;
    540     apr_datum_t dbmkey = {(char*) key.data, key.size};
    541     apr_datum_t dbmval;
    542     apr_status_t rv;
    543     apr_pool_t *spool;
    544 
    545     /* check if it is time for cache expiration */
    546     dbm_cache_expire(s);
    547 
    548     apr_pool_create(&spool, NULL);
    549 
    550     /* create DBM value */
    551     dbmval.dsize = data.size + sizeof (apr_time_t);
    552     dbmval.dptr = (char *) apr_palloc(spool, dbmval.dsize);
    553 
    554     /* prepend expiration time */
    555     memcpy((char *) dbmval.dptr, &expiry, sizeof (apr_time_t));
    556     memcpy((char *) dbmval.dptr + sizeof (apr_time_t),
    557             data.data, data.size);
    558 
    559     apr_global_mutex_lock(sc->cache->mutex);
    560 
    561     rv = apr_dbm_open_ex(&dbm, db_type(sc),
    562                          sc->cache_config, APR_DBM_RWCREATE,
    563                          SSL_DBM_FILE_MODE, spool);
    564     if (rv != APR_SUCCESS)
    565     {
    566         ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, s,
    567                      "error opening cache '%s'",
    568                      sc->cache_config);
    569         apr_global_mutex_unlock(sc->cache->mutex);
    570         apr_pool_destroy(spool);
    571         return -1;
    572     }
    573 
    574     rv = apr_dbm_store(dbm, dbmkey, dbmval);
    575     if (rv != APR_SUCCESS)
    576     {
    577         ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s,
    578                      "error storing in cache '%s'",
    579                      sc->cache_config);
    580         apr_dbm_close(dbm);
    581         apr_global_mutex_unlock(sc->cache->mutex);
    582         apr_pool_destroy(spool);
    583         return -1;
    584     }
    585 
    586     apr_dbm_close(dbm);
    587     apr_global_mutex_unlock(sc->cache->mutex);
    588 
    589     ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, s,
    590                  "stored %" APR_SIZE_T_FMT " bytes of data (%"
    591                  APR_SIZE_T_FMT " byte key) in cache '%s'",
    592                  dbmval.dsize, dbmkey.dsize, sc->cache_config);
    593 
    594     apr_pool_destroy(spool);
    595 
    596     return 0;
    597 }
    598 
    599 static int dbm_cache_store_session(void *baton, gnutls_datum_t key,
    600                                    gnutls_datum_t data)
    601 {
    602     mgs_handle_t *ctxt = baton;
    603     gnutls_datum_t dbmkey;
    604 
    605     if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0)
    606         return -1;
    607 
    608     apr_time_t expiry = apr_time_now() + ctxt->sc->cache_timeout;
    609 
    610     return dbm_cache_store(ctxt->c->base_server, dbmkey, data, expiry);
    611 }
    612 
    613 static int dbm_cache_delete(void *baton, gnutls_datum_t key)
    614 {
    615     apr_dbm_t *dbm;
     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{
    616286    gnutls_datum_t tmpkey;
    617287    mgs_handle_t *ctxt = baton;
    618     apr_status_t rv;
    619288
    620289    if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &tmpkey) < 0)
    621290        return -1;
    622     apr_datum_t dbmkey = {(char*) tmpkey.data, tmpkey.size};
    623 
    624     apr_global_mutex_lock(ctxt->sc->cache->mutex);
    625 
    626     rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc),
    627             ctxt->sc->cache_config, APR_DBM_RWCREATE,
    628             SSL_DBM_FILE_MODE, ctxt->c->pool);
     291
     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
    629301    if (rv != APR_SUCCESS) {
    630302        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    631303                     ctxt->c->base_server,
    632                      "error opening cache '%s'",
    633                      ctxt->sc->cache_config);
    634         apr_global_mutex_unlock(ctxt->sc->cache->mutex);
     304                     "error deleting from cache '%s:%s'",
     305                     ctxt->sc->cache->prov->name, ctxt->sc->cache->config);
    635306        return -1;
    636307    }
    637 
    638     rv = apr_dbm_delete(dbm, dbmkey);
    639 
    640     if (rv != APR_SUCCESS) {
    641         ap_log_error(APLOG_MARK, APLOG_NOTICE, rv,
    642                      ctxt->c->base_server,
    643                      "error deleting from cache '%s'",
    644                      ctxt->sc->cache_config);
    645         apr_dbm_close(dbm);
    646         apr_global_mutex_unlock(ctxt->sc->cache->mutex);
    647         return -1;
    648     }
    649 
    650     apr_dbm_close(dbm);
    651     apr_global_mutex_unlock(ctxt->sc->cache->mutex);
    652 
    653308    return 0;
    654309}
    655310
    656 static int dbm_cache_post_config(apr_pool_t * p, server_rec * s,
    657         mgs_srvconf_rec * sc) {
    658     apr_status_t rv;
    659     apr_dbm_t *dbm;
    660     const char *path1;
    661     const char *path2;
    662 
    663     rv = apr_dbm_open_ex(&dbm, db_type(sc), sc->cache_config,
    664             APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, p);
    665 
    666     if (rv != APR_SUCCESS) {
    667         ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
    668                 "GnuTLS: Cannot create DBM Cache at `%s'",
    669                 sc->cache_config);
    670         return rv;
    671     }
    672 
    673     apr_dbm_close(dbm);
    674 
    675     apr_dbm_get_usednames_ex(p, db_type(sc), sc->cache_config, &path1,
    676             &path2);
    677 
    678     /* The Following Code takes logic directly from mod_ssl's DBM Cache */
    679 #if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
    680     /* Running as Root */
    681     if (path1 && geteuid() == 0) {
    682         if (0 != chown(path1, ap_unixd_config.user_id, -1))
    683             ap_log_error(APLOG_MARK, APLOG_NOTICE, -1, s,
    684                          "GnuTLS: could not chown cache path1 `%s' to uid %d (errno: %d)",
    685                          path1, ap_unixd_config.user_id, errno);
    686         if (path2 != NULL) {
    687             if (0 != chown(path2, ap_unixd_config.user_id, -1))
    688                 ap_log_error(APLOG_MARK, APLOG_NOTICE, -1, s,
    689                              "GnuTLS: could not chown cache path2 `%s' to uid %d (errno: %d)",
    690                              path2, ap_unixd_config.user_id, errno);
    691         }
    692     }
    693 #endif
    694 
     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);
    695408    return rv;
    696409}
    697410
    698 int mgs_cache_post_config(apr_pool_t * p, server_rec * s,
    699         mgs_srvconf_rec * sc) {
    700 
    701     /* if GnuTLSCache was never explicitly set: */
    702     if (sc->cache_type == mgs_cache_unset)
    703         sc->cache_type = mgs_cache_none;
     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    }
    704481    /* if GnuTLSCacheTimeout was never explicitly set: */
    705482    if (sc->cache_timeout == MGS_TIMEOUT_UNSET)
    706483        sc->cache_timeout = apr_time_from_sec(MGS_DEFAULT_CACHE_TIMEOUT);
    707484
    708     /* initialize mutex only once */
    709     if (sc->cache == NULL)
    710     {
    711         sc->cache = apr_palloc(p, sizeof(struct mgs_cache));
    712         apr_status_t rv = ap_global_mutex_create(&sc->cache->mutex, NULL,
    713                                                  MGS_CACHE_MUTEX_NAME,
    714                                                  NULL, s, p, 0);
    715         if (rv != APR_SUCCESS)
    716             return rv;
    717     }
    718 
    719     if (sc->cache_type == mgs_cache_dbm || sc->cache_type == mgs_cache_gdbm)
    720     {
    721         sc->cache->store = dbm_cache_store;
    722         sc->cache->fetch = dbm_cache_fetch;
    723         return dbm_cache_post_config(p, s, sc);
    724     }
    725 #if HAVE_APR_MEMCACHE
    726     else if (sc->cache_type == mgs_cache_memcache)
    727     {
    728         sc->cache->store = mc_cache_store_generic;
    729         sc->cache->fetch = mc_cache_fetch_generic;
    730     }
    731 #endif
     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);
    732491
    733492    return APR_SUCCESS;
    734493}
    735494
    736 int mgs_cache_child_init(apr_pool_t * p,
    737                          server_rec * s,
    738                          mgs_srvconf_rec * sc)
     495int mgs_cache_child_init(apr_pool_t *p, server_rec *server,
     496                         mgs_cache_t cache, const char *mutex_name)
    739497{
    740498    /* reinit cache mutex */
    741     const char *lockfile = apr_global_mutex_lockfile(sc->cache->mutex);
    742     apr_status_t rv = apr_global_mutex_child_init(&sc->cache->mutex,
     499    const char *lockfile = apr_global_mutex_lockfile(cache->mutex);
     500    apr_status_t rv = apr_global_mutex_child_init(&cache->mutex,
    743501                                                  lockfile, p);
    744502    if (rv != APR_SUCCESS)
    745         ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
    746                      "Failed to reinit mutex '%s'", MGS_CACHE_MUTEX_NAME);
    747 
    748     if (sc->cache_type == mgs_cache_dbm
    749             || sc->cache_type == mgs_cache_gdbm) {
    750         return 0;
    751     }
    752 #if HAVE_APR_MEMCACHE
    753     else if (sc->cache_type == mgs_cache_memcache) {
    754         return mc_cache_child_init(p, s, sc);
    755     }
    756 #endif
     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    }
    757521    return 0;
    758522}
    759523
    760 #include <assert.h>
    761 
    762 int mgs_cache_session_init(mgs_handle_t * ctxt) {
    763     if (ctxt->sc->cache_type == mgs_cache_dbm
    764             || ctxt->sc->cache_type == mgs_cache_gdbm) {
    765         gnutls_db_set_retrieve_function(ctxt->session,
    766                 dbm_cache_fetch_session);
    767         gnutls_db_set_remove_function(ctxt->session,
    768                 dbm_cache_delete);
    769         gnutls_db_set_store_function(ctxt->session,
    770                 dbm_cache_store_session);
    771         gnutls_db_set_ptr(ctxt->session, ctxt);
    772     }
    773 #if HAVE_APR_MEMCACHE
    774     else if (ctxt->sc->cache_type == mgs_cache_memcache) {
    775         gnutls_db_set_retrieve_function(ctxt->session,
    776                 mc_cache_fetch_session);
    777         gnutls_db_set_remove_function(ctxt->session,
    778                 mc_cache_delete);
    779         gnutls_db_set_store_function(ctxt->session,
    780                 mc_cache_store_session);
    781         gnutls_db_set_ptr(ctxt->session, ctxt);
    782     }
    783 #endif
    784 
    785     return 0;
    786 }
     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_cache.h

    r0931b35 r19e80a5  
    22 *  Copyright 2004-2005 Paul Querna
    33 *  Copyright 2014 Nikos Mavrogiannopoulos
    4  *  Copyright 2015-2016 Fiona Klute
     4 *  Copyright 2015-2018 Fiona Klute
    55 *
    66 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2828#include "mod_gnutls.h"
    2929#include <httpd.h>
     30#include <ap_socache.h>
    3031
    3132/** Name of the mod_gnutls cache access mutex, for use with Apache's
     
    3435
    3536/**
     37 * Configure a cache instance
     38 *
     39 * This function is supposed to be called during config and
     40 * initializes an mgs_cache_t by finding the named socache provider
     41 * and creating a cache instance with the given configuration. Note
     42 * that the socache instance is only created, not initialized, which
     43 * is supposed to happen during post_config.
     44 *
     45 * @param cache pointer to the mgs_cache_t, will be assigned only if
     46 * configuration succeeds
     47 *
     48 * @param server associated server for logging purposes
     49 *
     50 * @param type socache provider type
     51 *
     52 * @param config configuration string for the socache provider, may be
     53 * `NULL` if the provider accepts an empty configuration
     54 *
     55 * @param pconf configuration memory pool, used to store cache
     56 * configuration
     57 *
     58 * @param ptemp temporary memory pool
     59 */
     60const char *mgs_cache_inst_config(mgs_cache_t *cache, server_rec *server,
     61                                  const char* type, const char* config,
     62                                  apr_pool_t *pconf, apr_pool_t *ptemp);
     63
     64/**
    3665 * Initialize the internal cache configuration structure. This
    3766 * function is called after the configuration file(s) have been
    3867 * parsed.
    3968 *
    40  * @param p configuration memory pool
     69 * @param pconf configuration memory pool
     70 * @param ptemp temporary memory pool
    4171 * @param s default server of the Apache configuration, head of the
    4272 * server list
    4373 * @param sc mod_gnutls data associated with `s`
    4474 */
    45 int mgs_cache_post_config(apr_pool_t *p, server_rec *s, mgs_srvconf_rec *sc);
     75int mgs_cache_post_config(apr_pool_t *pconf, apr_pool_t *ptemp,
     76                          server_rec *s, mgs_srvconf_rec *sc);
    4677
    4778/**
     
    5182 * @param s default server of the Apache configuration, head of the
    5283 * server list
    53  * @param sc mod_gnutls data associated with `s`
     84 * @param cache the cache to reinit
     85 * @param mutex_name name of the mutex associated with the cache for
     86 * logging purposes
    5487 */
    55 int mgs_cache_child_init(apr_pool_t *p, server_rec *s, mgs_srvconf_rec *sc);
     88int mgs_cache_child_init(apr_pool_t *p, server_rec *server,
     89                         mgs_cache_t cache, const char *mutex_name);
    5690
    5791/**
     
    79113
    80114/**
    81  * Generic store function for the mod_gnutls object cache.
     115 * Store function for the mod_gnutls object caches.
    82116 *
     117 * @param cache the cache to store the entry in
    83118 * @param s server associated with the cache entry
    84119 * @param key key for the cache entry
     
    88123 * @return `-1` on error, `0` on success
    89124 */
    90 typedef int (*cache_store_func)(server_rec *s, gnutls_datum_t key,
    91                                 gnutls_datum_t data, apr_time_t expiry);
     125int mgs_cache_store(mgs_cache_t cache, server_rec *server, gnutls_datum_t key,
     126                    gnutls_datum_t data, apr_time_t expiry);
     127
    92128/**
    93  * Generic fetch function for the mod_gnutls object cache.
     129 * Fetch function for the mod_gnutls object caches.
    94130 *
    95131 * *Warning*: The `data` element of the returned `gnutls_datum_t` is
     
    97133 * session caching API, and must be released using `gnutls_free()`.
    98134 *
    99  * @param ctxt mod_gnutls session context for the request
     135 * @param cache the cache to fetch from
     136 *
     137 * @param server server context for the request
     138 *
    100139 * @param key key for the cache entry to be fetched
     140 *
     141 * @param pool pool to allocate the response and other temporary
     142 * memory from
    101143 *
    102144 * @return the requested cache entry, or `{NULL, 0}`
    103145 */
    104 typedef gnutls_datum_t (*cache_fetch_func)(mgs_handle_t *ctxt,
    105                                            gnutls_datum_t key);
     146gnutls_datum_t mgs_cache_fetch(mgs_cache_t cache, server_rec *server,
     147                               gnutls_datum_t key, apr_pool_t *pool);
     148
    106149/**
    107150 * Internal cache configuration structure
    108151 */
    109152struct mgs_cache {
    110     /** Store function for this cache */
    111     cache_store_func store;
    112     /** Fetch function for this cache */
    113     cache_fetch_func fetch;
     153    /** Socache provider to use for this cache */
     154    const ap_socache_provider_t *prov;
     155    /** The actual socache instance */
     156    ap_socache_instance_t *socache;
     157    /** Cache configuration string (as passed to the socache create
     158     * function, for logging) */
     159    const char *config;
    114160    /** Mutex for cache access (used only if the cache type is not
    115161     * thread-safe) */
     
    117163};
    118164
     165/**
     166 * Write cache status to a mod_status report
     167 *
     168 * @param cache the cache to report on
     169 *
     170 * @param header_title string to prefix the report with to distinguish
     171 * caches
     172 *
     173 * @param r status output is added to the response for this request
     174 *
     175 * @param flags request flags, used to toggle "short status" mode
     176 *
     177 * @return request status, currently always `OK`
     178 */
     179int mgs_cache_status(mgs_cache_t cache, const char *header_title,
     180                     request_rec *r, int flags);
     181
    119182#endif /** __MOD_GNUTLS_CACHE_H__ */
  • src/gnutls_config.c

    r0931b35 r19e80a5  
    33 *  Copyright 2008, 2014 Nikos Mavrogiannopoulos
    44 *  Copyright 2011 Dash Shendy
    5  *  Copyright 2015-2016 Fiona Klute
     5 *  Copyright 2015-2018 Fiona Klute
    66 *
    77 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    1818 */
    1919
     20#include "gnutls_cache.h"
    2021#include "gnutls_config.h"
    2122#include "mod_gnutls.h"
    2223#include "gnutls_ocsp.h"
     24
    2325#include "apr_lib.h"
     26#include <apr_strings.h>
    2427#include <gnutls/abstract.h>
    2528
     
    142145    }
    143146
    144     if (sc->cert_pgp)
    145     {
    146         gnutls_pcert_deinit(&sc->cert_pgp[0]);
    147         sc->cert_pgp = NULL;
    148         gnutls_openpgp_crt_deinit(sc->cert_crt_pgp[0]);
    149         sc->cert_crt_pgp = NULL;
    150     }
    151 
    152     if (sc->privkey_pgp)
    153     {
    154         gnutls_privkey_deinit(sc->privkey_pgp);
    155         sc->privkey_pgp = NULL;
    156 #if GNUTLS_VERSION_NUMBER < 0x030312
    157         gnutls_openpgp_privkey_deinit(sc->privkey_pgp_internal);
    158         sc->privkey_pgp_internal = NULL;
    159 #endif
    160     }
    161 
    162     if (sc->pgp_list)
    163     {
    164         gnutls_openpgp_keyring_deinit(sc->pgp_list);
    165         sc->pgp_list = NULL;
    166     }
    167 
    168     if (sc->priorities)
     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)
    169151    {
    170152        gnutls_priority_deinit(sc->priorities);
     
    453435    }
    454436
    455     if (sc->pgp_cert_file && sc->cert_pgp == NULL)
    456     {
    457         sc->cert_pgp = apr_pcalloc(pconf, sizeof(sc->cert_pgp[0]));
    458         sc->cert_crt_pgp = apr_pcalloc(pconf, sizeof(sc->cert_crt_pgp[0]));
    459 
    460         if (load_datum_from_file(spool, sc->pgp_cert_file, &data) != 0) {
    461             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    462                          "GnuTLS: Error Reading " "Certificate '%s'",
    463                          sc->pgp_cert_file);
    464             ret = -1;
    465             goto cleanup;
    466         }
    467 
    468         ret = gnutls_openpgp_crt_init(&sc->cert_crt_pgp[0]);
    469         if (ret < 0) {
    470             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    471                          "GnuTLS: Failed to Init "
    472                          "PGP Certificate: (%d) %s", ret,
    473                          gnutls_strerror(ret));
    474             ret = -1;
    475             goto cleanup;
    476         }
    477 
    478         ret = gnutls_openpgp_crt_import(sc->cert_crt_pgp[0], &data,
    479                                         GNUTLS_OPENPGP_FMT_BASE64);
    480         if (ret < 0) {
    481             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    482                          "GnuTLS: Failed to Import "
    483                          "PGP Certificate: (%d) %s", ret,
    484                          gnutls_strerror(ret));
    485             ret = -1;
    486             goto cleanup;
    487         }
    488 
    489         ret = gnutls_pcert_import_openpgp(sc->cert_pgp,
    490                                           sc->cert_crt_pgp[0], 0);
    491         if (ret < 0) {
    492             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    493                          "GnuTLS: Failed to Import "
    494                          "PGP pCertificate: (%d) %s", ret,
    495                          gnutls_strerror(ret));
    496             ret = -1;
    497             goto cleanup;
    498         }
    499     }
    500 
    501     /* Load the PGP key file */
    502     if (sc->pgp_key_file && sc->privkey_pgp == NULL)
    503     {
    504         if (load_datum_from_file(spool, sc->pgp_key_file, &data) != 0) {
    505             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    506                          "GnuTLS: Error Reading " "Private Key '%s'",
    507                          sc->pgp_key_file);
    508             ret = -1;
    509             goto cleanup;
    510         }
    511 
    512         ret = gnutls_privkey_init(&sc->privkey_pgp);
    513         if (ret < 0) {
    514             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    515                          "GnuTLS: Failed to initialize"
    516                          ": (%d) %s", ret, gnutls_strerror(ret));
    517             ret = -1;
    518             goto cleanup;
    519         }
    520 
    521 #if GNUTLS_VERSION_NUMBER < 0x030312
    522         /* GnuTLS versions before 3.3.12 contain a bug in
    523          * gnutls_privkey_import_openpgp_raw which frees data that is
    524          * accessed when the key is used, leading to segfault. Loading
    525          * the key into a gnutls_openpgp_privkey_t and then assigning
    526          * it to the gnutls_privkey_t works around the bug, hence this
    527          * chain of gnutls_openpgp_privkey_init,
    528          * gnutls_openpgp_privkey_import and
    529          * gnutls_privkey_import_openpgp. */
    530         ret = gnutls_openpgp_privkey_init(&sc->privkey_pgp_internal);
    531         if (ret != 0) {
    532             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    533                          "GnuTLS: Failed to initialize "
    534                          "PGP Private Key '%s': (%d) %s",
    535                          sc->pgp_key_file, ret, gnutls_strerror(ret));
    536             ret = -1;
    537             goto cleanup;
    538         }
    539 
    540         ret = gnutls_openpgp_privkey_import(sc->privkey_pgp_internal, &data,
    541                                             GNUTLS_OPENPGP_FMT_BASE64, NULL, 0);
    542         if (ret != 0) {
    543             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    544                          "GnuTLS: Failed to Import "
    545                          "PGP Private Key '%s': (%d) %s",
    546                          sc->pgp_key_file, ret, gnutls_strerror(ret));
    547             ret = -1;
    548             goto cleanup;
    549         }
    550 
    551         ret = gnutls_privkey_import_openpgp(sc->privkey_pgp,
    552                                             sc->privkey_pgp_internal, 0);
    553         if (ret != 0)
    554         {
    555             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    556                          "GnuTLS: Failed to assign PGP Private Key '%s' "
    557                          "to gnutls_privkey_t structure: (%d) %s",
    558                          sc->pgp_key_file, ret, gnutls_strerror(ret));
    559             ret = -1;
    560             goto cleanup;
    561         }
    562 #else
    563         ret = gnutls_privkey_import_openpgp_raw(sc->privkey_pgp, &data,
    564                                                 GNUTLS_OPENPGP_FMT_BASE64,
    565                                                 NULL, NULL);
    566         if (ret != 0)
    567         {
    568             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    569                          "GnuTLS: Failed to Import "
    570                          "PGP Private Key '%s': (%d) %s",
    571                          sc->pgp_key_file, ret, gnutls_strerror(ret));
    572             ret = -1;
    573             goto cleanup;
    574         }
    575 #endif
    576     }
    577 
    578     /* Load the keyring file */
    579     if (sc->pgp_ring_file && sc->pgp_list == NULL)
    580     {
    581         if (load_datum_from_file(spool, sc->pgp_ring_file, &data) != 0) {
    582             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    583                          "GnuTLS: Error Reading " "Keyring File '%s'",
    584                          sc->pgp_ring_file);
    585             ret = -1;
    586             goto cleanup;
    587         }
    588 
    589         ret = gnutls_openpgp_keyring_init(&sc->pgp_list);
    590         if (ret < 0) {
    591             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    592                          "GnuTLS: Failed to initialize"
    593                          "keyring: (%d) %s", ret, gnutls_strerror(ret));
    594             ret = -1;
    595             goto cleanup;
    596         }
    597 
    598         ret = gnutls_openpgp_keyring_import(sc->pgp_list, &data,
    599                                             GNUTLS_OPENPGP_FMT_BASE64);
    600         if (ret < 0) {
    601             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    602                          "GnuTLS: Failed to load "
    603                          "Keyring File '%s': (%d) %s", sc->pgp_ring_file,
    604                          ret, gnutls_strerror(ret));
    605             ret = -1;
    606             goto cleanup;
    607         }
    608     }
    609 
    610437    if (sc->priorities_str && sc->priorities == NULL)
    611438    {
     
    715542}
    716543
    717 const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy __attribute__((unused)),
    718         const char *arg)
    719 {
    720     mgs_srvconf_rec *sc =
    721         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    722                                                  module_config,
    723                                                  &gnutls_module);
    724 
    725     sc->pgp_cert_file = ap_server_root_relative(parms->pool, arg);
    726 
    727     return NULL;
    728 }
    729 
    730 const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy __attribute__((unused)),
    731         const char *arg) {
    732     mgs_srvconf_rec *sc =
    733         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    734                                                  module_config,
    735                                                  &gnutls_module);
    736 
    737     sc->pgp_key_file = ap_server_root_relative(parms->pool, arg);
    738 
    739     return NULL;
    740 }
    741 
    742544const char *mgs_set_tickets(cmd_parms *parms,
    743545                            void *dummy __attribute__((unused)),
     
    784586#endif
    785587
    786 const char *mgs_set_cache(cmd_parms * parms, void *dummy __attribute__((unused)),
    787         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{
    788592    const char *err;
    789593    mgs_srvconf_rec *sc =
    790         ap_get_module_config(parms->server->module_config,
    791                              &gnutls_module);
    792     if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) {
    793         return err;
    794     }
    795 
    796     if (strcasecmp("none", type) == 0) {
    797         sc->cache_type = mgs_cache_none;
    798         sc->cache_config = NULL;
    799         return NULL;
    800     } else if (strcasecmp("dbm", type) == 0) {
    801         sc->cache_type = mgs_cache_dbm;
    802     } else if (strcasecmp("gdbm", type) == 0) {
    803         sc->cache_type = mgs_cache_gdbm;
    804     }
    805 #if HAVE_APR_MEMCACHE
    806     else if (strcasecmp("memcache", type) == 0) {
    807         sc->cache_type = mgs_cache_memcache;
    808     }
    809 #endif
    810     else {
    811         return "Invalid Type for GnuTLSCache!";
    812     }
    813 
    814     if (arg == NULL)
    815         return "Invalid argument 2 for GnuTLSCache!";
    816 
    817     if (sc->cache_type == mgs_cache_dbm
    818         || sc->cache_type == mgs_cache_gdbm) {
    819         sc->cache_config = ap_server_root_relative(parms->pool, arg);
    820     } else {
    821         sc->cache_config = apr_pstrdup(parms->pool, arg);
    822     }
    823 
    824     return NULL;
     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);
    825646}
    826647
     
    838659        ap_get_module_config(parms->server->module_config, &gnutls_module);
    839660
    840     if (!apr_strnatcasecmp(parms->directive->directive, "GnuTLSCacheTimeout"))
    841     {
    842         const char *err;
    843         if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY)))
    844             return err;
     661    if (!strcasecmp(parms->directive->directive, "GnuTLSCacheTimeout"))
    845662        sc->cache_timeout = apr_time_from_sec(argint);
    846     }
    847     else if (!apr_strnatcasecmp(parms->directive->directive,
    848                                 "GnuTLSOCSPCacheTimeout"))
     663    else if (!strcasecmp(parms->directive->directive,
     664                         "GnuTLSOCSPCacheTimeout"))
    849665        sc->ocsp_cache_time = apr_time_from_sec(argint);
    850     else if (!apr_strnatcasecmp(parms->directive->directive,
    851                                 "GnuTLSOCSPFailureTimeout"))
     666    else if (!strcasecmp(parms->directive->directive,
     667                         "GnuTLSOCSPFailureTimeout"))
    852668        sc->ocsp_failure_timeout = apr_time_from_sec(argint);
    853     else if (!apr_strnatcasecmp(parms->directive->directive,
    854                                 "GnuTLSOCSPSocketTimeout"))
     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"))
    855674        sc->ocsp_socket_timeout = apr_time_from_sec(argint);
    856675    else
     
    920739
    921740    sc->x509_ca_file = ap_server_root_relative(parms->pool, arg);
    922 
    923     return NULL;
    924 }
    925 
    926 const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy __attribute__((unused)),
    927         const char *arg) {
    928     mgs_srvconf_rec *sc =
    929         (mgs_srvconf_rec *) ap_get_module_config(parms->server->
    930                                                  module_config,
    931                                                  &gnutls_module);
    932 
    933     sc->pgp_ring_file = ap_server_root_relative(parms->pool, arg);
    934741
    935742    return NULL;
     
    1071878    sc->pin = NULL;
    1072879
    1073     sc->cert_pgp = NULL;
    1074     sc->cert_crt_pgp = NULL;
    1075     sc->privkey_pgp = NULL;
    1076 #if GNUTLS_VERSION_NUMBER < 0x030312
    1077     sc->privkey_pgp_internal = NULL;
    1078 #endif
    1079     sc->pgp_list = NULL;
    1080 
    1081880    sc->priorities_str = NULL;
    1082881    sc->cache_timeout = MGS_TIMEOUT_UNSET;
    1083     sc->cache_type = mgs_cache_unset;
    1084     sc->cache_config = NULL;
     882    sc->cache_enable = GNUTLS_ENABLED_UNSET;
    1085883    sc->cache = NULL;
    1086884    sc->tickets = GNUTLS_ENABLED_UNSET;
     
    1105903
    1106904    sc->ocsp_staple = GNUTLS_ENABLED_UNSET;
     905    sc->ocsp_auto_refresh = GNUTLS_ENABLED_UNSET;
    1107906    sc->ocsp_check_nonce = GNUTLS_ENABLED_UNSET;
    1108907    sc->ocsp_response_file = NULL;
    1109908    sc->ocsp_mutex = NULL;
     909    sc->ocsp_cache = NULL;
    1110910    sc->ocsp_cache_time = MGS_TIMEOUT_UNSET;
    1111911    sc->ocsp_failure_timeout = MGS_TIMEOUT_UNSET;
     912    sc->ocsp_fuzz_time = MGS_TIMEOUT_UNSET;
    1112913    sc->ocsp_socket_timeout = MGS_TIMEOUT_UNSET;
     914
     915    sc->singleton_wd = NULL;
    1113916
    1114917/* this relies on GnuTLS never changing the gnutls_certificate_request_t enum to define -1 */
     
    1133936void *mgs_config_server_merge(apr_pool_t * p, void *BASE, void *ADD)
    1134937{
    1135     int i;
    1136938    char *err = NULL;
    1137939    mgs_srvconf_rec *base = (mgs_srvconf_rec *) BASE;
     
    1155957    gnutls_srvconf_merge(p11_modules, NULL);
    1156958    gnutls_srvconf_merge(pin, NULL);
    1157     gnutls_srvconf_merge(pgp_cert_file, NULL);
    1158     gnutls_srvconf_merge(pgp_key_file, NULL);
    1159     gnutls_srvconf_merge(pgp_ring_file, NULL);
    1160959    gnutls_srvconf_merge(dh_file, NULL);
    1161960    gnutls_srvconf_merge(priorities_str, NULL);
     961    gnutls_srvconf_merge(cache_timeout, MGS_TIMEOUT_UNSET);
    1162962
    1163963    gnutls_srvconf_merge(proxy_x509_key_file, NULL);
     
    1169969
    1170970    gnutls_srvconf_merge(ocsp_staple, GNUTLS_ENABLED_UNSET);
     971    gnutls_srvconf_merge(ocsp_auto_refresh, GNUTLS_ENABLED_UNSET);
    1171972    gnutls_srvconf_merge(ocsp_check_nonce, GNUTLS_ENABLED_UNSET);
    1172973    gnutls_srvconf_assign(ocsp_response_file);
    1173974    gnutls_srvconf_merge(ocsp_cache_time, MGS_TIMEOUT_UNSET);
    1174975    gnutls_srvconf_merge(ocsp_failure_timeout, MGS_TIMEOUT_UNSET);
     976    gnutls_srvconf_merge(ocsp_fuzz_time, MGS_TIMEOUT_UNSET);
    1175977    gnutls_srvconf_merge(ocsp_socket_timeout, MGS_TIMEOUT_UNSET);
    1176978
    1177979    gnutls_srvconf_assign(ca_list);
    1178980    gnutls_srvconf_assign(ca_list_size);
    1179     gnutls_srvconf_assign(cert_pgp);
    1180     gnutls_srvconf_assign(cert_crt_pgp);
    1181     gnutls_srvconf_assign(pgp_list);
    1182981    gnutls_srvconf_assign(certs);
    1183982    gnutls_srvconf_assign(anon_creds);
     
    1186985    gnutls_srvconf_assign(certs_x509_crt_chain);
    1187986    gnutls_srvconf_assign(certs_x509_chain_num);
    1188 
    1189     /* how do these get transferred cleanly before the data from ADD
    1190      * goes away? */
    1191     gnutls_srvconf_assign(cert_cn);
    1192     for (i = 0; i < MAX_CERT_SAN; i++)
    1193         gnutls_srvconf_assign(cert_san[i]);
    1194987
    1195988    return sc;
  • src/gnutls_config.h

    r0931b35 r19e80a5  
    11/*
    2  *  Copyright 2016 Fiona Klute
     2 *  Copyright 2016-2018 Fiona Klute
    33 *
    44 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2727 * mod_gnutls.h.in over here */
    2828
     29const char *mgs_set_cache(cmd_parms * parms, void *dummy,
     30                          const char *type, const char* arg);
     31
    2932#endif /* __MOD_GNUTLS_CONFIG_H__ */
  • src/gnutls_hooks.c

    r0931b35 r19e80a5  
    44 *  Copyright 2011 Dash Shendy
    55 *  Copyright 2013-2014 Daniel Kahn Gillmor
    6  *  Copyright 2015-2018 Fiona Klute
     6 *  Copyright 2015-2019 Fiona Klute
    77 *
    88 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2121#include "mod_gnutls.h"
    2222#include "gnutls_cache.h"
     23#include "gnutls_config.h"
    2324#include "gnutls_ocsp.h"
     25#include "gnutls_proxy.h"
     26#include "gnutls_sni.h"
    2427#include "gnutls_util.h"
     28#include "gnutls_watchdog.h"
     29
    2530#include "http_vhost.h"
    2631#include "ap_mpm.h"
    27 #include "mod_status.h"
     32#include <mod_status.h>
    2833#include <util_mutex.h>
    2934#include <apr_escape.h>
     35/* This provides strcmp and related functions */
     36#define APR_WANT_STRFUNC
     37#include <apr_want.h>
    3038
    3139#ifdef ENABLE_MSVA
     
    5058static gnutls_datum_t session_ticket_key = {NULL, 0};
    5159
     60
     61
    5262static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt);
    53 /* use side==0 for server and side==1 for client */
     63/** use side==0 for server and side==1 for client */
    5464static void mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, size_t export_cert_size);
    55 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);
    5666static int mgs_status_hook(request_rec *r, int flags);
    5767#ifdef ENABLE_MSVA
    5868static const char* mgs_x509_construct_uid(request_rec * pool, gnutls_x509_crt_t cert);
    5969#endif
    60 static int load_proxy_x509_credentials(apr_pool_t *pconf, apr_pool_t *ptemp, server_rec *s)
    61     __attribute__((nonnull));
    6270
    6371/* Pool Cleanup Function */
     
    7179    session_ticket_key.data = NULL;
    7280    session_ticket_key.size = 0;
     81
     82    /* Deinit default priority setting */
     83    mgs_default_priority_deinit();
    7384    return APR_SUCCESS;
    7485}
     
    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
    128149    ap_mutex_register(pconf, MGS_CACHE_MUTEX_NAME, NULL, APR_LOCK_DEFAULT, 0);
    129150    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);
    130153
    131154    /* Register a pool clean-up function */
     
    153176    const apr_array_header_t *pupgrades = NULL;
    154177    apr_status_t ret =
    155         ap_get_protocol_upgrades(ctxt->c, NULL, ctxt->c->base_server,
     178        ap_get_protocol_upgrades(ctxt->c, NULL, ctxt->sc->s,
    156179                                 /*report_all*/ 0, &pupgrades);
    157180    if (ret != APR_SUCCESS)
     
    170193    }
    171194
    172     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctxt->c,
     195    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctxt->c,
    173196                  "%s: Found %d protocol upgrade(s) for ALPN: %s",
    174197                  __func__, pupgrades->nelts,
    175198                  apr_array_pstrcat(ctxt->c->pool, pupgrades, ','));
    176199    gnutls_datum_t *alpn_protos =
    177         apr_palloc(ctxt->c->pool,
    178                    (pupgrades->nelts + 1) * sizeof(gnutls_datum_t));
    179     for (int i = 0; i < pupgrades->nelts; i++)
    180     {
    181         alpn_protos[i].data = (void *) APR_ARRAY_IDX(pupgrades, i, char *);
    182         alpn_protos[i].size =
    183             strnlen(APR_ARRAY_IDX(pupgrades, i, char *),
    184                     pupgrades->elt_size);
    185     }
     200        mgs_str_array_to_datum_array(pupgrades,
     201                                     ctxt->c->pool,
     202                                     pupgrades->nelts + 1);
    186203
    187204    /* Add the current (default) protocol at the end of the list */
     
    224241        apr_pstrndup(ctxt->c->pool, (char*) alpn_proto.data, alpn_proto.size);
    225242    const char *selected =
    226         ap_select_protocol(ctxt->c, NULL, ctxt->c->base_server,
    227                            client_protos);
     243        ap_select_protocol(ctxt->c, NULL, ctxt->sc->s, client_protos);
    228244
    229245    /* ap_select_protocol() will return NULL if none of the ALPN
     
    258274                  __func__, selected);
    259275    apr_status_t status = ap_switch_protocol(ctxt->c, NULL,
    260                                              ctxt->c->base_server,
     276                                             ctxt->sc->s,
    261277                                             selected);
    262278    if (status != APR_SUCCESS)
     
    274290
    275291/**
    276  * Post client hello function for GnuTLS, used to configure the TLS
    277  * server based on virtual host configuration. Uses SNI to select the
    278  * virtual host if available.
     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);
     302
     303    /* Set x509 credentials */
     304    gnutls_credentials_set(ctxt->session,
     305                           GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
     306    /* Set Anon credentials */
     307    gnutls_credentials_set(ctxt->session, GNUTLS_CRD_ANON,
     308                           ctxt->sc->anon_creds);
     309
     310#ifdef ENABLE_SRP
     311        /* Set SRP credentials */
     312    if (ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) {
     313        gnutls_credentials_set(ctxt->session, GNUTLS_CRD_SRP,
     314                               ctxt->sc->srp_creds);
     315    }
     316#endif
     317
     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
     330     * enabled on this virtual server. Note that here we ignore the version
     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.
    279344 *
    280345 * @param session the TLS session
     
    283348 * definition
    284349 */
    285 static int mgs_select_virtual_server_cb(gnutls_session_t session)
     350static int post_client_hello_hook(gnutls_session_t session)
    286351{
    287352    int ret = 0;
    288353    mgs_handle_t *ctxt = gnutls_session_get_ptr(session);
    289354
    290     /* try to find a virtual host */
    291     mgs_srvconf_rec *tsc = mgs_find_sni_server(session);
    292     if (tsc != NULL)
    293     {
    294         /* Found a TLS vhost based on the SNI, configure the
    295          * connection context. */
    296         ctxt->sc = tsc;
    297         }
    298 
    299     gnutls_certificate_server_set_request(session, ctxt->sc->client_verify_mode);
    300 
    301     /* Set x509 credentials */
    302     gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, ctxt->sc->certs);
    303     /* Set Anon credentials */
    304     gnutls_credentials_set(session, GNUTLS_CRD_ANON, ctxt->sc->anon_creds);
    305 
    306 #ifdef ENABLE_SRP
    307         /* Set SRP credentials */
    308     if (ctxt->sc->srp_tpasswd_conf_file != NULL && ctxt->sc->srp_tpasswd_file != NULL) {
    309         gnutls_credentials_set(session, GNUTLS_CRD_SRP, ctxt->sc->srp_creds);
    310     }
    311 #endif
     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    }
    312376
    313377    ret = process_alpn_result(ctxt);
    314378    if (ret != GNUTLS_E_SUCCESS)
    315379        return ret;
    316 
    317     /* Update the priorities - to avoid negotiating a ciphersuite that is not
    318      * enabled on this virtual server. Note that here we ignore the version
    319      * negotiation. */
    320     ret = gnutls_priority_set(session, ctxt->sc->priorities);
    321380
    322381    /* actually it shouldn't fail since we have checked at startup */
     
    350409        *privkey = ctxt->sc->privkey_x509;
    351410        return 0;
    352     } else if (gnutls_certificate_type_get(session) == GNUTLS_CRT_OPENPGP) {
    353                 // OPENPGP CERTIFICATE
    354         *pcerts = ctxt->sc->cert_pgp;
    355         *pcert_length = 1;
    356         *privkey = ctxt->sc->privkey_pgp;
    357         return 0;
    358411    } else {
    359412                // UNKNOWN CERTIFICATE
    360413            return -1;
    361414        }
    362 }
    363 
    364 /* Read the common name or the alternative name of the certificate.
    365  * We only support a single name per certificate.
    366  *
    367  * Returns negative on error.
    368  */
    369 static int read_crt_cn(server_rec * s, apr_pool_t * p, gnutls_x509_crt_t cert, char **cert_cn) {
    370 
    371     int rv = 0;
    372     size_t data_len;
    373 
    374 
    375     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    376     *cert_cn = NULL;
    377 
    378     data_len = 0;
    379     rv = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, NULL, &data_len);
    380 
    381     if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
    382         *cert_cn = apr_palloc(p, data_len);
    383         rv = gnutls_x509_crt_get_dn_by_oid(cert,
    384                 GNUTLS_OID_X520_COMMON_NAME,
    385                 0, 0, *cert_cn,
    386                 &data_len);
    387     } else { /* No CN return subject alternative name */
    388         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
    389                 "No common name found in certificate for '%s:%d'. Looking for subject alternative name...",
    390                 s->server_hostname, s->port);
    391         rv = 0;
    392         /* read subject alternative name */
    393         for (int i = 0; !(rv < 0); i++)
    394         {
    395             data_len = 0;
    396             rv = gnutls_x509_crt_get_subject_alt_name(cert, i,
    397                     NULL,
    398                     &data_len,
    399                     NULL);
    400 
    401             if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER
    402                     && data_len > 1) {
    403                 /* FIXME: not very efficient. What if we have several alt names
    404                  * before DNSName?
    405                  */
    406                 *cert_cn = apr_palloc(p, data_len + 1);
    407 
    408                 rv = gnutls_x509_crt_get_subject_alt_name
    409                         (cert, i, *cert_cn, &data_len, NULL);
    410                 (*cert_cn)[data_len] = 0;
    411 
    412                 if (rv == GNUTLS_SAN_DNSNAME)
    413                     break;
    414             }
    415         }
    416     }
    417 
    418     return rv;
    419 }
    420 
    421 static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p,
    422         gnutls_openpgp_crt_t cert, char **cert_cn) {
    423     int rv = 0;
    424     size_t data_len;
    425 
    426 
    427     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    428     *cert_cn = NULL;
    429 
    430     data_len = 0;
    431     rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len);
    432 
    433     if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) {
    434         *cert_cn = apr_palloc(p, data_len);
    435         rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn,
    436                 &data_len);
    437     } else { /* No CN return subject alternative name */
    438         ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
    439                 "No name found in PGP certificate for '%s:%d'.",
    440                 s->server_hostname, s->port);
    441     }
    442 
    443     return rv;
    444415}
    445416
     
    607578
    608579
    609     rv = mgs_cache_post_config(pconf, s, sc_base);
     580    rv = mgs_cache_post_config(pconf, ptemp, s, sc_base);
    610581    if (rv != APR_SUCCESS)
    611582    {
     
    644615                rv = gnutls_pkcs11_add_provider(p11_module, NULL);
    645616                if (rv != GNUTLS_E_SUCCESS)
    646                     ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
     617                    ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EGENERAL, s,
    647618                                 "GnuTLS: Loading PKCS #11 provider module %s "
    648619                                 "failed: %s (%d).",
    649620                                 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);
    650625            }
    651626        }
    652627    }
    653628
     629    sc_base->singleton_wd =
     630        mgs_new_singleton_watchdog(base_server, MGS_SINGLETON_WATCHDOG, pconf);
     631
    654632    for (s = base_server; s; s = s->next)
    655633    {
    656634        sc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, &gnutls_module);
    657         sc->cache_type = sc_base->cache_type;
    658         sc->cache_config = sc_base->cache_config;
    659         sc->cache_timeout = sc_base->cache_timeout;
     635        sc->s = s;
     636        sc->cache_enable = sc_base->cache_enable;
    660637        sc->cache = sc_base->cache;
    661 
    662         rv = mgs_load_files(pconf, ptemp, s);
    663         if (rv != 0) {
    664             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    665                 "GnuTLS: Loading required files failed."
    666                 " Shutting Down.");
    667             return HTTP_NOT_FOUND;
    668         }
    669 
    670         if (sc->ocsp_staple == GNUTLS_ENABLED_UNSET)
    671             sc->ocsp_staple = GNUTLS_ENABLED_FALSE;
    672 
    673         sc->ocsp_mutex = sc_base->ocsp_mutex;
    674         /* init OCSP configuration if OCSP is enabled for this host */
    675         if (sc->ocsp_staple)
    676         {
    677             rv = mgs_ocsp_post_config_server(pconf, ptemp, s);
    678             if (rv != OK && rv != DECLINED)
    679                 return rv;
    680         }
     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;
    681643
    682644        /* defaults for unset values: */
     
    684646            sc->enabled = GNUTLS_ENABLED_FALSE;
    685647        if (sc->tickets == GNUTLS_ENABLED_UNSET)
    686             sc->tickets = GNUTLS_ENABLED_FALSE;
     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        }
    687655        if (sc->export_certificates_size < 0)
    688656            sc->export_certificates_size = 0;
     
    692660            sc->client_verify_method = mgs_cvm_cartel;
    693661
     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
    694713        /* Check if the priorities have been set */
    695714        if (sc->priorities == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
    696             ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    697                     "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!",
    698                     s->server_hostname, s->port);
    699             return HTTP_NOT_ACCEPTABLE;
     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();
    700721        }
    701722
     
    726747
    727748        if ((sc->certs_x509_chain == NULL || sc->certs_x509_chain_num < 1) &&
    728             sc->cert_pgp == NULL && sc->enabled == GNUTLS_ENABLED_TRUE) {
     749            sc->enabled == GNUTLS_ENABLED_TRUE) {
    729750                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    730751                                                "GnuTLS: Host '%s:%d' is missing a Certificate File!",
    731                                                 s->server_hostname, s->port);
     752                                                s->server_hostname, s->addrs->host_port);
    732753            return HTTP_UNAUTHORIZED;
    733754        }
    734755        if (sc->enabled == GNUTLS_ENABLED_TRUE &&
    735             ((sc->certs_x509_chain_num > 0 && sc->privkey_x509 == NULL) ||
    736              (sc->cert_crt_pgp != NULL && sc->privkey_pgp == NULL)))
     756            (sc->certs_x509_chain_num > 0 && sc->privkey_x509 == NULL))
    737757        {
    738758                        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    739759                                                "GnuTLS: Host '%s:%d' is missing a Private Key File!",
    740                                                 s->server_hostname, s->port);
     760                                                s->server_hostname, s->addrs->host_port);
    741761            return HTTP_UNAUTHORIZED;
    742         }
    743 
    744         /* If OpenPGP support is already disabled in the loaded GnuTLS
    745          * library startup will fail if the configuration tries to
    746          * load PGP credentials. Otherwise warn affected users about
    747          * deprecation. */
    748         if (sc->pgp_cert_file || sc->pgp_key_file || sc->pgp_ring_file)
    749             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
    750                          "Host '%s:%d' is configured to use OpenPGP auth. "
    751                          "OpenPGP support has been deprecated in GnuTLS "
    752                          "since version 3.5.9 and will be removed from "
    753                          "mod_gnutls in a future release.",
    754                          s->server_hostname, s->port);
    755 
    756         if (sc->enabled == GNUTLS_ENABLED_TRUE) {
    757             rv = -1;
    758             if (sc->certs_x509_chain_num > 0) {
    759                 rv = read_crt_cn(s, pconf, sc->certs_x509_crt_chain[0], &sc->cert_cn);
    760             }
    761             if (rv < 0 && sc->cert_pgp != NULL) {
    762                 rv = read_pgpcrt_cn(s, pconf, sc->cert_crt_pgp[0], &sc->cert_cn);
    763                         }
    764 
    765             if (rv < 0) {
    766                 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    767                                                         "GnuTLS: Cannot find a certificate for host '%s:%d'!",
    768                                                         s->server_hostname, s->port);
    769                 sc->cert_cn = NULL;
    770                 continue;
    771             }
    772762        }
    773763
     
    779769                         "%s: loading proxy credentials for host "
    780770                         "'%s:%d' failed, exiting!",
    781                          __func__, s->server_hostname, s->port);
     771                         __func__, s->server_hostname, s->addrs->host_port);
    782772            return HTTP_PROXY_AUTHENTICATION_REQUIRED;
    783773        }
     
    816806    }
    817807
    818     if (sc->cache_type != mgs_cache_none) {
    819         rv = mgs_cache_child_init(p, s, sc);
    820         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)
    821812            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
    822                     "GnuTLS: Failed to run Cache Init");
    823         }
    824     }
    825 
    826     /* reinit OCSP mutex */
     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 */
    827826    const char *lockfile = apr_global_mutex_lockfile(sc->ocsp_mutex);
    828827    rv = apr_global_mutex_child_init(&sc->ocsp_mutex, lockfile, p);
     
    876875}
    877876
    878 /**
    879  * Default buffer size for SNI data, including the terminating NULL
    880  * byte. The size matches what gnutls-cli uses initially.
    881  */
    882 #define DEFAULT_SNI_HOST_LEN 256
     877
    883878
    884879typedef struct {
     
    900895int check_server_aliases(vhost_cb_rec *x, server_rec * s, mgs_srvconf_rec *tsc)
    901896{
    902         apr_array_header_t *names;
    903         int rv = 0;
    904         char ** name;
    905 
    906         /* Check ServerName First! */
    907         if(apr_strnatcasecmp(x->sni_name, s->server_hostname) == 0) {
    908                 // We have a match, save this server configuration
    909                 x->sc = tsc;
    910                 rv = 1;
    911         /* Check any ServerAlias directives */
    912         } else if(s->names->nelts) {
    913                 names = s->names;
    914                 name = (char **)names->elts;
    915                 for (int i = 0; i < names->nelts; ++i)
     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)
    916911        {
    917                         if (!name[i]) { continue; }
    918                                 if (apr_strnatcasecmp(x->sni_name, name[i]) == 0) {
    919                                         // We have a match, save this server configuration
    920                                         x->sc = tsc;
    921                                         rv = 1;
    922                         }
    923                 }
    924         /* Wild any ServerAlias Directives */
    925         } else if(s->wild_names->nelts) {
    926                 names = s->wild_names;
    927         name = (char **)names->elts;
    928                 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)
    929926        {
    930                         if (!name[i]) { continue; }
    931                                 if(apr_fnmatch(name[i], x->sni_name ,
    932                                                                 APR_FNM_CASE_BLIND|
    933                                                                 APR_FNM_PERIOD|
    934                                                                 APR_FNM_PATHNAME|
    935                                                                 APR_FNM_NOESCAPE) == APR_SUCCESS) {
    936                                 x->sc = tsc;
    937                                 rv = 1;
    938                         }
    939                 }
    940         }
    941         return rv;
     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;
    942937}
    943938
     
    952947            &gnutls_module);
    953948
    954     if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) {
     949    if (tsc->enabled != GNUTLS_ENABLED_TRUE) {
    955950        return 0;
    956951    }
     
    978973 * hello function.
    979974 *
    980  * @param session the GnuTLS session
     975 * @param ctxt the mod_gnutls connection handle
    981976 *
    982977 * @return either the matching mod_gnutls server config, or `NULL`
    983978 */
    984 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session)
     979mgs_srvconf_rec *mgs_find_sni_server(mgs_handle_t *ctxt)
    985980{
    986     mgs_handle_t *ctxt = gnutls_session_get_ptr(session);
    987 
    988     char *sni_name = apr_palloc(ctxt->c->pool, DEFAULT_SNI_HOST_LEN);
    989     size_t sni_len = DEFAULT_SNI_HOST_LEN;
    990     unsigned int sni_type;
    991 
    992     /* Search for a DNS SNI element. Note that RFC 6066 prohibits more
    993      * than one server name per type. */
    994     int sni_index = -1;
    995     int rv = 0;
    996     do {
    997         /* The sni_index is incremented before each use, so if the
    998          * loop terminates with a type match we will have the right
    999          * one stored. */
    1000         rv = gnutls_server_name_get(session, sni_name,
    1001                                     &sni_len, &sni_type, ++sni_index);
    1002         if (rv == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
    1003         {
    1004             ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_EGENERAL, ctxt->c,
    1005                           "%s: no DNS SNI found (last index: %d).",
    1006                           __func__, sni_index);
     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
    1007987            return NULL;
    1008         }
    1009     } while (sni_type != GNUTLS_NAME_DNS);
    1010     /* The (rv == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) path inside
    1011      * the loop above returns, so if we reach this point we have a DNS
    1012      * SNI at the current index. */
    1013 
    1014     if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER)
    1015     {
    1016         /* Allocate a new buffer of the right size and retry */
    1017         sni_name = apr_palloc(ctxt->c->pool, sni_len);
    1018         ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
    1019                       "%s: reallocated SNI data buffer for %" APR_SIZE_T_FMT
    1020                       " bytes.", __func__, sni_len);
    1021         rv = gnutls_server_name_get(session, sni_name,
    1022                                     &sni_len, &sni_type, sni_index);
    1023     }
    1024 
    1025     /* Unless there's a bug in the GnuTLS API only GNUTLS_E_IDNA_ERROR
    1026      * can occur here, but a catch all is safer and no more
    1027      * complicated. */
    1028     if (rv != GNUTLS_E_SUCCESS)
    1029     {
    1030         ap_log_cerror(APLOG_MARK, APLOG_INFO, APR_EGENERAL, ctxt->c,
    1031                       "%s: error while getting SNI DNS data: '%s' (%d).",
    1032                       __func__, gnutls_strerror(rv), rv);
    1033         return NULL;
    1034988    }
    1035989
    1036990    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
    1037991                  "%s: client requested server '%s'.",
    1038                   __func__, sni_name);
     992                  __func__, ctxt->sni_name);
    1039993
    1040994    /* Search for vhosts matching connection parameters and the
     
    1044998        .ctxt = ctxt,
    1045999        .sc = NULL,
    1046         .sni_name = sni_name
     1000        .sni_name = ctxt->sni_name
    10471001    };
    1048     rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
     1002    int rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx);
    10491003    if (rv == 1) {
    10501004        return cbx.sc;
     
    10521006    return NULL;
    10531007}
     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
     1015 * 3.6.3). Reading the SNI (if any) before GnuTLS processes the client
     1016 * hello allows loading virtual host settings that cannot be changed
     1017 * in the post client hello hook, including ALPN proposals (required
     1018 * for HTTP/2 support using the `Protocols` directive). In addition to
     1019 * ALPN this function configures the server credentials.
     1020 *
     1021 * The function signature is required by the GnuTLS API.
     1022 *
     1023 * @param session the current session
     1024 * @param htype handshake message type
     1025 * @param when hook position relative to GnuTLS processing
     1026 * @param incoming true if the message is incoming, for client hello
     1027 * that means the hook is running on the server
     1028 * @param msg raw message data
     1029 *
     1030 * @return `GNUTLS_E_SUCCESS` or a GnuTLS error code
     1031 */
     1032static int early_sni_hook(gnutls_session_t session,
     1033                          unsigned int htype,
     1034                          unsigned when,
     1035                          unsigned int incoming,
     1036                          const gnutls_datum_t *msg)
     1037{
     1038    if (!incoming)
     1039        return 0;
     1040
     1041    mgs_handle_t *ctxt = (mgs_handle_t *) gnutls_session_get_ptr(session);
     1042
     1043    /* This is a hook for pre client hello ONLY! */
     1044    if (htype != GNUTLS_HANDSHAKE_CLIENT_HELLO || when != GNUTLS_HOOK_PRE)
     1045    {
     1046        ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EINVAL, ctxt->c,
     1047                      "%s called outside pre client hello hook, this "
     1048                      "indicates a programming error!",
     1049                      __func__);
     1050        return GNUTLS_E_SELF_TEST_ERROR;
     1051    }
     1052
     1053    int ret = gnutls_ext_raw_parse(session, mgs_sni_ext_hook, msg,
     1054                                   GNUTLS_EXT_RAW_FLAG_TLS_CLIENT_HELLO);
     1055    if (ret == 0 && ctxt->sni_name != NULL)
     1056    {
     1057        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
     1058                      "%s found SNI name: '%s'",
     1059                      __func__, ctxt->sni_name);
     1060
     1061        /* try to find a virtual host for that name */
     1062        mgs_srvconf_rec *tsc = mgs_find_sni_server(ctxt);
     1063        if (tsc != NULL)
     1064        {
     1065            /* Found a TLS vhost based on the SNI, configure the
     1066             * connection context. */
     1067            ctxt->sc = tsc;
     1068            ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ctxt->c,
     1069                          "%s: Selected virtual host %s from early SNI, "
     1070                          "connection server is %s.",
     1071                          __func__, ctxt->sc->s->server_hostname,
     1072                          ctxt->c->base_server->server_hostname);
     1073        }
     1074    }
     1075
     1076    reload_session_credentials(ctxt);
     1077
     1078    prepare_alpn_proposals(ctxt);
     1079
     1080    return ret;
     1081}
     1082#endif
     1083
     1084
    10541085
    10551086/**
     
    11321163                          "gnutls_init for server side failed: %s (%d)",
    11331164                          gnutls_strerror(err), err);
    1134         /* Initialize Session Tickets */
    1135         if (session_ticket_key.data != NULL &&
    1136             ctxt->sc->tickets == GNUTLS_ENABLED_TRUE)
    1137         {
    1138             err = gnutls_session_ticket_enable_server(ctxt->session, &session_ticket_key);
    1139             if (err != GNUTLS_E_SUCCESS)
    1140                 ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
    1141                               "gnutls_session_ticket_enable_server failed: %s (%d)",
    1142                               gnutls_strerror(err), err);
    1143         }
    11441165    }
    11451166
     
    11491170
    11501171    /* Set Default Priority */
    1151         err = gnutls_priority_set_direct(ctxt->session, "NORMAL", NULL);
     1172        err = gnutls_priority_set(ctxt->session, mgs_get_default_prio());
    11521173    if (err != GNUTLS_E_SUCCESS)
    1153         ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c, "gnutls_priority_set_direct failed!");
    1154     /* Set Handshake function */
     1174        ap_log_cerror(APLOG_MARK, APLOG_ERR, err, c,
     1175                      "gnutls_priority_set failed!");
     1176
     1177#ifdef ENABLE_EARLY_SNI
     1178    /* Pre-handshake hook, EXPERIMENTAL */
     1179    gnutls_handshake_set_hook_function(ctxt->session,
     1180                                       GNUTLS_HANDSHAKE_CLIENT_HELLO,
     1181                                       GNUTLS_HOOK_PRE, early_sni_hook);
     1182#else
     1183    prepare_alpn_proposals(ctxt);
     1184#endif
     1185
     1186    /* Post client hello hook (called after GnuTLS has parsed it) */
    11551187    gnutls_handshake_set_post_client_hello_function(ctxt->session,
    1156             mgs_select_virtual_server_cb);
     1188            post_client_hello_hook);
    11571189
    11581190    /* Set GnuTLS user pointer, so we can access the module session
     
    11601192    gnutls_session_set_ptr(ctxt->session, ctxt);
    11611193
    1162     /* If mod_gnutls is the TLS server, mgs_select_virtual_server_cb
    1163      * will load appropriate credentials during handshake. However,
     1194    /* If mod_gnutls is the TLS server, early_sni_hook (or
     1195     * post_client_hello_hook, if early SNI is not available) will
     1196     * load appropriate credentials during the handshake. However,
    11641197     * when handling a proxy backend connection, mod_gnutls acts as
    11651198     * TLS client and credentials must be loaded here. */
     
    11811214    }
    11821215
    1183     prepare_alpn_proposals(ctxt);
    1184 
    11851216    /* Initialize Session Cache */
    11861217    mgs_cache_session_init(ctxt);
     
    12551286
    12561287
     1288/* Post request hook, checks if TLS connection and vhost match */
     1289int mgs_req_vhost_check(request_rec *r)
     1290{
     1291    /* mod_gnutls server record for the request vhost */
     1292    mgs_srvconf_rec *r_sc = (mgs_srvconf_rec *)
     1293        ap_get_module_config(r->server->module_config, &gnutls_module);
     1294    mgs_handle_t *ctxt = get_effective_gnutls_ctxt(r->connection);
     1295
     1296    /* Nothing to check for non-TLS and outgoing proxy connections */
     1297    if (ctxt == NULL || !ctxt->enabled || ctxt->is_proxy)
     1298        return DECLINED;
     1299
     1300    if (ctxt->sc != r_sc)
     1301    {
     1302        ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_SUCCESS, ctxt->c,
     1303                      "%s: Mismatch between handshake and request servers!",
     1304                      __func__);
     1305        return HTTP_MISDIRECTED_REQUEST;
     1306    }
     1307
     1308    if (!ctxt->sni_name)
     1309        return DECLINED;
     1310
     1311    /* Got an SNI name, so verify it matches. */
     1312    ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, ctxt->c,
     1313                  "%s: Checking request hostname against SNI name '%s'.",
     1314                  __func__, ctxt->sni_name);
     1315
     1316    if (!r->hostname)
     1317    {
     1318        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, r->connection,
     1319                      "Client requested '%s' via SNI, but provided "
     1320                      "no hostname in HTTP request!", ctxt->sni_name);
     1321        return HTTP_MISDIRECTED_REQUEST;
     1322    }
     1323
     1324    if (strcasecmp(r->hostname, ctxt->sni_name) != 0)
     1325    {
     1326        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, r->connection,
     1327                      "Client requested '%s' via SNI, but '%s' in "
     1328                      "the HTTP request!", ctxt->sni_name, r->hostname);
     1329        return HTTP_MISDIRECTED_REQUEST;
     1330    }
     1331
     1332    return DECLINED;
     1333}
     1334
     1335
     1336
    12571337int mgs_hook_fixups(request_rec * r) {
    12581338    unsigned char sbuf[GNUTLS_MAX_SESSION_ID];
     
    12921372                                         gnutls_mac_get(ctxt->session)));
    12931373
     1374#if GNUTLS_VERSION_NUMBER >= 0x030600
     1375    /* Compression support has been removed since GnuTLS 3.6.0 */
     1376    apr_table_setn(env, "SSL_COMPRESS_METHOD", "NULL");
     1377#else
    12941378    apr_table_setn(env, "SSL_COMPRESS_METHOD",
    12951379            gnutls_compression_get_name(gnutls_compression_get(ctxt->session)));
     1380#endif
    12961381
    12971382#ifdef ENABLE_SRP
     
    13291414
    13301415    if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) {
    1331         mgs_add_common_cert_vars(r, ctxt->sc->certs_x509_crt_chain[0], 0, ctxt->sc->export_certificates_size);
    1332     } else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP) {
    1333         mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_crt_pgp[0], 0, ctxt->sc->export_certificates_size);
     1416        mgs_add_common_cert_vars(r, ctxt->sc->certs_x509_crt_chain[0], 0,
     1417                                 ctxt->sc->export_certificates_size);
    13341418    }
    13351419
     
    15261610
    15271611
    1528 /* @param side 0: server, 1: client
    1529  *
    1530  * @param export_cert_size (int) maximum size for environment variable
    1531  * to use for the PEM-encoded certificate (0 means do not export)
    1532  */
    1533 static void mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, int side, size_t export_cert_size) {
    1534 
    1535         unsigned char sbuf[64]; /* buffer to hold serials */
    1536     char buf[AP_IOBUFSIZE];
    1537     const char *tmp;
    1538     size_t len;
    1539     int ret;
    1540 
    1541     if (r == NULL)
    1542         return;
    1543 
    1544     _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__);
    1545     apr_table_t *env = r->subprocess_env;
    1546 
    1547     if (export_cert_size > 0) {
    1548         len = 0;
    1549         ret = gnutls_openpgp_crt_export(cert, GNUTLS_OPENPGP_FMT_BASE64, NULL, &len);
    1550         if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
    1551             if (len >= export_cert_size) {
    1552                 apr_table_setn(env, MGS_SIDE("_CERT"),
    1553                                "GNUTLS_CERTIFICATE_SIZE_LIMIT_EXCEEDED");
    1554                 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1555                               "GnuTLS: Failed to export too-large OpenPGP certificate to environment");
    1556             } else {
    1557                 char* cert_buf = apr_palloc(r->pool, len + 1);
    1558                 if (cert_buf != NULL && gnutls_openpgp_crt_export(cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0) {
    1559                     cert_buf[len] = 0;
    1560                     apr_table_setn(env, MGS_SIDE("_CERT"), cert_buf);
    1561                 } else {
    1562                     ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
    1563                                   "GnuTLS: failed to export OpenPGP certificate");
    1564                 }
    1565             }
    1566         } else {
    1567             ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
    1568                           "GnuTLS: dazed and confused about OpenPGP certificate size");
    1569         }
    1570     }
    1571 
    1572     len = sizeof (buf);
    1573     gnutls_openpgp_crt_get_name(cert, 0, buf, &len);
    1574     apr_table_setn(env, MGS_SIDE("_NAME"), apr_pstrmemdup(r->pool, buf, len));
    1575 
    1576     len = sizeof (sbuf);
    1577     gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len);
    1578     apr_table_setn(env, MGS_SIDE("_FINGERPRINT"),
    1579                    apr_pescape_hex(r->pool, sbuf, len, 0));
    1580 
    1581     ret = gnutls_openpgp_crt_get_version(cert);
    1582     if (ret > 0)
    1583         apr_table_setn(env, MGS_SIDE("_M_VERSION"),
    1584                        apr_psprintf(r->pool, "%u", ret));
    1585 
    1586     apr_table_setn(env, MGS_SIDE("_CERT_TYPE"), "OPENPGP");
    1587 
    1588     tmp =
    1589             mgs_time2sz(gnutls_openpgp_crt_get_expiration_time
    1590             (cert), buf, sizeof (buf));
    1591     apr_table_setn(env, MGS_SIDE("_V_END"), apr_pstrdup(r->pool, tmp));
    1592 
    1593     tmp =
    1594             mgs_time2sz(gnutls_openpgp_crt_get_creation_time
    1595             (cert), buf, sizeof (buf));
    1596     apr_table_setn(env, MGS_SIDE("_V_START"), apr_pstrdup(r->pool, tmp));
    1597 
    1598     ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL);
    1599     if (ret >= 0) {
    1600         apr_table_setn(env, MGS_SIDE("_A_KEY"), gnutls_pk_algorithm_get_name(ret));
    1601     }
    1602 
    1603 }
    16041612
    16051613/* TODO: Allow client sending a X.509 certificate chain */
     
    16131621    unsigned int ch_size = 0;
    16141622
     1623    // TODO: union no longer needed here after removing its "pgp" component.
    16151624    union {
    16161625        gnutls_x509_crt_t x509[MAX_CHAIN_SIZE];
    1617         gnutls_openpgp_crt_t pgp;
    16181626    } cert;
    16191627    apr_time_t expiration_time, cur_time;
     
    16661674            }
    16671675        }
    1668     } else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP) {
    1669         if (cert_list_size > 1) {
    1670             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1671                     "GnuTLS: Failed to Verify Peer: "
    1672                     "Chained Client Certificates are not supported.");
    1673             return HTTP_FORBIDDEN;
    1674         }
    1675 
    1676         gnutls_openpgp_crt_init(&cert.pgp);
    1677         rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0],
    1678                 GNUTLS_OPENPGP_FMT_RAW);
    1679 
    16801676    } else
    16811677        return HTTP_FORBIDDEN;
     
    17531749
    17541750    } else {
    1755         apr_time_ansi_put(&expiration_time,
    1756                 gnutls_openpgp_crt_get_expiration_time
    1757                 (cert.pgp));
    1758 
    1759         switch(ctxt->sc->client_verify_method) {
    1760         case mgs_cvm_cartel:
    1761             rv = gnutls_openpgp_crt_verify_ring(cert.pgp,
    1762                                                 ctxt->sc->pgp_list, 0,
    1763                                                 &status);
    1764             break;
    1765 #ifdef ENABLE_MSVA
    1766         case mgs_cvm_msva:
    1767             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1768                           "GnuTLS:  OpenPGP verification via MSVA is not yet implemented");
    1769             rv = GNUTLS_E_UNIMPLEMENTED_FEATURE;
    1770             break;
    1771 #endif
    1772         default:
    1773             /* If this block is reached, that indicates a
    1774              * configuration error or bug in mod_gnutls (invalid value
    1775              * of ctxt->sc->client_verify_method). */
    1776             ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
    1777                           "GnuTLS: Failed to Verify OpenPGP Peer: method '%s' is not supported",
    1778                           mgs_readable_cvm(ctxt->sc->client_verify_method));
    1779             rv = GNUTLS_E_UNIMPLEMENTED_FEATURE;
    1780         }
     1751        /* Unknown certificate type */
     1752        rv = GNUTLS_E_UNIMPLEMENTED_FEATURE;
    17811753    }
    17821754
     
    17891761        if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND)
    17901762            ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r,
    1791                 "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?");
     1763                "GnuTLS: No certificate was found for verification. Did you set the GnuTLSClientCAFile directive?");
    17921764        ret = HTTP_FORBIDDEN;
    17931765        goto exit;
     
    18301802    }
    18311803
    1832     if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509)
    1833         mgs_add_common_cert_vars(r, cert.x509[0], 1, ctxt->sc->export_certificates_size);
    1834     else if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_OPENPGP)
    1835         mgs_add_common_pgpcert_vars(r, cert.pgp, 1, ctxt->sc->export_certificates_size);
     1804    mgs_add_common_cert_vars(r, cert.x509[0], 1, ctxt->sc->export_certificates_size);
    18361805
    18371806    {
     
    18611830        for (unsigned int i = 0; i < ch_size; i++)
    18621831            gnutls_x509_crt_deinit(cert.x509[i]);
    1863     else if (gnutls_certificate_type_get(ctxt->session) ==
    1864              GNUTLS_CRT_OPENPGP)
    1865         gnutls_openpgp_crt_deinit(cert.pgp);
     1832
    18661833    return ret;
    18671834}
     
    19221889 * certificate, but doesn't tell us (in any other way) who they are
    19231890 * trying to authenticate as.
    1924 
    1925  * TODO: we might need another parallel for OpenPGP, but for that it's
    1926  * much simpler: we can just assume that the first User ID marked as
    1927  * "primary" (or the first User ID, period) is the identity the user
    1928  * is trying to present as.
    19291891
    19301892 * one complaint might be "but the user wanted to be another identity,
     
    20972059        ap_rputs("</dl>\n", r);
    20982060
     2061    if (sc->ocsp_cache)
     2062        mgs_cache_status(sc->ocsp_cache, "GnuTLS OCSP Cache", r, flags);
     2063    if (sc->cache_enable)
     2064        mgs_cache_status(sc->cache, "GnuTLS Session Cache", r, flags);
     2065
    20992066    return OK;
    21002067}
    2101 
    2102 
    2103 
    2104 /*
    2105  * Callback to check the server certificate for proxy HTTPS
    2106  * connections, to be used with
    2107  * gnutls_certificate_set_verify_function.
    2108 
    2109  * Returns: 0 if certificate check was successful (certificate
    2110  * trusted), non-zero otherwise (error during check or untrusted
    2111  * certificate).
    2112  */
    2113 static int gtls_check_server_cert(gnutls_session_t session)
    2114 {
    2115     mgs_handle_t *ctxt = (mgs_handle_t *) gnutls_session_get_ptr(session);
    2116     unsigned int status;
    2117 
    2118     /* Get peer hostname from a note left by mod_proxy */
    2119     const char *peer_hostname =
    2120         apr_table_get(ctxt->c->notes, PROXY_SNI_NOTE);
    2121     if (peer_hostname == NULL)
    2122         ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, ctxt->c,
    2123                       "%s: " PROXY_SNI_NOTE " NULL, cannot check "
    2124                       "peer's hostname", __func__);
    2125 
    2126     /* Verify certificate, including hostname match. Should
    2127      * peer_hostname be NULL for some reason, the name is not
    2128      * checked. */
    2129     int err = gnutls_certificate_verify_peers3(session, peer_hostname,
    2130                                                &status);
    2131     if (err != GNUTLS_E_SUCCESS)
    2132     {
    2133         ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, ctxt->c,
    2134                       "%s: server certificate check failed: %s (%d)",
    2135                       __func__, gnutls_strerror(err), err);
    2136         return err;
    2137     }
    2138 
    2139     if (status == 0)
    2140         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctxt->c,
    2141                       "%s: server certificate is trusted.",
    2142                       __func__);
    2143     else
    2144     {
    2145         gnutls_datum_t out;
    2146         /* GNUTLS_CRT_X509: ATM, only X509 is supported for proxy
    2147          * certs 0: according to function API, the last argument
    2148          * should be 0 */
    2149         err = gnutls_certificate_verification_status_print(status,
    2150                                                            GNUTLS_CRT_X509,
    2151                                                            &out, 0);
    2152         if (err != GNUTLS_E_SUCCESS)
    2153             ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, ctxt->c,
    2154                           "%s: server verify print failed: %s (%d)",
    2155                           __func__, gnutls_strerror(err), err);
    2156         else
    2157             ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, ctxt->c,
    2158                           "%s: %s",
    2159                           __func__, out.data);
    2160         gnutls_free(out.data);
    2161     }
    2162 
    2163     return status;
    2164 }
    2165 
    2166 
    2167 
    2168 static apr_status_t cleanup_proxy_x509_credentials(void *arg)
    2169 {
    2170     mgs_srvconf_rec *sc = (mgs_srvconf_rec *) arg;
    2171 
    2172     if (sc->proxy_x509_creds)
    2173     {
    2174         /* This implicitly releases the associated trust list
    2175          * sc->proxy_x509_tl, too. */
    2176         gnutls_certificate_free_credentials(sc->proxy_x509_creds);
    2177         sc->proxy_x509_creds = NULL;
    2178         sc->proxy_x509_tl = NULL;
    2179     }
    2180 
    2181     if (sc->anon_client_creds)
    2182     {
    2183         gnutls_anon_free_client_credentials(sc->anon_client_creds);
    2184         sc->anon_client_creds = NULL;
    2185     }
    2186 
    2187     if (sc->proxy_priorities)
    2188     {
    2189         gnutls_priority_deinit(sc->proxy_priorities);
    2190         sc->proxy_priorities = NULL;
    2191     }
    2192 
    2193     return APR_SUCCESS;
    2194 }
    2195 
    2196 
    2197 
    2198 static apr_status_t load_proxy_x509_credentials(apr_pool_t *pconf,
    2199                                                 apr_pool_t *ptemp,
    2200                                                 server_rec *s)
    2201 {
    2202     mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
    2203         ap_get_module_config(s->module_config, &gnutls_module);
    2204 
    2205     if (sc == NULL)
    2206         return APR_EGENERAL;
    2207 
    2208     apr_status_t ret = APR_EINIT;
    2209     int err = GNUTLS_E_SUCCESS;
    2210 
    2211     /* Cleanup function for the GnuTLS structures allocated below */
    2212     apr_pool_cleanup_register(pconf, sc, cleanup_proxy_x509_credentials,
    2213                               apr_pool_cleanup_null);
    2214 
    2215     /* Function pool, gets destroyed before exit. */
    2216     apr_pool_t *pool;
    2217     ret = apr_pool_create(&pool, ptemp);
    2218     if (ret != APR_SUCCESS)
    2219     {
    2220         ap_log_error(APLOG_MARK, APLOG_ERR, ret, s,
    2221                      "%s: failed to allocate function memory pool.", __func__);
    2222         return ret;
    2223     }
    2224 
    2225     /* allocate credentials structures */
    2226     err = gnutls_certificate_allocate_credentials(&sc->proxy_x509_creds);
    2227     if (err != GNUTLS_E_SUCCESS)
    2228     {
    2229         ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
    2230                      "%s: Failed to initialize proxy credentials: (%d) %s",
    2231                      __func__, err, gnutls_strerror(err));
    2232         return APR_EGENERAL;
    2233     }
    2234     err = gnutls_anon_allocate_client_credentials(&sc->anon_client_creds);
    2235     if (err != GNUTLS_E_SUCCESS)
    2236     {
    2237         ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
    2238                      "%s: Failed to initialize anon credentials for proxy: "
    2239                      "(%d) %s", __func__, err, gnutls_strerror(err));
    2240         return APR_EGENERAL;
    2241     }
    2242 
    2243     /* Check if the proxy priorities have been set, fail immediately
    2244      * if not */
    2245     if (sc->proxy_priorities_str == NULL)
    2246     {
    2247         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s,
    2248                      "Host '%s:%d' is missing the GnuTLSProxyPriorities "
    2249                      "directive!",
    2250                      s->server_hostname, s->port);
    2251         return APR_EGENERAL;
    2252     }
    2253     /* parse proxy priorities */
    2254     const char *err_pos = NULL;
    2255     err = gnutls_priority_init(&sc->proxy_priorities,
    2256                                sc->proxy_priorities_str, &err_pos);
    2257     if (err != GNUTLS_E_SUCCESS)
    2258     {
    2259         if (ret == GNUTLS_E_INVALID_REQUEST)
    2260             ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
    2261                          "%s: Syntax error parsing proxy priorities "
    2262                          "string at: %s",
    2263                          __func__, err_pos);
    2264         else
    2265             ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
    2266                          "Error setting proxy priorities: %s (%d)",
    2267                          gnutls_strerror(err), err);
    2268         ret = APR_EGENERAL;
    2269     }
    2270 
    2271     /* load certificate and key for client auth, if configured */
    2272     if (sc->proxy_x509_key_file && sc->proxy_x509_cert_file)
    2273     {
    2274         char* cert_file = ap_server_root_relative(pool,
    2275                                                   sc->proxy_x509_cert_file);
    2276         char* key_file = ap_server_root_relative(pool,
    2277                                                  sc->proxy_x509_key_file);
    2278         err = gnutls_certificate_set_x509_key_file(sc->proxy_x509_creds,
    2279                                                    cert_file,
    2280                                                    key_file,
    2281                                                    GNUTLS_X509_FMT_PEM);
    2282         if (err != GNUTLS_E_SUCCESS)
    2283         {
    2284             ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
    2285                          "%s: loading proxy client credentials failed: %s (%d)",
    2286                          __func__, gnutls_strerror(err), err);
    2287             ret = APR_EGENERAL;
    2288         }
    2289     }
    2290     else if (!sc->proxy_x509_key_file && sc->proxy_x509_cert_file)
    2291     {
    2292         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
    2293                      "%s: proxy key file not set!", __func__);
    2294         ret = APR_EGENERAL;
    2295     }
    2296     else if (!sc->proxy_x509_cert_file && sc->proxy_x509_key_file)
    2297     {
    2298         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
    2299                      "%s: proxy certificate file not set!", __func__);
    2300         ret = APR_EGENERAL;
    2301     }
    2302     else
    2303         /* if both key and cert are NULL, client auth is not used */
    2304         ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
    2305                      "%s: no client credentials for proxy", __func__);
    2306 
    2307     /* must be set if the server certificate is to be checked */
    2308     if (sc->proxy_x509_ca_file)
    2309     {
    2310         /* initialize the trust list */
    2311         err = gnutls_x509_trust_list_init(&sc->proxy_x509_tl, 0);
    2312         if (err != GNUTLS_E_SUCCESS)
    2313         {
    2314             ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
    2315                          "%s: gnutls_x509_trust_list_init failed: %s (%d)",
    2316                          __func__, gnutls_strerror(err), err);
    2317             ret = APR_EGENERAL;
    2318         }
    2319 
    2320         char* ca_file = ap_server_root_relative(pool,
    2321                                                 sc->proxy_x509_ca_file);
    2322         /* if no CRL is used, sc->proxy_x509_crl_file is NULL */
    2323         char* crl_file = NULL;
    2324         if (sc->proxy_x509_crl_file)
    2325             crl_file = ap_server_root_relative(pool,
    2326                                                sc->proxy_x509_crl_file);
    2327 
    2328         /* returns number of loaded elements */
    2329         err = gnutls_x509_trust_list_add_trust_file(sc->proxy_x509_tl,
    2330                                                     ca_file,
    2331                                                     crl_file,
    2332                                                     GNUTLS_X509_FMT_PEM,
    2333                                                     0 /* tl_flags */,
    2334                                                     0 /* tl_vflags */);
    2335         if (err > 0)
    2336             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
    2337                          "%s: proxy CA trust list: %d structures loaded",
    2338                          __func__, err);
    2339         else if (err == 0)
    2340             ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
    2341                          "%s: proxy CA trust list is empty (%d)",
    2342                          __func__, err);
    2343         else /* err < 0 */
    2344         {
    2345             ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
    2346                          "%s: error loading proxy CA trust list: %s (%d)",
    2347                          __func__, gnutls_strerror(err), err);
    2348             ret = APR_EGENERAL;
    2349         }
    2350 
    2351         /* attach trust list to credentials */
    2352         gnutls_certificate_set_trust_list(sc->proxy_x509_creds,
    2353                                           sc->proxy_x509_tl, 0);
    2354     }
    2355     else
    2356         ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
    2357                      "%s: no CA trust list for proxy connections, "
    2358                      "TLS connections will fail!", __func__);
    2359 
    2360     gnutls_certificate_set_verify_function(sc->proxy_x509_creds,
    2361                                            gtls_check_server_cert);
    2362     apr_pool_destroy(pool);
    2363     return ret;
    2364 }
  • src/gnutls_io.c

    r0931b35 r19e80a5  
    33 *  Copyright 2008 Nikos Mavrogiannopoulos
    44 *  Copyright 2011 Dash Shendy
    5  *  Copyright 2015-2017 Fiona Klute
     5 *  Copyright 2015-2019 Fiona Klute
    66 *
    77 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    1919
    2020#include "mod_gnutls.h"
     21#include "gnutls_proxy.h"
    2122
    2223#ifdef APLOG_USE_MODULE
     
    6667                      "GnuTLS handshake failed: HTTP spoken on HTTPS port; "
    6768                      "trying to send HTML error page");
    68         mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
    69             ap_get_module_config(f->c->base_server->module_config,
    70                                  &gnutls_module);
    7169        ctxt->status = -1;
    72         sc->non_ssl_request = 1;
    7370
    7471        /* fake the request line */
     
    246243    while (1)
    247244    {
     245        /* Note: The pull function sets ctxt->input_rc */
    248246        rc = gnutls_record_recv(ctxt->session, buf + bytes, wanted - bytes);
    249 
    250         if (rc == GNUTLS_E_INTERRUPTED)
    251             ctxt->input_rc = APR_EINTR;
    252         else if (rc == GNUTLS_E_AGAIN)
    253             ctxt->input_rc = APR_EAGAIN;
    254247
    255248        if (rc > 0) {
     
    262255            return ctxt->input_rc;
    263256        } else if (rc == 0) {
    264             /* If EAGAIN, we will loop given a blocking read,
    265              * otherwise consider ourselves at EOF.
    266              */
    267             if (APR_STATUS_IS_EAGAIN(ctxt->input_rc)
    268                     || APR_STATUS_IS_EINTR(ctxt->input_rc)) {
    269                 /* Already read something, return APR_SUCCESS instead.
    270                  * On win32 in particular, but perhaps on other kernels,
    271                  * a blocking call isn't 'always' blocking.
    272                  */
    273                 if (*len > 0) {
    274                     ctxt->input_rc = APR_SUCCESS;
    275                     break;
    276                 }
    277                 if (ctxt->input_block == APR_NONBLOCK_READ) {
    278                     break;
    279                 }
     257            /* EOF, return code depends on whether we still have data
     258             * to return. */
     259            if (*len > 0) {
     260                ctxt->input_rc = APR_SUCCESS;
    280261            } else {
    281                 if (*len > 0) {
    282                     ctxt->input_rc = APR_SUCCESS;
    283                 } else {
    284                     ctxt->input_rc = APR_EOF;
    285                 }
    286                 break;
    287             }
     262                ctxt->input_rc = APR_EOF;
     263            }
     264            break;
    288265        } else { /* (rc < 0) */
    289266
    290             if (rc == GNUTLS_E_REHANDSHAKE) {
     267            if (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN)
     268            {
     269                ap_log_cerror(APLOG_MARK, APLOG_TRACE2, ctxt->input_rc, ctxt->c,
     270                              "%s: looping recv after '%s' (%d)",
     271                              __func__, gnutls_strerror(rc), rc);
     272                /* For a blocking read, loop and try again
     273                 * immediately. Otherwise just notify the caller. */
     274                if (ctxt->input_block != APR_NONBLOCK_READ)
     275                    continue;
     276                else
     277                    ctxt->input_rc =
     278                        (rc == GNUTLS_E_AGAIN ? APR_EAGAIN : APR_EINTR);
     279            } else if (rc == GNUTLS_E_REHANDSHAKE) {
    291280                /* A client has asked for a new Hankshake. Currently, we don't do it */
    292281                ap_log_cerror(APLOG_MARK, APLOG_INFO,
     
    395384    }
    396385
    397     /* Enable SNI for proxy connections */
     386    /* Enable SNI and ALPN for proxy connections */
    398387    if (ctxt->is_proxy == GNUTLS_ENABLED_TRUE)
    399     {
    400         /* Get peer hostname from note left by mod_proxy */
    401         const char *peer_hostname =
    402             apr_table_get(ctxt->c->notes, PROXY_SNI_NOTE);
    403         /* Used only as target for apr_ipsubnet_create() */
    404         apr_ipsubnet_t *probe;
    405         /* Check if the note is present (!= NULL) and NOT an IP
    406          * address */
    407         if ((peer_hostname) != NULL
    408             && (apr_ipsubnet_create(&probe, peer_hostname, NULL, ctxt->c->pool)
    409                 != APR_SUCCESS))
    410         {
    411             ret = gnutls_server_name_set(ctxt->session, GNUTLS_NAME_DNS,
    412                                          peer_hostname, strlen(peer_hostname));
    413             if (ret != GNUTLS_E_SUCCESS)
    414                 ap_log_cerror(APLOG_MARK, APLOG_ERR, ret, ctxt->c,
    415                               "Could not set SNI '%s' for proxy connection: "
    416                               "%s (%d)",
    417                               peer_hostname, gnutls_strerror(ret), ret);
    418         }
    419     }
     388        mgs_set_proxy_handshake_ext(ctxt);
    420389
    421390tryagain:
     
    567536    }
    568537
    569     if (ctxt->status < 0) {
    570         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctxt->c,
    571                       "%s %s: ap_get_brigade", __func__, IS_PROXY_STR(ctxt));
    572         return ap_get_brigade(f->next, bb, mode, block, readbytes);
     538    if (ctxt->status < 0)
     539    {
     540        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctxt->c,
     541                      "%s: %sconnection failed, cannot provide data!",
     542                      __func__, IS_PROXY_STR(ctxt));
     543        apr_bucket *bucket =
     544                apr_bucket_eos_create(f->c->bucket_alloc);
     545        APR_BRIGADE_INSERT_TAIL(bb, bucket);
     546        return APR_ECONNABORTED;
    573547    }
    574548
     
    708682                          "%s: TLS %sconnection opened.",
    709683                          __func__, IS_PROXY_STR(ctxt));
    710     }
    711 
    712     if (ctxt->status < 0) {
    713         return ap_pass_brigade(f->next, bb);
     684        else if (ctxt->is_proxy)
     685        {
     686            /* If mod_proxy receives an error while trying to send its
     687             * request it sends an "invalid request" error to the
     688             * client. By pretending we could send the request
     689             * mod_proxy continues its processing and sends a proper
     690             * "proxy error" message when there's no response to read. */
     691            apr_bucket *bucket = apr_bucket_eos_create(f->c->bucket_alloc);
     692            APR_BRIGADE_INSERT_TAIL(bb, bucket);
     693            return APR_SUCCESS;
     694        }
     695        /* No final else here, the "ctxt->status < 0" check below will
     696         * catch that. */
     697    }
     698
     699    if (ctxt->status < 0)
     700    {
     701        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctxt->c,
     702                      "%s: %sconnection failed, refusing to send.",
     703                      __func__, IS_PROXY_STR(ctxt));
     704        return APR_ECONNABORTED;
    714705    }
    715706
     
    864855                && APR_BRIGADE_EMPTY(ctxt->input_bb)))
    865856        {
    866             if (APR_STATUS_IS_EOF(ctxt->input_rc))
    867             {
    868                 return 0;
    869             }
    870             else
    871             {
    872                 gnutls_transport_set_errno(ctxt->session,
    873                                            EAI_APR_TO_RAW(ctxt->input_rc));
    874                 return -1;
    875             }
     857            /* Turning APR_SUCCESS into APR_EINTR isn't ideal, but
     858             * it's the best matching error code for "didn't get data,
     859             * but read didn't permanently fail either." */
     860            ctxt->input_rc = (rc != APR_SUCCESS ? rc : APR_EINTR);
     861            gnutls_transport_set_errno(ctxt->session,
     862                                       EAI_APR_TO_RAW(ctxt->input_rc));
     863            return -1;
     864        }
     865
     866        /* Blocking ap_get_brigade() can return a timeout status,
     867         * sometimes after a very short time. "Don't give up, just
     868         * return the timeout" is what mod_ssl does. */
     869        if (ctxt->input_block == APR_BLOCK_READ
     870            && APR_STATUS_IS_TIMEUP(rc)
     871            && APR_BRIGADE_EMPTY(ctxt->input_bb))
     872        {
     873            ctxt->input_rc = rc;
     874            gnutls_transport_set_errno(ctxt->session, EAGAIN);
     875            return -1;
    876876        }
    877877
     
    879879        {
    880880            /* Unexpected errors discard the brigade */
     881            ap_log_cerror(APLOG_MARK, APLOG_INFO, rc, ctxt->c,
     882                          "%s: Unexpected error!", __func__);
    881883            apr_brigade_cleanup(ctxt->input_bb);
    882884            ctxt->input_bb = NULL;
  • src/gnutls_ocsp.c

    r0931b35 r19e80a5  
    11/*
    2  *  Copyright 2016 Fiona Klute
     2 *  Copyright 2016-2018 Fiona Klute
    33 *
    44 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2020#include "gnutls_config.h"
    2121#include "gnutls_util.h"
     22#include "gnutls_watchdog.h"
    2223
    2324#include <apr_escape.h>
    2425#include <apr_lib.h>
    2526#include <apr_time.h>
     27#include <gnutls/crypto.h>
    2628#include <gnutls/ocsp.h>
     29#include <mod_watchdog.h>
    2730#include <time.h>
    2831
     
    8386    else
    8487        sc->ocsp_staple = GNUTLS_ENABLED_FALSE;
     88
     89    return NULL;
     90}
     91
     92
     93
     94const char *mgs_set_ocsp_auto_refresh(cmd_parms *parms,
     95                                      void *dummy __attribute__((unused)),
     96                                      const int arg)
     97{
     98    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
     99        ap_get_module_config(parms->server->module_config, &gnutls_module);
     100
     101    if (arg)
     102        sc->ocsp_auto_refresh = GNUTLS_ENABLED_TRUE;
     103    else
     104        sc->ocsp_auto_refresh = GNUTLS_ENABLED_FALSE;
    85105
    86106    return NULL;
     
    594614
    595615
    596 apr_status_t mgs_cache_ocsp_response(server_rec *s)
     616/**
     617 * Get a fresh OCSP response and put it into the cache.
     618 *
     619 * @param s server that needs a new response
     620 *
     621 * @param cache_expiry If not `NULL`, this `apr_time_t` will be set to
     622 * the expiration time of the cache entry. Remains unchanged on
     623 * failure.
     624 *
     625 * @return APR_SUCCESS or an APR error code
     626 */
     627static apr_status_t mgs_cache_ocsp_response(server_rec *s,
     628                                            apr_time_t *cache_expiry)
    597629{
    598630    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
    599631        ap_get_module_config(s->module_config, &gnutls_module);
    600632
    601     if (sc->cache == NULL)
     633    if (sc->ocsp_cache == NULL)
    602634    {
    603635        /* OCSP caching requires a cache. */
     
    691723    }
    692724
    693     int r = sc->cache->store(s, sc->ocsp->fingerprint, resp, expiry);
     725    int r = mgs_cache_store(sc->ocsp_cache, s,
     726                            sc->ocsp->fingerprint, resp, expiry);
    694727    /* destroy pool, and original copy of the OCSP response with it */
    695728    apr_pool_destroy(tmp);
     
    700733        return APR_EGENERAL;
    701734    }
     735
     736    if (cache_expiry != NULL)
     737        *cache_expiry = expiry;
    702738    return APR_SUCCESS;
    703739}
     
    705741
    706742
    707 /*
     743/**
    708744 * Retries after failed OCSP requests must be rate limited. If the
    709745 * responder is overloaded or buggy we don't want to add too much more
    710746 * load, and if a MITM is messing with requests a repetition loop
    711  * might end up being a self-inflicted denial of service.
     747 * might end up being a self-inflicted denial of service. This
     748 * function writes a specially formed entry to the cache to indicate a
     749 * recent failure.
     750 *
     751 * @param s the server for which an OCSP request failed
     752 * @param timeout lifetime of the cache entry
    712753 */
    713 void mgs_cache_ocsp_failure(server_rec *s)
     754static void mgs_cache_ocsp_failure(server_rec *s, apr_interval_time_t timeout)
    714755{
    715756    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
     
    721762        .size = sizeof(c)
    722763    };
    723     apr_time_t expiry = apr_time_now() + sc->ocsp_failure_timeout;
    724 
    725     char date_str[APR_RFC822_DATE_LEN];
    726     apr_rfc822_date(date_str, expiry);
    727     ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
    728                  "OCSP request for %s failed, next try after %s.",
    729                  s->server_hostname, date_str);
    730 
    731     int r = sc->cache->store(s, sc->ocsp->fingerprint, dummy, expiry);
     764    apr_time_t expiry = apr_time_now() + timeout;
     765
     766    int r = mgs_cache_store(sc->ocsp_cache, s,
     767                            sc->ocsp->fingerprint, dummy, expiry);
    732768    if (r != 0)
    733769        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
     
    744780    mgs_srvconf_rec *sc = ctxt->sc;
    745781
    746     if (!sc->ocsp_staple || sc->cache == NULL)
     782    if (!sc->ocsp_staple || sc->ocsp_cache == NULL)
    747783    {
    748784        /* OCSP must be enabled and caching requires a cache. */
     
    750786    }
    751787
    752     *ocsp_response = sc->cache->fetch(ctxt,
    753                                       sc->ocsp->fingerprint);
     788    *ocsp_response = mgs_cache_fetch(ctxt->sc->ocsp_cache,
     789                                     ctxt->c->base_server,
     790                                     ctxt->sc->ocsp->fingerprint,
     791                                     ctxt->c->pool);
    754792    if (ocsp_response->size == 0)
    755793    {
     
    786824         * moment there's no good way to integrate that with the
    787825         * Apache Mutex directive. */
    788         *ocsp_response = sc->cache->fetch(ctxt,
    789                                           sc->ocsp->fingerprint);
     826        *ocsp_response = mgs_cache_fetch(ctxt->sc->ocsp_cache,
     827                                         ctxt->c->base_server,
     828                                         ctxt->sc->ocsp->fingerprint,
     829                                         ctxt->c->pool);
    790830        if (ocsp_response->size > 0)
    791831        {
     
    801841    }
    802842
    803     rv = mgs_cache_ocsp_response(ctxt->c->base_server);
     843    rv = mgs_cache_ocsp_response(ctxt->c->base_server, NULL);
    804844    if (rv != APR_SUCCESS)
    805845    {
     
    807847                      "Caching a fresh OCSP response failed");
    808848        /* cache failure to rate limit retries */
    809         mgs_cache_ocsp_failure(ctxt->c->base_server);
     849        mgs_cache_ocsp_failure(ctxt->c->base_server,
     850                               ctxt->sc->ocsp_failure_timeout);
    810851        apr_global_mutex_unlock(sc->ocsp_mutex);
    811852        goto fail_cleanup;
     
    814855
    815856    /* retry reading from cache */
    816     *ocsp_response = sc->cache->fetch(ctxt,
    817                                       sc->ocsp->fingerprint);
     857    *ocsp_response = mgs_cache_fetch(ctxt->sc->ocsp_cache,
     858                                     ctxt->c->base_server,
     859                                     ctxt->sc->ocsp->fingerprint,
     860                                     ctxt->c->pool);
    818861    if (ocsp_response->size == 0)
    819862    {
     
    908951
    909952
     953/** The maximum random fuzz base (half the maximum fuzz) that will not
     954 * overflow. The permitted values are limited to whatever will not
     955 * make an `apr_interval_time_t` variable overflow when multiplied
     956 * with `APR_UINT16_MAX`. With apr_interval_time_t being a 64 bit
     957 * signed integer the maximum fuzz interval is about 4.5 years, which
     958 * should be more than plenty. */
     959#define MAX_FUZZ_BASE (APR_INT64_MAX / APR_UINT16_MAX)
     960
     961/**
     962 * Perform an asynchronous OCSP cache update. This is a callback for
     963 * mod_watchdog, so the API is fixed.
     964 *
     965 * @param state watchdog state (starting/running/stopping)
     966 * @param data callback data, contains the server_rec
     967 * @param pool temporary callback pool destroyed after the call
     968 * @return always `APR_SUCCESS` as required by the mod_watchdog API to
     969 * indicate that the callback should be called again
     970 */
     971static apr_status_t mgs_async_ocsp_update(int state,
     972                                          void *data,
     973                                          apr_pool_t *pool)
     974{
     975    /* If the server is stopping there's no need to do an OCSP
     976     * update. */
     977    if (state == AP_WATCHDOG_STATE_STOPPING)
     978        return APR_SUCCESS;
     979
     980    server_rec *server = (server_rec *) data;
     981    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
     982        ap_get_module_config(server->module_config, &gnutls_module);
     983    apr_time_t expiry = 0;
     984
     985    /* Holding the mutex should help avoiding simultaneous synchronous
     986     * and asynchronous OCSP requests in some edge cases: during
     987     * startup if there's an early request, and if OCSP requests fail
     988     * repeatedly until the cached response expires and a synchronous
     989     * update is triggered before a failure cache entry is
     990     * created. Usually there should be a good OCSP response in the
     991     * cache and the mutex is never touched in
     992     * mgs_get_ocsp_response. */
     993    apr_global_mutex_lock(sc->ocsp_mutex);
     994    apr_status_t rv = mgs_cache_ocsp_response(server, &expiry);
     995
     996    apr_interval_time_t next_interval;
     997    if (rv != APR_SUCCESS)
     998        next_interval = sc->ocsp_failure_timeout;
     999    else
     1000    {
     1001        apr_uint16_t random_bytes;
     1002        int res = gnutls_rnd(GNUTLS_RND_NONCE, &random_bytes,
     1003                             sizeof(random_bytes));
     1004        if (__builtin_expect(res < 0, 0))
     1005        {
     1006            /* Shouldn't ever happen, because a working random number
     1007             * generator is required for establishing TLS sessions. */
     1008            random_bytes = (apr_uint16_t) apr_time_now();
     1009            ap_log_error(APLOG_MARK, APLOG_WARNING, APR_EGENERAL, server,
     1010                         "Error getting random number for fuzzy update "
     1011                         "interval: %s Falling back on truncated time.",
     1012                         gnutls_strerror(res));
     1013        }
     1014
     1015        /* Choose the fuzz interval for the next update between
     1016         * `sc->ocsp_fuzz_time` and twice that. */
     1017        apr_interval_time_t fuzz = sc->ocsp_fuzz_time
     1018            + (sc->ocsp_fuzz_time * random_bytes / APR_UINT16_MAX);
     1019
     1020        /* With an extremly short timeout or weird nextUpdate value
     1021         * next_interval <= 0 might happen. Use the failure timeout to
     1022         * avoid endlessly repeating updates. */
     1023        next_interval = expiry - apr_time_now();
     1024        if (next_interval <= 0)
     1025        {
     1026            next_interval = sc->ocsp_failure_timeout;
     1027            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server,
     1028                         "OCSP cache expiration time of the response for "
     1029                         "%s:%d is in the past, repeating after failure "
     1030                         "timeout (GnuTLSOCSPFailureTimeout).",
     1031                         server->server_hostname, server->addrs->host_port);
     1032        }
     1033
     1034        /* It's possible to compare maximum fuzz and configured OCSP
     1035         * cache timeout at configuration time, but the interval until
     1036         * the nextUpdate value expires (or the failure timeout
     1037         * fallback above) might be shorter. Make sure that we don't
     1038         * end up with a negative interval. */
     1039        while (fuzz > next_interval)
     1040            fuzz /= 2;
     1041        next_interval -= fuzz;
     1042    }
     1043
     1044    sc->singleton_wd->set_callback_interval(sc->singleton_wd->wd,
     1045                                            next_interval,
     1046                                            server, mgs_async_ocsp_update);
     1047
     1048    ap_log_error(APLOG_MARK, rv == APR_SUCCESS ? APLOG_DEBUG : APLOG_WARNING,
     1049                 rv, server,
     1050                 "Async OCSP update %s for %s:%d, next update in "
     1051                 "%" APR_TIME_T_FMT " seconds.",
     1052                 rv == APR_SUCCESS ? "done" : "failed",
     1053                 server->server_hostname, server->addrs->host_port,
     1054                 apr_time_sec(next_interval));
     1055
     1056    /* Check if there's still a response in the cache. If not, add a
     1057     * failure entry. If there already is a failure entry, refresh
     1058     * it. The lifetime of such entries is twice the error timeout to
     1059     * make sure they do not expire before the next scheduled
     1060     * update. */
     1061    if (rv != APR_SUCCESS)
     1062    {
     1063        const gnutls_datum_t ocsp_response =
     1064            mgs_cache_fetch(sc->ocsp_cache, server,
     1065                            sc->ocsp->fingerprint, pool);
     1066
     1067        if (ocsp_response.size == 0 ||
     1068            ((ocsp_response.size == sizeof(unsigned char)) &&
     1069             (*((unsigned char *) ocsp_response.data) ==
     1070              OCSP_FAILURE_CACHE_DATA)))
     1071        {
     1072            ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, server,
     1073                         "Caching OCSP request failure for %s:%d.",
     1074                         server->server_hostname, server->addrs->host_port);
     1075            mgs_cache_ocsp_failure(server, sc->ocsp_failure_timeout * 2);
     1076        }
     1077
     1078        /* Get rid of the response, if any */
     1079        if (ocsp_response.size != 0)
     1080            gnutls_free(ocsp_response.data);
     1081    }
     1082    apr_global_mutex_unlock(sc->ocsp_mutex);
     1083
     1084    return APR_SUCCESS;
     1085}
     1086
     1087
     1088
     1089const char* mgs_ocsp_configure_stapling(apr_pool_t *pconf,
     1090                                        apr_pool_t *ptemp __attribute__((unused)),
     1091                                        server_rec *server)
     1092{
     1093    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
     1094        ap_get_module_config(server->module_config, &gnutls_module);
     1095
     1096    if (sc->certs_x509_chain_num < 2)
     1097        return "No issuer (CA) certificate available, cannot enable "
     1098            "stapling. Please add it to the GnuTLSCertificateFile.";
     1099
     1100    mgs_ocsp_data_t ocsp = apr_palloc(pconf, sizeof(struct mgs_ocsp_data));
     1101
     1102    ocsp->uri = mgs_cert_get_ocsp_uri(pconf,
     1103                                      sc->certs_x509_crt_chain[0]);
     1104    if (ocsp->uri == NULL && sc->ocsp_response_file == NULL)
     1105        return "No OCSP URI in the certificate nor a GnuTLSOCSPResponseFile "
     1106            "setting, cannot configure OCSP stapling.";
     1107
     1108    if (sc->ocsp_cache == NULL)
     1109        return "No OCSP response cache available, please check "
     1110            "the GnuTLSOCSPCache setting.";
     1111
     1112    sc->ocsp = ocsp;
     1113    return NULL;
     1114}
     1115
     1116
     1117
    9101118/*
    9111119 * Like in the general post_config hook the HTTP status codes for
     
    9131121 * to denote an error.
    9141122 */
    915 int mgs_ocsp_post_config_server(apr_pool_t *pconf,
    916                                 apr_pool_t *ptemp __attribute__((unused)),
    917                                 server_rec *server)
     1123int mgs_ocsp_enable_stapling(apr_pool_t *pconf,
     1124                             apr_pool_t *ptemp __attribute__((unused)),
     1125                             server_rec *server)
    9181126{
    9191127    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
    9201128        ap_get_module_config(server->module_config, &gnutls_module);
    921 
    922     if (sc->certs_x509_chain_num < 2)
    923     {
    924         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, server,
    925                      "OCSP stapling is enabled but no CA certificate "
    926                      "available for %s:%d, make sure it is included in "
    927                      "GnuTLSCertificateFile!",
    928                      server->server_hostname, server->addrs->host_port);
    929         return HTTP_NOT_FOUND;
     1129    if (sc->ocsp == NULL)
     1130    {
     1131        ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EGENERAL, server,
     1132                     "CRITICAL ERROR: %s called with uninitialized OCSP "
     1133                     "data structure. This indicates a bug in mod_gnutls.",
     1134                     __func__);
     1135        return HTTP_INTERNAL_SERVER_ERROR;
    9301136    }
    9311137
    9321138    /* set default values for unset parameters */
     1139    if (sc->ocsp_auto_refresh == GNUTLS_ENABLED_UNSET)
     1140        sc->ocsp_auto_refresh = GNUTLS_ENABLED_TRUE;
    9331141    if (sc->ocsp_check_nonce == GNUTLS_ENABLED_UNSET)
    9341142        sc->ocsp_check_nonce = GNUTLS_ENABLED_TRUE;
     
    9391147    if (sc->ocsp_socket_timeout == MGS_TIMEOUT_UNSET)
    9401148        sc->ocsp_socket_timeout = apr_time_from_sec(MGS_OCSP_SOCKET_TIMEOUT);
    941 
    942     sc->ocsp = apr_palloc(pconf, sizeof(struct mgs_ocsp_data));
     1149    /* Base fuzz is half the configured maximum, the actual fuzz is
     1150     * between the maximum and half that. The default maximum is
     1151     * sc->ocsp_cache_time / 8, or twice the failure timeout,
     1152     * whichever is larger (so the default guarantees at least one
     1153     * retry before the cache entry expires).*/
     1154    if (sc->ocsp_fuzz_time == MGS_TIMEOUT_UNSET)
     1155    {
     1156        sc->ocsp_fuzz_time = sc->ocsp_cache_time / 16;
     1157        if (sc->ocsp_fuzz_time < sc->ocsp_failure_timeout)
     1158            sc->ocsp_fuzz_time = sc->ocsp_failure_timeout;
     1159    }
     1160    else
     1161        sc->ocsp_fuzz_time = sc->ocsp_fuzz_time / 2;
     1162
     1163    /* This really shouldn't happen considering MAX_FUZZ_BASE is about
     1164     * 4.5 years, but better safe than sorry. */
     1165    if (sc->ocsp_fuzz_time > MAX_FUZZ_BASE)
     1166    {
     1167        ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EINVAL, server,
     1168                     "%s: Maximum fuzz time is too large, maximum "
     1169                     "supported value is %" APR_INT64_T_FMT " seconds",
     1170                     __func__, apr_time_sec(MAX_FUZZ_BASE) * 2);
     1171        return HTTP_INTERNAL_SERVER_ERROR;
     1172    }
    9431173
    9441174    sc->ocsp->fingerprint =
     
    9471177        return HTTP_INTERNAL_SERVER_ERROR;
    9481178
    949     sc->ocsp->uri = mgs_cert_get_ocsp_uri(pconf,
    950                                           sc->certs_x509_crt_chain[0]);
    951     if (sc->ocsp->uri == NULL && sc->ocsp_response_file == NULL)
    952     {
    953         ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, server,
    954                      "OCSP stapling is enabled for for %s:%d, but there is "
    955                      "neither an OCSP URI in the certificate nor a "
    956                      "GnuTLSOCSPResponseFile setting for this host!",
    957                      server->server_hostname, server->addrs->host_port);
    958         return HTTP_NOT_FOUND;
    959     }
    960 
    9611179    sc->ocsp->trust = apr_palloc(pconf,
    9621180                                 sizeof(gnutls_x509_trust_list_t));
    963      /* Only the direct issuer may sign the OCSP response or an OCSP
    964       * signer. */
     1181    /* Only the direct issuer may sign the OCSP response or an OCSP
     1182     * signer. */
    9651183    int ret = mgs_create_ocsp_trust_list(sc->ocsp->trust,
    9661184                                         &(sc->certs_x509_crt_chain[1]),
     
    9831201                                                        sc);
    9841202
     1203    /* The watchdog structure may be NULL if mod_watchdog is
     1204     * unavailable. */
     1205    if (sc->singleton_wd != NULL
     1206        && sc->ocsp_auto_refresh == GNUTLS_ENABLED_TRUE)
     1207    {
     1208        apr_status_t rv =
     1209            sc->singleton_wd->register_callback(sc->singleton_wd->wd,
     1210                                                sc->ocsp_cache_time,
     1211                                                server, mgs_async_ocsp_update);
     1212        if (rv == APR_SUCCESS)
     1213            ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
     1214                         "Enabled async OCSP update via watchdog "
     1215                         "for %s:%d",
     1216                         server->server_hostname, server->addrs->host_port);
     1217        else
     1218            ap_log_error(APLOG_MARK, APLOG_WARNING, rv, server,
     1219                         "Enabling async OCSP update via watchdog "
     1220                         "for %s:%d failed!",
     1221                         server->server_hostname, server->addrs->host_port);
     1222    }
     1223
    9851224    return OK;
    9861225}
  • src/gnutls_ocsp.h

    r0931b35 r19e80a5  
    11/*
    2  *  Copyright 2016 Fiona Klute
     2 *  Copyright 2016-2018 Fiona Klute
    33 *
    44 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2424
    2525#define MGS_OCSP_MUTEX_NAME "gnutls-ocsp"
     26#define MGS_OCSP_CACHE_MUTEX_NAME "gnutls-ocsp-cache"
     27#define MGS_OCSP_CACHE_NAME "gnutls_ocsp"
    2628
    2729/** Default OCSP response cache timeout in seconds */
     
    5355                                     void *dummy __attribute__((unused)),
    5456                                     const int arg);
     57
     58const char *mgs_set_ocsp_auto_refresh(cmd_parms *parms,
     59                                      void *dummy __attribute__((unused)),
     60                                      const int arg);
    5561
    5662const char *mgs_set_ocsp_check_nonce(cmd_parms *parms,
     
    9298
    9399/**
    94  * Initialize server config for OCSP, supposed to be called in the
    95  * post_config hook for each server where OCSP stapling is enabled,
    96  * after certificates have been loaded.
     100 * Try to generate the OCSP stapling configuration for a (virtual)
     101 * host. This function must be called in the post_config hook after
     102 * certificates have been loaded. This method does not actually enable
     103 * stapling, it only prepares the configuration. The reason for
     104 * splitting these tasks is that configuration failure may be ignored
     105 * if stapling is not explicitly enabled but only opportunistically.
     106 *
     107 * @return `NULL` on success, a string describing why configuration
     108 * failed otherwise (static or allocated from ptemp)
     109 */
     110const char* mgs_ocsp_configure_stapling(apr_pool_t *pconf, apr_pool_t *ptemp,
     111                                        server_rec *server);
     112
     113/**
     114 * Enable OCSP stapling for a (virtual) host. Must be called in the
     115 * post_config hook after mgs_ocsp_configure_stapling has returned
     116 * successfully for that host.
    97117 *
    98118 * @return OK or DECLINED on success, any other value on error (like
    99  * the post_config hook itself)
     119 * the post_config hook)
    100120 */
    101 int mgs_ocsp_post_config_server(apr_pool_t *pconf, apr_pool_t *ptemp,
    102                                 server_rec *server);
     121int mgs_ocsp_enable_stapling(apr_pool_t *pconf, apr_pool_t *ptemp,
     122                             server_rec *server);
    103123
    104124int mgs_get_ocsp_response(gnutls_session_t session, void *ptr,
  • src/gnutls_util.c

    r0931b35 r19e80a5  
    11/*
    2  *  Copyright 2016-2018 Fiona Klute
     2 *  Copyright 2016-2019 Fiona Klute
    33 *
    44 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    1919#include <apr_strings.h>
    2020#include <gnutls/gnutls.h>
     21
     22
     23
     24/** Compiled version of MGS_DEFAULT_PRIORITY, must be initialized
     25 * using mgs_default_priority_init() in the pre_config hook and
     26 * deinitialized in the matching pool cleanup hook. */
     27static gnutls_priority_t default_prio;
     28
    2129
    2230
     
    148156        /* Default, unconditionally changed in proxy setup functions */
    149157        ctxt->is_proxy = GNUTLS_ENABLED_FALSE;
     158        /* Other default values */
     159        ctxt->sni_name = NULL;
    150160    }
    151161    return ctxt;
    152162}
     163
     164
     165
     166int mgs_default_priority_init()
     167{
     168    return gnutls_priority_init(&default_prio, MGS_DEFAULT_PRIORITY, NULL);
     169}
     170
     171
     172
     173gnutls_priority_t mgs_get_default_prio()
     174{
     175    return default_prio;
     176}
     177
     178
     179
     180void mgs_default_priority_deinit()
     181{
     182    gnutls_priority_deinit(default_prio);
     183}
     184
     185
     186
     187gnutls_datum_t * mgs_str_array_to_datum_array(const apr_array_header_t *src,
     188                                              apr_pool_t *pool,
     189                                              const int min_elements)
     190{
     191    int num = min_elements > src->nelts ? min_elements : src->nelts;
     192    gnutls_datum_t *dest = apr_palloc(pool, num * sizeof(gnutls_datum_t));
     193    for (int i = 0; i < src->nelts; i++)
     194    {
     195        dest[i].data = (void *) APR_ARRAY_IDX(src, i, char *);
     196        dest[i].size = strlen(APR_ARRAY_IDX(src, i, char *));
     197    }
     198    return dest;
     199}
  • src/gnutls_util.h

    r0931b35 r19e80a5  
    11/*
    2  *  Copyright 2016-2018 Fiona Klute
     2 *  Copyright 2016-2019 Fiona Klute
    33 *
    44 *  Licensed under the Apache License, Version 2.0 (the "License");
     
    2525#ifndef __MOD_GNUTLS_UTIL_H__
    2626#define __MOD_GNUTLS_UTIL_H__
     27
     28/** Default GnuTLS priority string for mod_gnutls */
     29#define MGS_DEFAULT_PRIORITY "NORMAL"
    2730
    2831/** maximum allowed length of one header line */
     
    7477mgs_handle_t *init_gnutls_ctxt(conn_rec *c);
    7578
     79/**
     80 * Initialize the global default priorities, must be called by the
     81 * pre_config hook
     82 *
     83 * @return `GNUTLS_E_SUCCESS` or a GnuTLS error code
     84 */
     85int mgs_default_priority_init();
     86
     87/**
     88 * Get the global default priorities
     89 */
     90gnutls_priority_t mgs_get_default_prio();
     91
     92/**
     93 * Deinitialize the global default priorities, must be in the cleanup
     94 * hook of the pre_config pool.
     95 */
     96void mgs_default_priority_deinit();
     97
     98/**
     99 * Create a shallow copy of an APR array of `char *` into a new array
     100 * of gnutls_datum_t, filling `size` via `strlen()`. "Shallow copy"
     101 * means that the strings themselves are not copied, just the pointers
     102 * to them.
     103 *
     104 * @param src array to copy
     105 * @param pool allocate memory for the new array
     106 * @param min_elements allocate room for at least this many elements
     107 *
     108 * @return pointer to the first element of the new array
     109 */
     110gnutls_datum_t * mgs_str_array_to_datum_array(const apr_array_header_t *src,
     111                                              apr_pool_t *pool,
     112                                              const int min_elements);
     113
    76114#endif /* __MOD_GNUTLS_UTIL_H__ */
  • src/mod_gnutls.c

    r0931b35 r19e80a5  
    1919
    2020#include "mod_gnutls.h"
     21#include "gnutls_config.h"
    2122#include "gnutls_ocsp.h"
    2223#include "gnutls_util.h"
     24
     25#include <apr_strings.h>
    2326
    2427#ifdef APLOG_USE_MODULE
     
    3033                   int proxy, int enable);
    3134
     35#define MOD_HTTP2 "mod_http2.c"
     36#define MOD_WATCHDOG "mod_watchdog.c"
    3237static const char * const mod_proxy[] = { "mod_proxy.c", NULL };
    33 static const char * const mod_http2[] = { "mod_http2.c", NULL };
     38static const char * const mod_http2[] = { MOD_HTTP2, NULL };
     39static const char * const mod_watchdog[] = { MOD_WATCHDOG, NULL };
    3440
    3541static void gnutls_hooks(apr_pool_t * p __attribute__((unused)))
    3642{
    37     /* Try Run Post-Config Hook After mod_proxy */
    38     ap_hook_post_config(mgs_hook_post_config, mod_proxy, mod_http2,
     43    /* Watchdog callbacks must be configured before post_config of
     44     * mod_watchdog runs, or the watchdog won't be started. Similarly,
     45     * our child_init hook must run before mod_watchdog's because our
     46     * watchdog threads are started there and need some child-specific
     47     * resources. */
     48    static const char * const post_conf_succ[] =
     49        { MOD_HTTP2, MOD_WATCHDOG, NULL };
     50    ap_hook_post_config(mgs_hook_post_config, mod_proxy, post_conf_succ,
    3951                        APR_HOOK_MIDDLE);
    4052    /* HTTP Scheme Hook */
     
    5163                       APR_HOOK_MIDDLE);
    5264    /* Child-Init Hook */
    53     ap_hook_child_init(mgs_hook_child_init, NULL, NULL,
     65    ap_hook_child_init(mgs_hook_child_init, NULL, mod_watchdog,
    5466                       APR_HOOK_MIDDLE);
    5567    /* Authentication Hook */
     
    5870    /* Fixups Hook */
    5971    ap_hook_fixups(mgs_hook_fixups, NULL, NULL, APR_HOOK_REALLY_FIRST);
     72
     73    /* Request hook: Check if TLS connection and request host match */
     74    ap_hook_post_read_request(mgs_req_vhost_check, NULL, NULL, APR_HOOK_MIDDLE);
    6075
    6176    /* TODO: HTTP Upgrade Filter */
     
    209224        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
    210225                      "%s: mod_proxy requested TLS proxy, but not enabled "
    211                       "for %s", __func__, ctxt->sc->cert_cn);
     226                      "for %s:%d", __func__,
     227                      ctxt->c->base_server->server_hostname,
     228                      ctxt->c->base_server->addrs->host_port);
    212229        return 0;
    213230    }