source: mod_gnutls/src/gnutls_ocsp.c @ 3c123cd

debian/masterdebian/stretch-backportsupstream
Last change on this file since 3c123cd was 3c123cd, checked in by Fiona Klute <fiona.klute@…>, 19 months ago

Update my name, prepare changelog for the next release

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