source: mod_gnutls/src/gnutls_ocsp.c @ c39ae1a

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

Initialize OCSP timeouts with an "unset" value

The configuration merge function used the default timeout to check if
an OCSP related timeout has been set in a virtual host
configuration. This would work most of the time, but break in the
corner case of the global configuration setting a non-default timeout
and a virtual host configuration restoring the default. In this
situation the merge would handle the value from the virtual host
configuration as unset and copy the global timeout.

The problem is solved by initializing the timeouts using the new macro
MGS_TIMEOUT_UNSET. Timeouts as used in the mod_gnutls configuration
cannot be negative, so there is ample room for explicitly unset
values. MGS_TIMEOUT_UNSET is also used for the session cache timeout
instead of hard coded -1.

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