source: mod_gnutls/src/gnutls_ocsp.c @ 9c456a9

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

OCSP post config: Ensure OCSP URI or response file are set

If the certificate does not contain an OCSP URI and the vhost is not
using a response file mod_gnutls has no way to acquire a response. In
that case post config fails if stapling is enabled.

  • Property mode set to 100644
File size: 30.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_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    if (sc->ocsp->uri == NULL && sc->ocsp_response_file == NULL)
878    {
879        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, server,
880                     "OCSP stapling is enabled for for %s:%d, but there is "
881                     "neither an OCSP URI in the certificate nor a "
882                     "GnuTLSOCSPResponseFile setting for this host!",
883                     server->server_hostname, server->addrs->host_port);
884        return HTTP_NOT_FOUND;
885    }
886
887    sc->ocsp->trust = apr_palloc(pconf,
888                                 sizeof(gnutls_x509_trust_list_t));
889     /* Only the direct issuer may sign the OCSP response or an OCSP
890      * signer. */
891    int ret = mgs_create_ocsp_trust_list(sc->ocsp->trust,
892                                         &(sc->certs_x509_crt_chain[1]),
893                                         1);
894    if (ret != GNUTLS_E_SUCCESS)
895    {
896        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, server,
897                     "Could not create OCSP trust list: %s (%d)",
898                     gnutls_strerror(ret), ret);
899        return HTTP_INTERNAL_SERVER_ERROR;
900    }
901    /* deinit trust list when the config pool is destroyed */
902    apr_pool_cleanup_register(pconf, sc->ocsp->trust,
903                              mgs_cleanup_trust_list,
904                              apr_pool_cleanup_null);
905
906    return OK;
907}
Note: See TracBrowser for help on using the repository browser.