source: mod_gnutls/src/gnutls_ocsp.c @ ef06c74

debian/masterdebian/stretch-backportsproxy-ticketupstream
Last change on this file since ef06c74 was ef06c74, checked in by Thomas Klute <thomas2.klute@…>, 4 years ago

Compatibility code for GCC version < 5

The builtin_add_overflow() which is used for safe integer type
conversion was introduced with GCC 5, and thus unfortunately is not
available in Debian stable.

The "!defined(clang)" part in the version check is because Clang
3.8 has the builtin, but pretends to be GCC 4 as far as the GNUC
macro is concerned.

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