source: mod_gnutls/src/gnutls_ocsp.c

mod_gnutls/0.12.0
Last change on this file was eb21e89, checked in by Fiona Klute <fiona.klute@…>, 3 months ago

Fix server_rec references in mgs_get_ocsp_response()

During the handshake the base_server of the relevant conn_rec is
always the first vhost matching the host/port combination of the
incoming connection. By the time an OCSP response is requested
mod_gnutls may already have selected another server based on SNI, but
Apache hasn't updated the conn_rec yet. In that case c->base_server
does not refer to the right server, and if that server reference is
used to get the mod_gnutls configuration it'll be the wrong one.

That behavior caused a bug where caching a fresh OCSP response during
handshake failed if the initial vhost had OCSP stapling disabled,
because with stapling disabled the cache lifetime is set to -1. In
other cases a wrong cache lifetime might have been used.

The bug is fixed by using the mod_gnutls server configuration
referenced by the mod_gnutls connection structure, which has already
been updated by the SNI parsing code. It contains a reference to the
correct server_rec.

This commit also contains a regression test.

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