source: mod_gnutls/src/gnutls_ocsp.c @ 333bbc7

debian/masterdebian/stretch-backportsupstream
Last change on this file since 333bbc7 was 333bbc7, checked in by Thomas Klute <thomas2.klute@…>, 2 years ago

Configurable OCSP socket timeout

Stalled OCSP requests must time out after a while to prevent stalling
the server too much. However, if the timeout is too short requests may
fail with a slow OCSP responder or high latency network
connection. Using the new GnuTLSOCSPFailureTimeout parameter users can
adjust the timeout if necessary.

All macros defining default values for OCSP related times are now
collected in gnutls_ocsp.h.

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