Changeset 19e80a5 in mod_gnutls for src/gnutls_ocsp.c


Ignore:
Timestamp:
Jan 28, 2019, 2:50:38 PM (16 months 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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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}
Note: See TracChangeset for help on using the changeset viewer.