source: mod_gnutls/src/gnutls_ocsp.c @ eee1432

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

Check OCSP response nonce

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