Changeset c6dda6d in mod_gnutls


Ignore:
Timestamp:
Oct 21, 2016, 6:40:02 PM (14 months ago)
Author:
Thomas Klute <thomas2.klute@…>
Branches:
master, debian, upstream
Children:
333bbc7
Parents:
d26fa55
Message:

Rate limit OCSP requests

Retries after failed OCSP requests must be rate limited. If the
responder is overloaded or buggy we don't want to add too much more
load, and if a MITM is messing with requests a repetition loop might
end up being a self-inflicted denial of service.

The minimum time to wait between retries can be configured using the
GnuTLSOCSPFailureTimeout directive.

Files:
5 edited

Legend:

Unmodified
Added
Removed
  • doc/mod_gnutls_manual.mdwn

    rdf49a2d rc6dda6d  
    586586account for potential clock skew between server, CA, and client, as
    587587well as transmission time in corner cases.
     588
     589### GnuTLSOCSPFailureTimeout
     590
     591EXPERIMENTAL: Wait this many seconds before retrying a failed OCSP request.
     592
     593    GnuTLSOCSPFailureTimeout SECONDS
     594
     595Default: *300*\
     596Context: server config, virtual host
     597
     598Retries of failed OCSP requests must be rate limited to avoid
     599overloading both the server using mod_gnutls and the CA's OCSP
     600responder. A shorter value increases the load on both sides, a longer
     601one means that stapling will remain disabled for longer after a failed
     602request.
    588603
    589604* * * * *
  • include/mod_gnutls.h.in

    r78b75b3 rc6dda6d  
    216216     * instead of sending a request over HTTP */
    217217    char *ocsp_response_file;
    218     /* Server specific OCSP data */
     218    /* Internal OCSP data for this server */
    219219    mgs_ocsp_data_t ocsp;
    220220    /* Mutex to prevent parallel OCSP requests */
     
    224224     * valid responses. */
    225225    apr_time_t ocsp_grace_time;
     226    /* If an OCSP request fails wait this long before trying again. */
     227    apr_time_t ocsp_failure_timeout;
    226228} mgs_srvconf_rec;
    227229
  • src/gnutls_config.c

    rd26fa55 rc6dda6d  
    2626/* Default OCSP response grace time in seconds */
    2727#define MGS_GRACE_TIME 60
     28/* Default OCSP failure timeout in seconds */
     29#define MGS_FAILURE_TIMEOUT 300
    2830
    2931#ifdef APLOG_USE_MODULE
     
    870872                                "GnuTLSOCSPGraceTime"))
    871873        sc->ocsp_grace_time = apr_time_from_sec(argint);
     874    else if (!apr_strnatcasecmp(parms->directive->directive,
     875                                "GnuTLSOCSPFailureTimeout"))
     876        sc->ocsp_failure_timeout = apr_time_from_sec(argint);
    872877    else
    873878        /* Can't happen unless there's a serious bug in mod_gnutls or Apache */
     
    11231128    sc->ocsp_mutex = NULL;
    11241129    sc->ocsp_grace_time = apr_time_from_sec(MGS_GRACE_TIME);
     1130    sc->ocsp_failure_timeout = apr_time_from_sec(MGS_FAILURE_TIMEOUT);
    11251131
    11261132/* this relies on GnuTLS never changing the gnutls_certificate_request_t enum to define -1 */
     
    11831189    gnutls_srvconf_assign(ocsp_response_file);
    11841190    gnutls_srvconf_merge(ocsp_grace_time, apr_time_from_sec(MGS_GRACE_TIME));
     1191    gnutls_srvconf_merge(ocsp_failure_timeout,
     1192                         apr_time_from_sec(MGS_FAILURE_TIMEOUT));
    11851193
    11861194    gnutls_srvconf_assign(ca_list);
  • src/gnutls_ocsp.c

    r3f0b470 rc6dda6d  
    3939 * or received", not the whole connection. 10 seconds in mod_ssl. */
    4040#define OCSP_SOCKET_TIMEOUT 2
     41
     42/* Dummy data for failure cache entries (one byte). */
     43#define OCSP_FAILURE_CACHE_DATA 0x0f
    4144
    4245
     
    684687
    685688
     689/*
     690 * Retries after failed OCSP requests must be rate limited. If the
     691 * responder is overloaded or buggy we don't want to add too much more
     692 * load, and if a MITM is messing with requests a repetition loop
     693 * might end up being a self-inflicted denial of service.
     694 */
     695void mgs_cache_ocsp_failure(server_rec *s)
     696{
     697    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
     698        ap_get_module_config(s->module_config, &gnutls_module);
     699
     700    unsigned char c = OCSP_FAILURE_CACHE_DATA;
     701    gnutls_datum_t dummy = {
     702        .data = &c,
     703        .size = sizeof(c)
     704    };
     705    apr_time_t expiry = apr_time_now() + sc->ocsp_failure_timeout;
     706
     707    char date_str[APR_RFC822_DATE_LEN];
     708    apr_rfc822_date(date_str, expiry);
     709    ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
     710                 "OCSP request for %s failed, next try after %s.",
     711                 s->server_hostname, date_str);
     712
     713    int r = sc->cache->store(s, sc->ocsp->fingerprint, dummy, expiry);
     714    if (r != 0)
     715        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
     716                     "Caching OCSP failure failed.");
     717}
     718
     719
     720
    686721int mgs_get_ocsp_response(gnutls_session_t session __attribute__((unused)),
    687722                          void *ptr,
     
    702737                      "Fetching OCSP response from cache failed.");
    703738    }
     739    else if ((ocsp_response->size == sizeof(unsigned char)) &&
     740             (*((unsigned char *) ocsp_response->data) == OCSP_FAILURE_CACHE_DATA))
     741    {
     742        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_EGENERAL, ctxt->c,
     743                      "Cached OCSP failure found for %s.",
     744                      ctxt->c->base_server->server_hostname);
     745        goto fail_cleanup;
     746    }
    704747    else
    705748    {
     
    714757                  "No valid OCSP response in cache, trying to update.");
    715758
    716     /* TODO: Once sending OCSP requests is implemented we need a rate
    717      * limit for retries on error. If the responder is overloaded or
    718      * buggy we don't want to add too much more load, and if a MITM is
    719      * messing with requests a repetition loop might end up being a
    720      * self-inflicted denial of service. */
    721759    apr_status_t rv = apr_global_mutex_trylock(ctxt->sc->ocsp_mutex);
    722760    if (APR_STATUS_IS_EBUSY(rv))
     
    747785    {
    748786        ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, ctxt->c,
    749                       "Updating OCSP response cache failed");
     787                      "Caching a fresh OCSP response failed");
     788        /* cache failure to rate limit retries */
     789        mgs_cache_ocsp_failure(ctxt->c->base_server);
    750790        apr_global_mutex_unlock(ctxt->sc->ocsp_mutex);
    751791        goto fail_cleanup;
  • src/mod_gnutls.c

    r78b75b3 rc6dda6d  
    284284                  "EXPERIMENTAL: Replace cached OCSP responses this many "
    285285                  "seconds before they expire"),
     286    AP_INIT_TAKE1("GnuTLSOCSPFailureTimeout", mgs_set_timeout,
     287                  NULL, RSRC_CONF,
     288                  "EXPERIMENTAL: Wait this many seconds before retrying a "
     289                  "failed OCSP request"),
    286290#ifdef __clang__
    287291    /* Workaround for this clang bug:
Note: See TracChangeset for help on using the changeset viewer.