source: mod_gnutls/src/gnutls_ocsp.c @ 4e60dd8

proxy-ticket
Last change on this file since 4e60dd8 was 4e60dd8, checked in by Fiona Klute <fiona.klute@…>, 9 months ago

Handle initialization of the OCSP data structure in one place

This will make it easier to loop over the certificate chain for OCSP
multi staple.

  • Property mode set to 100644
File size: 44.2 KB
Line 
1/*
2 *  Copyright 2016-2020 Fiona Klute
3 *
4 *  Licensed under the Apache License, Version 2.0 (the "License");
5 *  you may not use this file except in compliance with the License.
6 *  You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *  Unless required by applicable law or agreed to in writing, software
11 *  distributed under the License is distributed on an "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 *  See the License for the specific language governing permissions and
14 *  limitations under the License.
15 */
16
17#include "gnutls_ocsp.h"
18#include "mod_gnutls.h"
19#include "gnutls_cache.h"
20#include "gnutls_config.h"
21#include "gnutls_util.h"
22#include "gnutls_watchdog.h"
23
24#include <apr_escape.h>
25#include <apr_lib.h>
26#include <apr_time.h>
27#include <gnutls/crypto.h>
28#include <gnutls/ocsp.h>
29#include <mod_watchdog.h>
30#include <time.h>
31
32#ifdef APLOG_USE_MODULE
33APLOG_USE_MODULE(gnutls);
34#endif
35
36/** maximum supported OCSP response size, 8K should be plenty */
37#define OCSP_RESP_SIZE_MAX (8 * 1024)
38#define OCSP_REQ_TYPE "application/ocsp-request"
39#define OCSP_RESP_TYPE "application/ocsp-response"
40
41/** Dummy data for failure cache entries (one byte). */
42#define OCSP_FAILURE_CACHE_DATA 0x0f
43/** Macro to check if an OCSP reponse pointer contains a cached
44 * failure */
45#define IS_FAILURE_RESPONSE(resp) \
46    (((resp)->size == sizeof(unsigned char)) &&                     \
47     (*((unsigned char *) (resp)->data) == OCSP_FAILURE_CACHE_DATA))
48
49
50#define _log_one_ocsp_fail(str, srv)                                    \
51    ap_log_error(APLOG_MARK, APLOG_INFO, APR_EGENERAL, (srv),           \
52                 "Reason for failed OCSP response verification: %s", (str))
53/**
54 * Log all matching reasons for verification failure
55 */
56static void _log_verify_fail_reason(const unsigned int verify, server_rec *s)
57{
58    if (verify & GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND)
59        _log_one_ocsp_fail("Signer cert not found", s);
60
61    if (verify & GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR)
62        _log_one_ocsp_fail("Signer cert keyusage error", s);
63
64    if (verify & GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER)
65        _log_one_ocsp_fail("Signer cert is not trusted", s);
66
67    if (verify & GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM)
68        _log_one_ocsp_fail("Insecure algorithm", s);
69
70    if (verify & GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE)
71        _log_one_ocsp_fail("Signature failure", s);
72
73    if (verify & GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED)
74        _log_one_ocsp_fail("Signer cert not yet activated", s);
75
76    if (verify & GNUTLS_OCSP_VERIFY_CERT_EXPIRED)
77        _log_one_ocsp_fail("Signer cert expired", s);
78}
79
80
81
82const char *mgs_ocsp_stapling_enable(cmd_parms *parms,
83                                     void *dummy __attribute__((unused)),
84                                     const int arg)
85{
86    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
87        ap_get_module_config(parms->server->module_config, &gnutls_module);
88
89    if (arg)
90        sc->ocsp_staple = GNUTLS_ENABLED_TRUE;
91    else
92        sc->ocsp_staple = GNUTLS_ENABLED_FALSE;
93
94    return NULL;
95}
96
97
98
99const char *mgs_set_ocsp_auto_refresh(cmd_parms *parms,
100                                      void *dummy __attribute__((unused)),
101                                      const int arg)
102{
103    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
104        ap_get_module_config(parms->server->module_config, &gnutls_module);
105
106    if (arg)
107        sc->ocsp_auto_refresh = GNUTLS_ENABLED_TRUE;
108    else
109        sc->ocsp_auto_refresh = GNUTLS_ENABLED_FALSE;
110
111    return NULL;
112}
113
114
115
116const char *mgs_set_ocsp_check_nonce(cmd_parms *parms,
117                                     void *dummy __attribute__((unused)),
118                                     const int arg)
119{
120    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
121        ap_get_module_config(parms->server->module_config, &gnutls_module);
122
123    if (arg)
124        sc->ocsp_check_nonce = GNUTLS_ENABLED_TRUE;
125    else
126        sc->ocsp_check_nonce = GNUTLS_ENABLED_FALSE;
127
128    return NULL;
129}
130
131
132
133const char *mgs_store_ocsp_response_path(cmd_parms *parms,
134                                         void *dummy __attribute__((unused)),
135                                         const char *arg)
136{
137    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
138        ap_get_module_config(parms->server->module_config, &gnutls_module);
139
140    sc->ocsp_response_file = ap_server_root_relative(parms->pool, arg);
141    return NULL;
142}
143
144
145
146/**
147 * Create an OCSP request for the certificate of the given server. The
148 * DER encoded request is stored in 'req' (must be released with
149 * gnutls_free() when no longer needed), its nonce in 'nonce' (same,
150 * if not NULL).
151 *
152 * @param s server reference for logging
153 *
154 * @return GNUTLS_E_SUCCESS, or a GnuTLS error code.
155 */
156static int mgs_create_ocsp_request(server_rec *s,
157                                   struct mgs_ocsp_data *req_data,
158                                   gnutls_datum_t *req,
159                                   gnutls_datum_t *nonce)
160    __attribute__((nonnull(1, 3)));
161static int mgs_create_ocsp_request(server_rec *s,
162                                   struct mgs_ocsp_data *req_data,
163                                   gnutls_datum_t *req,
164                                   gnutls_datum_t *nonce)
165{
166    gnutls_ocsp_req_t r;
167    int ret = gnutls_ocsp_req_init(&r);
168    if (ret != GNUTLS_E_SUCCESS)
169    {
170        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
171                     "Could not initialize OCSP request structure: %s (%d)",
172                     gnutls_strerror(ret), ret);
173        return ret;
174    }
175
176    /* issuer is set to a reference, so musn't be cleaned up */
177    gnutls_x509_crt_t issuer;
178    ret = gnutls_x509_trust_list_get_issuer(*req_data->trust, req_data->cert,
179                                            &issuer, 0);
180    if (ret != GNUTLS_E_SUCCESS)
181    {
182        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
183                     "Could not get issuer from trust list: %s (%d)",
184                     gnutls_strerror(ret), ret);
185        gnutls_ocsp_req_deinit(r);
186        return ret;
187    }
188
189    /* GnuTLS doc says that the digest is "normally"
190     * GNUTLS_DIG_SHA1. */
191    ret = gnutls_ocsp_req_add_cert(r, GNUTLS_DIG_SHA256,
192                                   issuer, req_data->cert);
193
194    if (ret != GNUTLS_E_SUCCESS)
195    {
196        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
197                     "Adding certificate to OCSP request for %s:%d "
198                     "failed: %s (%d)",
199                     s->server_hostname, s->addrs->host_port,
200                     gnutls_strerror(ret), ret);
201        gnutls_ocsp_req_deinit(r);
202        return ret;
203    }
204
205    ret = gnutls_ocsp_req_randomize_nonce(r);
206    if (ret != GNUTLS_E_SUCCESS)
207    {
208        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
209                     "OCSP nonce creation failed: %s (%d)",
210                     gnutls_strerror(ret), ret);
211        gnutls_ocsp_req_deinit(r);
212        return ret;
213    }
214
215    if (nonce != NULL)
216    {
217        ret = gnutls_ocsp_req_get_nonce(r, NULL, nonce);
218        if (ret != GNUTLS_E_SUCCESS)
219        {
220            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
221                         "Could not get nonce: %s (%d)",
222                         gnutls_strerror(ret), ret);
223            gnutls_free(nonce->data);
224            nonce->data = NULL;
225            nonce->size = 0;
226            gnutls_ocsp_req_deinit(r);
227            return ret;
228        }
229    }
230
231    ret = gnutls_ocsp_req_export(r, req);
232    if (ret != GNUTLS_E_SUCCESS)
233    {
234        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
235                     "OCSP request export failed: %s (%d)",
236                     gnutls_strerror(ret), ret);
237        gnutls_free(req->data);
238        req->data = NULL;
239        req->size = 0;
240        if (nonce != NULL)
241        {
242            gnutls_free(nonce->data);
243            nonce->data = NULL;
244            nonce->size = 0;
245        }
246        gnutls_ocsp_req_deinit(r);
247        return ret;
248    }
249
250    gnutls_ocsp_req_deinit(r);
251    return ret;
252}
253
254
255
256/**
257 * Check if the provided OCSP response is usable for stapling in
258 * connections to this server. Returns GNUTLS_E_SUCCESS if yes.
259 *
260 * Supports only one certificate status per response.
261 *
262 * If expiry is not NULL, it will be set to the nextUpdate time
263 * contained in the response, or zero if the response does not contain
264 * a nextUpdate field.
265 *
266 * If nonce is not NULL, the response must contain a matching nonce.
267 */
268int check_ocsp_response(server_rec *s, struct mgs_ocsp_data *req_data,
269                        const gnutls_datum_t *ocsp_response,
270                        apr_time_t* expiry, const gnutls_datum_t *nonce)
271    __attribute__((nonnull(1, 3)));
272int check_ocsp_response(server_rec *s, struct mgs_ocsp_data *req_data,
273                        const gnutls_datum_t *ocsp_response,
274                        apr_time_t* expiry, const gnutls_datum_t *nonce)
275{
276    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
277        ap_get_module_config(s->module_config, &gnutls_module);
278
279    if (req_data->trust == NULL)
280    {
281        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
282                     "No OCSP trust list available for server \"%s\"!",
283                     s->server_hostname);
284        return GNUTLS_E_NO_CERTIFICATE_FOUND;
285    }
286
287    gnutls_ocsp_resp_t resp;
288    int ret = gnutls_ocsp_resp_init(&resp);
289    if (ret != GNUTLS_E_SUCCESS)
290    {
291        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
292                     "Could not initialize OCSP response structure: %s (%d)",
293                     gnutls_strerror(ret), ret);
294        goto resp_cleanup;
295    }
296    ret = gnutls_ocsp_resp_import(resp, ocsp_response);
297    if (ret != GNUTLS_E_SUCCESS)
298    {
299        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
300                     "Importing OCSP response failed: %s (%d)",
301                     gnutls_strerror(ret), ret);
302        goto resp_cleanup;
303    }
304
305    ret = gnutls_ocsp_resp_check_crt(resp, 0, req_data->cert);
306    if (ret != GNUTLS_E_SUCCESS)
307    {
308        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
309                     "OCSP response is not for server certificate: %s (%d)",
310                     gnutls_strerror(ret), ret);
311        goto resp_cleanup;
312    }
313
314    unsigned int verify;
315    ret = gnutls_ocsp_resp_verify(resp, *(req_data->trust), &verify, 0);
316    if (ret != GNUTLS_E_SUCCESS)
317    {
318        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
319                     "OCSP response verification failed: %s (%d)",
320                     gnutls_strerror(ret), ret);
321        goto resp_cleanup;
322    }
323    else
324    {
325        /* verification worked, check the result */
326        if (verify != 0)
327        {
328            _log_verify_fail_reason(verify, s);
329            ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
330            goto resp_cleanup;
331        }
332        else
333            ap_log_error(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, s,
334                         "OCSP response signature is valid.");
335    }
336
337    /* Even some large CAs do not support nonces, probably because
338     * that way they can cache responses. :-/ */
339    if (nonce != NULL && sc->ocsp_check_nonce)
340    {
341        gnutls_datum_t resp_nonce;
342        ret = gnutls_ocsp_resp_get_nonce(resp, 0, &resp_nonce);
343        if (ret != GNUTLS_E_SUCCESS)
344        {
345            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
346                         "Could not get OCSP response nonce: %s (%d)",
347                         gnutls_strerror(ret), ret);
348            goto resp_cleanup;
349        }
350        if (resp_nonce.size != nonce->size
351            || memcmp(resp_nonce.data, nonce->data, nonce->size))
352        {
353            ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
354            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
355                         "OCSP response invalid: nonce mismatch");
356            gnutls_free(resp_nonce.data);
357            goto resp_cleanup;
358        }
359        ap_log_error(APLOG_MARK, APLOG_TRACE2, APR_SUCCESS, s,
360                     "OCSP response: nonce match");
361        gnutls_free(resp_nonce.data);
362    }
363
364    /* OK, response is for our certificate and valid, let's get the
365     * actual response data. */
366    unsigned int cert_status;
367    time_t this_update;
368    time_t next_update;
369    ret = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL, NULL,
370                                      &cert_status, &this_update,
371                                      &next_update, NULL, NULL);
372    if (ret != GNUTLS_E_SUCCESS)
373    {
374        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
375                     "Could not get OCSP response data: %s (%d)",
376                     gnutls_strerror(ret), ret);
377        goto resp_cleanup;
378    }
379
380    apr_time_t now = apr_time_now();
381    apr_time_t valid_at;
382    apr_time_ansi_put(&valid_at, this_update);
383    /* Buffer for human-readable times produced by apr_rfc822_date,
384     * see apr_time.h */
385    char date_str[APR_RFC822_DATE_LEN];
386    apr_rfc822_date(date_str, valid_at);
387
388    if (now < valid_at)
389    {
390        /* We don't know if our clock or that of the OCSP responder is
391         * out of sync, so warn but continue. */
392        ap_log_error(APLOG_MARK, APLOG_WARNING, APR_EGENERAL, s,
393                     "OSCP response claims to be from future (%s), check "
394                     "time synchronization!", date_str);
395    }
396
397    if (next_update == (time_t) -1)
398    {
399        ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, s,
400                     "OSCP response does not contain nextUpdate info.");
401        if (expiry != NULL)
402            *expiry = 0;
403    }
404    else
405    {
406        apr_time_t valid_to;
407        apr_time_ansi_put(&valid_to, next_update);
408        if (expiry != NULL)
409            *expiry = valid_to;
410        if (now > valid_to)
411        {
412            apr_rfc822_date(date_str, valid_to);
413            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
414                         "OCSP response has expired at %s!", date_str);
415            /* Do not send a stale response */
416            ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
417            goto resp_cleanup;
418        }
419    }
420
421    /* What's the actual status? Will be one of
422     * gnutls_ocsp_cert_status_t as defined in gnutls/ocsp.h. */
423    if (cert_status == GNUTLS_OCSP_CERT_GOOD)
424    {
425        /* Yay, everything's good! */
426        ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, s,
427                     "CA flagged certificate as valid at %s.", date_str);
428    }
429    else
430    {
431        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
432                     "CA flagged certificate as %s at %s.",
433                     cert_status == GNUTLS_OCSP_CERT_REVOKED ?
434                     "revoked" : "unknown", date_str);
435        ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
436    }
437
438 resp_cleanup:
439    gnutls_ocsp_resp_deinit(resp);
440    return ret;
441}
442
443
444
445/*
446 * Returns the certificate fingerprint, memory is allocated from p.
447 */
448static gnutls_datum_t mgs_get_cert_fingerprint(apr_pool_t *p,
449                                               gnutls_x509_crt_t cert)
450{
451    gnutls_datum_t fingerprint = {NULL, 0};
452    size_t fplen = 0;
453    gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, NULL, &fplen);
454    unsigned char * fp = apr_palloc(p, fplen);
455    gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, fp, &fplen);
456    /* Safe integer type conversion: The types of fingerprint.size
457     * (unsigned int) and fplen (size_t) may have different
458     * lengths. */
459#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
460    if (__builtin_expect(fplen <= UINT_MAX, 1))
461    {
462        fingerprint.size = (unsigned int) fplen;
463        fingerprint.data = fp;
464    }
465#else
466    if (__builtin_add_overflow(fplen, 0, &fingerprint.size))
467        fingerprint.size = 0;
468    else
469        fingerprint.data = fp;
470#endif
471    return fingerprint;
472}
473
474
475
476static apr_status_t do_ocsp_request(apr_pool_t *p, server_rec *s,
477                                    apr_uri_t *uri,
478                                    gnutls_datum_t *request,
479                                    gnutls_datum_t *response)
480    __attribute__((nonnull));
481static apr_status_t do_ocsp_request(apr_pool_t *p, server_rec *s,
482                                    apr_uri_t *uri,
483                                    gnutls_datum_t *request,
484                                    gnutls_datum_t *response)
485{
486    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
487        ap_get_module_config(s->module_config, &gnutls_module);
488
489    if (apr_strnatcmp(uri->scheme, "http"))
490    {
491        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
492                     "Scheme \"%s\" is not supported for OCSP requests!",
493                     uri->scheme);
494        return APR_EINVAL;
495    }
496
497    const char* header = http_post_header(p, uri,
498                                          OCSP_REQ_TYPE, OCSP_RESP_TYPE,
499                                          request->size);
500    ap_log_error(APLOG_MARK, APLOG_TRACE2, APR_SUCCESS, s,
501                 "OCSP POST header: %s", header);
502
503    /* Find correct port */
504    apr_port_t port = uri->port ?
505        uri->port : apr_uri_port_of_scheme(uri->scheme);
506
507    apr_sockaddr_t *sa;
508    apr_status_t rv = apr_sockaddr_info_get(&sa, uri->hostname,
509                                            APR_UNSPEC, port, 0, p);
510    if (rv != APR_SUCCESS)
511    {
512        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
513                     "Address resolution for OCSP responder %s failed.",
514                     uri->hostinfo);
515    }
516
517    /* There may be multiple answers, try them in order until one
518     * works. */
519    apr_socket_t *sock;
520    while (sa)
521    {
522        rv = apr_socket_create(&sock, sa->family, SOCK_STREAM,
523                               APR_PROTO_TCP, p);
524        if (rv == APR_SUCCESS)
525        {
526            apr_socket_timeout_set(sock, sc->ocsp_socket_timeout);
527            rv = apr_socket_connect(sock, sa);
528            if (rv == APR_SUCCESS)
529                /* Connected! */
530                break;
531            apr_socket_close(sock);
532        }
533        sa = sa->next;
534    }
535    /* If the socket is connected, 'sa' points at the matching
536     * address. */
537    if (sa == NULL)
538    {
539        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
540                     "Connecting to OCSP responder %s failed.",
541                     uri->hostinfo);
542        return rv;
543    }
544
545    /* Header is generated locally, so strlen() is safe. */
546    rv = sock_send_buf(sock, header, strlen(header));
547    if (rv == APR_SUCCESS)
548        rv = sock_send_buf(sock, (char*) request->data, request->size);
549    /* catches errors from both header and request */
550    if (rv != APR_SUCCESS)
551    {
552        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
553                     "Sending OCSP request failed.");
554        goto exit;
555    }
556
557    /* Prepare bucket brigades to read the response header. BBs make
558     * it easy to split the header into lines. */
559    apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
560    apr_bucket_brigade *bb = apr_brigade_create(p, ba);
561    /* will carry split response headers */
562    apr_bucket_brigade *rh = apr_brigade_create(p, ba);
563
564    APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_socket_create(sock, ba));
565    /* The first line in the response header must be the status, check
566     * for OK status code. Line looks similar to "HTTP/1.0 200 OK". */
567    const char *h = read_line(p, bb, rh);
568    const char *code = 0;
569    if (h == NULL
570        || strncmp(h, "HTTP/", 5)
571        || (code = ap_strchr(h, ' ')) == NULL
572        || apr_atoi64(code + 1) != HTTP_OK)
573    {
574        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
575                     "Invalid HTTP response status from %s: %s",
576                     uri->hostinfo, h);
577        rv = APR_ECONNRESET;
578        goto exit;
579    }
580    /* Read remaining header lines */
581    for (h = read_line(p, bb, rh); h != NULL && apr_strnatcmp(h, "") != 0;
582         h = read_line(p, bb, rh))
583    {
584        ap_log_error(APLOG_MARK, APLOG_TRACE2, APR_SUCCESS, s,
585                     "Received header: %s", h);
586    }
587    /* The last header line should be empty (""), NULL indicates an
588     * error. */
589    if (h == NULL)
590    {
591        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
592                     "Error while reading HTTP response header from %s",
593                     uri->hostinfo);
594        rv = APR_ECONNRESET;
595        goto exit;
596    }
597
598    /* Headers have been consumed, the rest of the available data
599     * should be the actual response. */
600    apr_size_t len = OCSP_RESP_SIZE_MAX;
601    char buf[OCSP_RESP_SIZE_MAX];
602    /* apr_brigade_pflatten() can allocate directly from the pool, but
603     * the documentation does not describe a way to limit the size of
604     * the buffer, which is necessary here to prevent DoS by endless
605     * response. Use apr_brigade_flatten() to read to a stack pool,
606     * then create a copy to return. */
607    rv = apr_brigade_flatten(bb, buf, &len);
608    if (rv != APR_SUCCESS)
609    {
610        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
611                     "Failed to read OCSP response.");
612        goto exit;
613    }
614
615    /* With the length restriction this really should not overflow. */
616#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
617    if (__builtin_expect(len > UINT_MAX, 0))
618#else
619    if (__builtin_add_overflow(len, 0, &response->size))
620#endif
621    {
622        response->data = NULL;
623        rv = APR_ENOMEM;
624    }
625    else
626    {
627#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
628        response->size = (unsigned int) len;
629#endif
630        response->data = apr_pmemdup(p, buf, len);
631    }
632
633 exit:
634    apr_socket_close(sock);
635    return rv;
636}
637
638
639
640/**
641 * Get a fresh OCSP response and put it into the cache.
642 *
643 * @param s server that needs a new response
644 *
645 * @param req_data struct describing the certificate for which to
646 * cache a response
647 *
648 * @param cache_expiry If not `NULL`, this `apr_time_t` will be set to
649 * the expiration time of the cache entry. Remains unchanged on
650 * failure.
651 *
652 * @return APR_SUCCESS or an APR error code
653 */
654static apr_status_t mgs_cache_ocsp_response(server_rec *s,
655                                            struct mgs_ocsp_data *req_data,
656                                            apr_time_t *cache_expiry)
657{
658    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
659        ap_get_module_config(s->module_config, &gnutls_module);
660
661    if (sc->ocsp_cache == NULL)
662    {
663        /* OCSP caching requires a cache. */
664        return APR_ENOTIMPL;
665    }
666
667    apr_pool_t *tmp;
668    apr_status_t rv = apr_pool_create(&tmp, NULL);
669    if (rv != APR_SUCCESS)
670    {
671        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
672                     "could not create temporary pool for %s",
673                     __func__);
674        return rv;
675    }
676
677    gnutls_datum_t resp;
678    gnutls_datum_t nonce = { NULL, 0 };
679
680    if (sc->ocsp_response_file != NULL)
681    {
682        ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, s,
683                     "Loading OCSP response from %s",
684                     sc->ocsp_response_file);
685        rv = datum_from_file(tmp, sc->ocsp_response_file, &resp);
686        if (rv != APR_SUCCESS)
687        {
688            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
689                         "Loading OCSP response from %s failed!",
690                         sc->ocsp_response_file);
691            apr_pool_destroy(tmp);
692            return rv;
693        }
694    }
695    else
696    {
697        gnutls_datum_t req;
698        int ret = mgs_create_ocsp_request(s, req_data, &req, &nonce);
699        if (ret == GNUTLS_E_SUCCESS)
700        {
701            ap_log_error(APLOG_MARK, APLOG_TRACE2, APR_SUCCESS, s,
702                         "created OCSP request for %s:%d: %s",
703                         s->server_hostname, s->addrs->host_port,
704                         apr_pescape_hex(tmp, req.data, req.size, 0));
705        }
706        else
707        {
708            gnutls_free(req.data);
709            gnutls_free(nonce.data);
710            apr_pool_destroy(tmp);
711            return APR_EGENERAL;
712        }
713
714        rv = do_ocsp_request(tmp, s, req_data->uri, &req, &resp);
715        gnutls_free(req.data);
716        if (rv != APR_SUCCESS)
717        {
718            /* do_ocsp_request() does its own error logging. */
719            gnutls_free(nonce.data);
720            apr_pool_destroy(tmp);
721            return rv;
722        }
723    }
724
725    apr_time_t next_update;
726    if (check_ocsp_response(s, req_data, &resp, &next_update,
727                            nonce.size ? &nonce : NULL)
728        != GNUTLS_E_SUCCESS)
729    {
730        ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_EGENERAL, s,
731                     "OCSP response validation failed, cannot "
732                     "update cache.");
733        apr_pool_destroy(tmp);
734        gnutls_free(nonce.data);
735        return APR_EGENERAL;
736    }
737    gnutls_free(nonce.data);
738
739    apr_time_t expiry = apr_time_now() + sc->ocsp_cache_time;
740    /* Make sure that a response is not cached beyond its nextUpdate
741     * time. If the variable next_update is zero, the response does
742     * not contain a nextUpdate field. */
743    if (next_update != 0 && next_update < expiry)
744    {
745        char date_str[APR_RFC822_DATE_LEN];
746        apr_rfc822_date(date_str, next_update);
747        ap_log_error(APLOG_MARK, APLOG_WARNING, APR_EGENERAL, s,
748                     "OCSP response timeout restricted to nextUpdate time %s. "
749                     "Check if GnuTLSOCSPCacheTimeout is appropriate.",
750                     date_str);
751        expiry = next_update;
752    }
753
754    int r = mgs_cache_store(sc->ocsp_cache, s,
755                            req_data->fingerprint, resp, expiry);
756    /* destroy pool, and original copy of the OCSP response with it */
757    apr_pool_destroy(tmp);
758    if (r != 0)
759    {
760        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
761                      "Storing OCSP response in cache failed.");
762        return APR_EGENERAL;
763    }
764
765    if (cache_expiry != NULL)
766        *cache_expiry = expiry;
767    return APR_SUCCESS;
768}
769
770
771
772/**
773 * Retries after failed OCSP requests must be rate limited. If the
774 * responder is overloaded or buggy we don't want to add too much more
775 * load, and if a MITM is messing with requests a repetition loop
776 * might end up being a self-inflicted denial of service. This
777 * function writes a specially formed entry to the cache to indicate a
778 * recent failure.
779 *
780 * @param s the server for which an OCSP request failed
781 *
782 * @param req_data OCSP data structure for the certificate that could
783 * not be checked
784 *
785 * @param timeout lifetime of the cache entry
786 */
787static void mgs_cache_ocsp_failure(server_rec *s,
788                                   struct mgs_ocsp_data *req_data,
789                                   apr_interval_time_t timeout)
790{
791    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
792        ap_get_module_config(s->module_config, &gnutls_module);
793
794    unsigned char c = OCSP_FAILURE_CACHE_DATA;
795    gnutls_datum_t dummy = {
796        .data = &c,
797        .size = sizeof(c)
798    };
799    apr_time_t expiry = apr_time_now() + timeout;
800
801    int r = mgs_cache_store(sc->ocsp_cache, s,
802                            req_data->fingerprint, dummy, expiry);
803    if (r != 0)
804        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
805                     "Caching OCSP failure failed.");
806}
807
808
809
810int mgs_get_ocsp_response(mgs_handle_t *ctxt,
811                          struct mgs_ocsp_data *req_data,
812                          gnutls_datum_t *ocsp_response)
813{
814    mgs_srvconf_rec *sc = ctxt->sc;
815
816    if (!sc->ocsp_staple || sc->ocsp_cache == NULL)
817    {
818        /* OCSP must be enabled and caching requires a cache. */
819        return GNUTLS_E_NO_CERTIFICATE_STATUS;
820    }
821
822    // TODO: Large allocation, and the pool system doesn't offer realloc
823    ocsp_response->data = apr_palloc(ctxt->c->pool, OCSP_RESP_SIZE_MAX);
824    ocsp_response->size = OCSP_RESP_SIZE_MAX;
825
826    apr_status_t rv = mgs_cache_fetch(sc->ocsp_cache,
827                                      ctxt->c->base_server,
828                                      req_data->fingerprint,
829                                      ocsp_response,
830                                      ctxt->c->pool);
831    if (rv != APR_SUCCESS)
832    {
833        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_EGENERAL, ctxt->c,
834                      "Fetching OCSP response from cache failed.");
835    }
836    else if (IS_FAILURE_RESPONSE(ocsp_response))
837    {
838        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_EGENERAL, ctxt->c,
839                      "Cached OCSP failure found for %s.",
840                      ctxt->c->base_server->server_hostname);
841        goto fail_cleanup;
842    }
843    else
844    {
845        return GNUTLS_E_SUCCESS;
846    }
847    /* keep response buffer, reset size for reuse */
848    ocsp_response->size = OCSP_RESP_SIZE_MAX;
849
850    /* If the cache had no response or an invalid one, try to update. */
851    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ctxt->c,
852                  "No valid OCSP response in cache, trying to update.");
853
854    rv = apr_global_mutex_trylock(sc->ocsp_mutex);
855    if (APR_STATUS_IS_EBUSY(rv))
856    {
857        /* Another thread is currently holding the mutex, wait. */
858        apr_global_mutex_lock(sc->ocsp_mutex);
859        /* Check if this other thread updated the response we need. It
860         * would be better to have a vhost specific mutex, but at the
861         * moment there's no good way to integrate that with the
862         * Apache Mutex directive. */
863        rv = mgs_cache_fetch(sc->ocsp_cache,
864                             ctxt->c->base_server,
865                             req_data->fingerprint,
866                             ocsp_response,
867                             ctxt->c->pool);
868        if (rv == APR_SUCCESS)
869        {
870            apr_global_mutex_unlock(sc->ocsp_mutex);
871            /* Check if the response is valid. */
872            if (IS_FAILURE_RESPONSE(ocsp_response))
873            {
874                ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_EGENERAL, ctxt->c,
875                              "Cached OCSP failure found for %s.",
876                              ctxt->c->base_server->server_hostname);
877                goto fail_cleanup;
878            }
879            else
880                return GNUTLS_E_SUCCESS;
881        }
882        else
883        {
884            /* keep response buffer, reset size for reuse */
885            ocsp_response->size = OCSP_RESP_SIZE_MAX;
886        }
887    }
888
889    rv = mgs_cache_ocsp_response(ctxt->c->base_server, req_data, NULL);
890    if (rv != APR_SUCCESS)
891    {
892        ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, ctxt->c,
893                      "Caching a fresh OCSP response failed");
894        /* cache failure to rate limit retries */
895        mgs_cache_ocsp_failure(ctxt->c->base_server,
896                               req_data,
897                               sc->ocsp_failure_timeout);
898        apr_global_mutex_unlock(sc->ocsp_mutex);
899        goto fail_cleanup;
900    }
901    apr_global_mutex_unlock(sc->ocsp_mutex);
902
903    /* retry reading from cache */
904    rv = mgs_cache_fetch(sc->ocsp_cache,
905                         ctxt->c->base_server,
906                         req_data->fingerprint,
907                         ocsp_response,
908                         ctxt->c->pool);
909    if (rv != APR_SUCCESS)
910    {
911        ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, ctxt->c,
912                      "Fetching OCSP response from cache failed on retry.");
913    }
914    else
915    {
916        return GNUTLS_E_SUCCESS;
917    }
918
919    /* failure, reset struct, buffer will be released with the
920     * connection pool */
921 fail_cleanup:
922    ocsp_response->size = 0;
923    ocsp_response->data = NULL;
924    return GNUTLS_E_NO_CERTIFICATE_STATUS;
925}
926
927
928
929int mgs_create_ocsp_trust_list(gnutls_x509_trust_list_t *tl,
930                               const gnutls_x509_crt_t *chain,
931                               const int num)
932{
933    int added = 0;
934    int ret = gnutls_x509_trust_list_init(tl, num);
935
936    if (ret == GNUTLS_E_SUCCESS)
937        added = gnutls_x509_trust_list_add_cas(*tl, chain, num, 0);
938
939    if (added != num)
940        ret = GNUTLS_E_CERTIFICATE_ERROR;
941
942    /* Clean up trust list in case of error */
943    if (ret != GNUTLS_E_SUCCESS)
944        gnutls_x509_trust_list_deinit(*tl, 0);
945
946    return ret;
947}
948
949
950
951apr_status_t mgs_cleanup_trust_list(void *data)
952{
953    gnutls_x509_trust_list_t *tl = (gnutls_x509_trust_list_t *) data;
954    gnutls_x509_trust_list_deinit(*tl, 0);
955    return APR_SUCCESS;
956}
957
958
959
960apr_uri_t * mgs_cert_get_ocsp_uri(apr_pool_t *p, gnutls_x509_crt_t cert)
961{
962    apr_pool_t *tmp;
963    apr_status_t rv = apr_pool_create(&tmp, p);
964    if (rv != APR_SUCCESS)
965        return NULL;
966
967    apr_uri_t *ocsp_uri = NULL;
968
969    int ret = GNUTLS_E_SUCCESS;
970    /* search authority info access for OCSP URI */
971    for (int seq = 0; ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; seq++)
972    {
973        gnutls_datum_t ocsp_access_data;
974        ret = gnutls_x509_crt_get_authority_info_access(cert, seq,
975                                                        GNUTLS_IA_OCSP_URI,
976                                                        &ocsp_access_data,
977                                                        NULL);
978        if (ret == GNUTLS_E_SUCCESS)
979        {
980            /* create NULL terminated string */
981            char *ocsp_str =
982                apr_pstrndup(tmp, (const char*) ocsp_access_data.data,
983                             ocsp_access_data.size);
984            gnutls_free(ocsp_access_data.data);
985
986            ocsp_uri = apr_palloc(p, sizeof(apr_uri_t));
987            rv = apr_uri_parse(p, ocsp_str, ocsp_uri);
988            if (rv == APR_SUCCESS)
989                break;
990            else
991                ocsp_uri = NULL;
992        }
993    }
994
995    apr_pool_destroy(tmp);
996    return ocsp_uri;
997}
998
999
1000
1001/** The maximum random fuzz base (half the maximum fuzz) that will not
1002 * overflow. The permitted values are limited to whatever will not
1003 * make an `apr_interval_time_t` variable overflow when multiplied
1004 * with `APR_UINT16_MAX`. With apr_interval_time_t being a 64 bit
1005 * signed integer the maximum fuzz interval is about 4.5 years, which
1006 * should be more than plenty. */
1007#define MAX_FUZZ_BASE (APR_INT64_MAX / APR_UINT16_MAX)
1008
1009/**
1010 * Perform an asynchronous OCSP cache update. This is a callback for
1011 * mod_watchdog, so the API is fixed.
1012 *
1013 * @param state watchdog state (starting/running/stopping)
1014 * @param data callback data, contains the server_rec
1015 * @param pool temporary callback pool destroyed after the call
1016 * @return always `APR_SUCCESS` as required by the mod_watchdog API to
1017 * indicate that the callback should be called again
1018 */
1019static apr_status_t mgs_async_ocsp_update(int state,
1020                                          void *data,
1021                                          apr_pool_t *pool)
1022{
1023    /* If the server is stopping there's no need to do an OCSP
1024     * update. */
1025    if (state == AP_WATCHDOG_STATE_STOPPING)
1026        return APR_SUCCESS;
1027
1028    server_rec *server = (server_rec *) data;
1029    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
1030        ap_get_module_config(server->module_config, &gnutls_module);
1031    apr_time_t expiry = 0;
1032
1033    /* Holding the mutex should help avoiding simultaneous synchronous
1034     * and asynchronous OCSP requests in some edge cases: during
1035     * startup if there's an early request, and if OCSP requests fail
1036     * repeatedly until the cached response expires and a synchronous
1037     * update is triggered before a failure cache entry is
1038     * created. Usually there should be a good OCSP response in the
1039     * cache and the mutex is never touched in
1040     * mgs_get_ocsp_response. */
1041    apr_global_mutex_lock(sc->ocsp_mutex);
1042    apr_status_t rv = mgs_cache_ocsp_response(server, sc->ocsp, &expiry);
1043
1044    apr_interval_time_t next_interval;
1045    if (rv != APR_SUCCESS)
1046        next_interval = sc->ocsp_failure_timeout;
1047    else
1048    {
1049        apr_uint16_t random_bytes;
1050        int res = gnutls_rnd(GNUTLS_RND_NONCE, &random_bytes,
1051                             sizeof(random_bytes));
1052        if (__builtin_expect(res < 0, 0))
1053        {
1054            /* Shouldn't ever happen, because a working random number
1055             * generator is required for establishing TLS sessions. */
1056            random_bytes = (apr_uint16_t) apr_time_now();
1057            ap_log_error(APLOG_MARK, APLOG_WARNING, APR_EGENERAL, server,
1058                         "Error getting random number for fuzzy update "
1059                         "interval: %s Falling back on truncated time.",
1060                         gnutls_strerror(res));
1061        }
1062
1063        /* Choose the fuzz interval for the next update between
1064         * `sc->ocsp_fuzz_time` and twice that. */
1065        apr_interval_time_t fuzz = sc->ocsp_fuzz_time
1066            + (sc->ocsp_fuzz_time * random_bytes / APR_UINT16_MAX);
1067
1068        /* With an extremly short timeout or weird nextUpdate value
1069         * next_interval <= 0 might happen. Use the failure timeout to
1070         * avoid endlessly repeating updates. */
1071        next_interval = expiry - apr_time_now();
1072        if (next_interval <= 0)
1073        {
1074            next_interval = sc->ocsp_failure_timeout;
1075            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server,
1076                         "OCSP cache expiration time of the response for "
1077                         "%s:%d is in the past, repeating after failure "
1078                         "timeout (GnuTLSOCSPFailureTimeout).",
1079                         server->server_hostname, server->addrs->host_port);
1080        }
1081
1082        /* It's possible to compare maximum fuzz and configured OCSP
1083         * cache timeout at configuration time, but the interval until
1084         * the nextUpdate value expires (or the failure timeout
1085         * fallback above) might be shorter. Make sure that we don't
1086         * end up with a negative interval. */
1087        while (fuzz > next_interval)
1088            fuzz /= 2;
1089        next_interval -= fuzz;
1090    }
1091
1092    sc->singleton_wd->set_callback_interval(sc->singleton_wd->wd,
1093                                            next_interval,
1094                                            server, mgs_async_ocsp_update);
1095
1096    ap_log_error(APLOG_MARK, rv == APR_SUCCESS ? APLOG_DEBUG : APLOG_WARNING,
1097                 rv, server,
1098                 "Async OCSP update %s for %s:%d, next update in "
1099                 "%" APR_TIME_T_FMT " seconds.",
1100                 rv == APR_SUCCESS ? "done" : "failed",
1101                 server->server_hostname, server->addrs->host_port,
1102                 apr_time_sec(next_interval));
1103
1104    /* Check if there's still a response in the cache. If not, add a
1105     * failure entry. If there already is a failure entry, refresh
1106     * it. The lifetime of such entries is twice the error timeout to
1107     * make sure they do not expire before the next scheduled
1108     * update. */
1109    if (rv != APR_SUCCESS)
1110    {
1111        gnutls_datum_t ocsp_response;
1112        ocsp_response.data = apr_palloc(pool, OCSP_RESP_SIZE_MAX);
1113        ocsp_response.size = OCSP_RESP_SIZE_MAX;
1114
1115        apr_status_t rv = mgs_cache_fetch(sc->ocsp_cache, server,
1116                                          sc->ocsp->fingerprint,
1117                                          &ocsp_response,
1118                                          pool);
1119
1120        if (rv != APR_SUCCESS || (IS_FAILURE_RESPONSE(&ocsp_response)))
1121        {
1122            ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, server,
1123                         "Caching OCSP request failure for %s:%d.",
1124                         server->server_hostname, server->addrs->host_port);
1125            mgs_cache_ocsp_failure(server, sc->ocsp,
1126                                   sc->ocsp_failure_timeout * 2);
1127        }
1128    }
1129    apr_global_mutex_unlock(sc->ocsp_mutex);
1130
1131    return APR_SUCCESS;
1132}
1133
1134
1135
1136const char* mgs_ocsp_configure_stapling(apr_pool_t *pconf,
1137                                        apr_pool_t *ptemp __attribute__((unused)),
1138                                        server_rec *server)
1139{
1140    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
1141        ap_get_module_config(server->module_config, &gnutls_module);
1142
1143    if (sc->ocsp_cache == NULL)
1144        return "No OCSP response cache available, please check "
1145            "the GnuTLSOCSPCache setting.";
1146
1147    if (sc->certs_x509_chain_num < 2)
1148        return "No issuer (CA) certificate available, cannot enable "
1149            "stapling. Please add it to the GnuTLSCertificateFile.";
1150
1151    mgs_ocsp_data_t ocsp = apr_palloc(pconf, sizeof(struct mgs_ocsp_data));
1152
1153    ocsp->cert = sc->certs_x509_crt_chain[0];
1154
1155    ocsp->uri = mgs_cert_get_ocsp_uri(pconf, ocsp->cert);
1156    if (ocsp->uri == NULL && sc->ocsp_response_file == NULL)
1157        return "No OCSP URI in the certificate nor a GnuTLSOCSPResponseFile "
1158            "setting, cannot configure OCSP stapling.";
1159
1160    ocsp->fingerprint =
1161        mgs_get_cert_fingerprint(pconf, sc->certs_x509_crt_chain[0]);
1162    if (ocsp->fingerprint.data == NULL)
1163        return "Could not read fingerprint from certificate!";
1164
1165    ocsp->trust = apr_palloc(pconf,
1166                             sizeof(gnutls_x509_trust_list_t));
1167    /* Only the direct issuer may sign the OCSP response or an OCSP
1168     * signer. */
1169    int ret = mgs_create_ocsp_trust_list(ocsp->trust,
1170                                         &(sc->certs_x509_crt_chain[1]),
1171                                         1);
1172    if (ret != GNUTLS_E_SUCCESS)
1173    {
1174        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, server,
1175                     "Could not create OCSP trust list: %s (%d)",
1176                     gnutls_strerror(ret), ret);
1177        return "Could not build trust list for OCSP stapling!";
1178    }
1179    /* deinit trust list when the config pool is destroyed */
1180    apr_pool_cleanup_register(pconf, ocsp->trust,
1181                              mgs_cleanup_trust_list,
1182                              apr_pool_cleanup_null);
1183
1184    sc->ocsp = ocsp;
1185    return NULL;
1186}
1187
1188
1189
1190/*
1191 * Like in the general post_config hook the HTTP status codes for
1192 * errors are just for fun. What matters is "neither OK nor DECLINED"
1193 * to denote an error.
1194 */
1195int mgs_ocsp_enable_stapling(apr_pool_t *pconf __attribute__((unused)),
1196                             apr_pool_t *ptemp __attribute__((unused)),
1197                             server_rec *server)
1198{
1199    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
1200        ap_get_module_config(server->module_config, &gnutls_module);
1201    if (sc->ocsp == NULL)
1202    {
1203        ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EGENERAL, server,
1204                     "CRITICAL ERROR: %s called with uninitialized OCSP "
1205                     "data structure. This indicates a bug in mod_gnutls.",
1206                     __func__);
1207        return HTTP_INTERNAL_SERVER_ERROR;
1208    }
1209
1210    /* set default values for unset parameters */
1211    if (sc->ocsp_auto_refresh == GNUTLS_ENABLED_UNSET)
1212        sc->ocsp_auto_refresh = GNUTLS_ENABLED_TRUE;
1213    if (sc->ocsp_check_nonce == GNUTLS_ENABLED_UNSET)
1214        sc->ocsp_check_nonce = GNUTLS_ENABLED_TRUE;
1215    if (sc->ocsp_cache_time == MGS_TIMEOUT_UNSET)
1216        sc->ocsp_cache_time = apr_time_from_sec(MGS_OCSP_CACHE_TIMEOUT);
1217    if (sc->ocsp_failure_timeout == MGS_TIMEOUT_UNSET)
1218        sc->ocsp_failure_timeout = apr_time_from_sec(MGS_OCSP_FAILURE_TIMEOUT);
1219    if (sc->ocsp_socket_timeout == MGS_TIMEOUT_UNSET)
1220        sc->ocsp_socket_timeout = apr_time_from_sec(MGS_OCSP_SOCKET_TIMEOUT);
1221    /* Base fuzz is half the configured maximum, the actual fuzz is
1222     * between the maximum and half that. The default maximum is
1223     * sc->ocsp_cache_time / 8, or twice the failure timeout,
1224     * whichever is larger (so the default guarantees at least one
1225     * retry before the cache entry expires).*/
1226    if (sc->ocsp_fuzz_time == MGS_TIMEOUT_UNSET)
1227    {
1228        sc->ocsp_fuzz_time = sc->ocsp_cache_time / 16;
1229        if (sc->ocsp_fuzz_time < sc->ocsp_failure_timeout)
1230            sc->ocsp_fuzz_time = sc->ocsp_failure_timeout;
1231    }
1232    else
1233        sc->ocsp_fuzz_time = sc->ocsp_fuzz_time / 2;
1234
1235    /* This really shouldn't happen considering MAX_FUZZ_BASE is about
1236     * 4.5 years, but better safe than sorry. */
1237    if (sc->ocsp_fuzz_time > MAX_FUZZ_BASE)
1238    {
1239        ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EINVAL, server,
1240                     "%s: Maximum fuzz time is too large, maximum "
1241                     "supported value is %" APR_INT64_T_FMT " seconds",
1242                     __func__, apr_time_sec(MAX_FUZZ_BASE) * 2);
1243        return HTTP_INTERNAL_SERVER_ERROR;
1244    }
1245
1246    /* The watchdog structure may be NULL if mod_watchdog is
1247     * unavailable. */
1248    if (sc->singleton_wd != NULL
1249        && sc->ocsp_auto_refresh == GNUTLS_ENABLED_TRUE)
1250    {
1251        apr_status_t rv =
1252            sc->singleton_wd->register_callback(sc->singleton_wd->wd,
1253                                                sc->ocsp_cache_time,
1254                                                server, mgs_async_ocsp_update);
1255        if (rv == APR_SUCCESS)
1256            ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
1257                         "Enabled async OCSP update via watchdog "
1258                         "for %s:%d",
1259                         server->server_hostname, server->addrs->host_port);
1260        else
1261            ap_log_error(APLOG_MARK, APLOG_WARNING, rv, server,
1262                         "Enabling async OCSP update via watchdog "
1263                         "for %s:%d failed!",
1264                         server->server_hostname, server->addrs->host_port);
1265    }
1266
1267    return OK;
1268}
Note: See TracBrowser for help on using the repository browser.