source: mod_gnutls/src/gnutls_ocsp.c @ f233a23

debian/masterproxy-ticket
Last change on this file since f233a23 was f233a23, checked in by Fiona Klute <fiona.klute@…>, 2 years ago

Logic for fuzzy OCSP update timing

If a server has a lot of virtual hosts using OCSP stapling with
identical OCSP cache lifetime settings (e.g. the defaults), this will
spread update intervals so requests don't happen all at once.

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