source: mod_gnutls/src/gnutls_ocsp.c @ 61e802c

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

Simplify mgs_async_ocsp_update

Always use OCSP mutex for updates, update comment, rename server_rec*
for readability.

  • Property mode set to 100644
File size: 36.9 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 *server = (server_rec *) data;
950    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
951        ap_get_module_config(server->module_config, &gnutls_module);
952    apr_time_t expiry = 0;
953
954    /* Holding the mutex should help avoiding simultaneous synchronous
955     * and asynchronous OCSP requests in some edge cases: during
956     * startup if there's an early request, and if OCSP requests fail
957     * repeatedly until the cached response expires and a synchronous
958     * update is triggered before a failure cache entry is
959     * created. Usually there should be a good OCSP response in the
960     * cache and the mutex is never touched in
961     * mgs_get_ocsp_response. */
962    apr_global_mutex_lock(sc->ocsp_mutex);
963    apr_status_t rv = mgs_cache_ocsp_response(server, &expiry);
964
965    /* TODO: fuzzy interval */
966    apr_interval_time_t next_interval = expiry - apr_time_now();
967    if (rv != APR_SUCCESS)
968        next_interval = sc->ocsp_failure_timeout;
969    sc->singleton_wd->set_callback_interval(sc->singleton_wd->wd,
970                                            next_interval,
971                                            server, mgs_async_ocsp_update);
972
973    ap_log_error(APLOG_MARK, rv == APR_SUCCESS ? APLOG_DEBUG : APLOG_WARNING,
974                 rv, server,
975                 "Async OCSP update %s for %s:%d, next update in "
976                 "%" APR_TIME_T_FMT " seconds.",
977                 rv == APR_SUCCESS ? "done" : "failed",
978                 server->server_hostname, server->addrs->host_port,
979                 apr_time_sec(next_interval));
980
981    apr_global_mutex_unlock(sc->ocsp_mutex);
982
983    return APR_SUCCESS;
984}
985
986
987
988/*
989 * Like in the general post_config hook the HTTP status codes for
990 * errors are just for fun. What matters is "neither OK nor DECLINED"
991 * to denote an error.
992 */
993int mgs_ocsp_post_config_server(apr_pool_t *pconf,
994                                apr_pool_t *ptemp __attribute__((unused)),
995                                server_rec *server)
996{
997    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
998        ap_get_module_config(server->module_config, &gnutls_module);
999
1000    if (sc->certs_x509_chain_num < 2)
1001    {
1002        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, server,
1003                     "OCSP stapling is enabled but no CA certificate "
1004                     "available for %s:%d, make sure it is included in "
1005                     "GnuTLSCertificateFile!",
1006                     server->server_hostname, server->addrs->host_port);
1007        return HTTP_NOT_FOUND;
1008    }
1009
1010    /* set default values for unset parameters */
1011    if (sc->ocsp_check_nonce == GNUTLS_ENABLED_UNSET)
1012        sc->ocsp_check_nonce = GNUTLS_ENABLED_TRUE;
1013    if (sc->ocsp_cache_time == MGS_TIMEOUT_UNSET)
1014        sc->ocsp_cache_time = apr_time_from_sec(MGS_OCSP_CACHE_TIMEOUT);
1015    if (sc->ocsp_failure_timeout == MGS_TIMEOUT_UNSET)
1016        sc->ocsp_failure_timeout = apr_time_from_sec(MGS_OCSP_FAILURE_TIMEOUT);
1017    if (sc->ocsp_socket_timeout == MGS_TIMEOUT_UNSET)
1018        sc->ocsp_socket_timeout = apr_time_from_sec(MGS_OCSP_SOCKET_TIMEOUT);
1019
1020    sc->ocsp = apr_palloc(pconf, sizeof(struct mgs_ocsp_data));
1021
1022    sc->ocsp->fingerprint =
1023        mgs_get_cert_fingerprint(pconf, sc->certs_x509_crt_chain[0]);
1024    if (sc->ocsp->fingerprint.data == NULL)
1025        return HTTP_INTERNAL_SERVER_ERROR;
1026
1027    sc->ocsp->uri = mgs_cert_get_ocsp_uri(pconf,
1028                                          sc->certs_x509_crt_chain[0]);
1029    if (sc->ocsp->uri == NULL && sc->ocsp_response_file == NULL)
1030    {
1031        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, server,
1032                     "OCSP stapling is enabled for for %s:%d, but there is "
1033                     "neither an OCSP URI in the certificate nor a "
1034                     "GnuTLSOCSPResponseFile setting for this host!",
1035                     server->server_hostname, server->addrs->host_port);
1036        return HTTP_NOT_FOUND;
1037    }
1038
1039    sc->ocsp->trust = apr_palloc(pconf,
1040                                 sizeof(gnutls_x509_trust_list_t));
1041     /* Only the direct issuer may sign the OCSP response or an OCSP
1042      * signer. */
1043    int ret = mgs_create_ocsp_trust_list(sc->ocsp->trust,
1044                                         &(sc->certs_x509_crt_chain[1]),
1045                                         1);
1046    if (ret != GNUTLS_E_SUCCESS)
1047    {
1048        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, server,
1049                     "Could not create OCSP trust list: %s (%d)",
1050                     gnutls_strerror(ret), ret);
1051        return HTTP_INTERNAL_SERVER_ERROR;
1052    }
1053    /* deinit trust list when the config pool is destroyed */
1054    apr_pool_cleanup_register(pconf, sc->ocsp->trust,
1055                              mgs_cleanup_trust_list,
1056                              apr_pool_cleanup_null);
1057
1058    /* enable status request callback */
1059    gnutls_certificate_set_ocsp_status_request_function(sc->certs,
1060                                                        mgs_get_ocsp_response,
1061                                                        sc);
1062
1063    /* The watchdog structure may be NULL if mod_watchdog is
1064     * unavailable. */
1065    if (sc->singleton_wd != NULL)
1066    {
1067        apr_status_t rv =
1068            sc->singleton_wd->register_callback(sc->singleton_wd->wd,
1069                                                sc->ocsp_cache_time,
1070                                                server, mgs_async_ocsp_update);
1071        if (rv == APR_SUCCESS)
1072            ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
1073                         "Enabled async OCSP update via watchdog "
1074                         "for %s:%d",
1075                         server->server_hostname, server->addrs->host_port);
1076        else
1077            ap_log_error(APLOG_MARK, APLOG_WARNING, rv, server,
1078                         "Enabling async OCSP update via watchdog "
1079                         "for %s:%d failed!",
1080                         server->server_hostname, server->addrs->host_port);
1081    }
1082
1083    return OK;
1084}
Note: See TracBrowser for help on using the repository browser.