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

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

Macro for the OCSP socket timeout

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