source: mod_gnutls/src/gnutls_ocsp.c @ 103cafa

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

Remove extra "OCSP failed" log entry while writing failure to cache

Both synchronous and asynchronous OCSP requests write their own
failure log messages, and the "next try" time doesn't make sense with
asynchronous updates, because they run on time regardless of cache
entries.

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