source: mod_gnutls/src/gnutls_ocsp.c @ c67643b

Last change on this file since c67643b was c67643b, checked in by Fiona Klute <fiona.klute@…>, 5 months ago

SHA1 for issuer name hash and issuer key hash in OCSP requests

Some CAs (notably Let's Encrypt) support only SHA1. Support for that
is required by RFC 5019 [1] and referenced in CAB Forum Baseline
Requirements, too. This particular hash doesn't need to be
cryptographically secure, so switching to SHA1 is the simplest
solution.

[1] https://datatracker.ietf.org/doc/html/rfc5019#section-2.1.1

  • Property mode set to 100644
File size: 46.7 KB
Line 
1/*
2 *  Copyright 2016-2020 Fiona Klute
3 *
4 *  Licensed under the Apache License, Version 2.0 (the "License");
5 *  you may not use this file except in compliance with the License.
6 *  You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *  Unless required by applicable law or agreed to in writing, software
11 *  distributed under the License is distributed on an "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 *  See the License for the specific language governing permissions and
14 *  limitations under the License.
15 */
16
17#include "gnutls_ocsp.h"
18#include "mod_gnutls.h"
19#include "gnutls_cache.h"
20#include "gnutls_config.h"
21#include "gnutls_util.h"
22#include "gnutls_watchdog.h"
23
24#include <apr_escape.h>
25#include <apr_lib.h>
26#include <apr_time.h>
27#include <gnutls/crypto.h>
28#include <gnutls/ocsp.h>
29#include <mod_watchdog.h>
30#include <string.h>
31#include <time.h>
32
33#ifdef APLOG_USE_MODULE
34APLOG_USE_MODULE(gnutls);
35#endif
36
37/** maximum supported OCSP response size, 8K should be plenty */
38#define OCSP_RESP_SIZE_MAX (8 * 1024)
39#define OCSP_REQ_TYPE "application/ocsp-request"
40#define OCSP_RESP_TYPE "application/ocsp-response"
41
42/** Dummy data for failure cache entries (one byte). */
43#define OCSP_FAILURE_CACHE_DATA 0x0f
44/** Macro to check if an OCSP reponse pointer contains a cached
45 * failure */
46#define IS_FAILURE_RESPONSE(resp) \
47    (((resp)->size == sizeof(unsigned char)) &&                     \
48     (*((unsigned char *) (resp)->data) == OCSP_FAILURE_CACHE_DATA))
49
50
51#define _log_one_ocsp_fail(str, srv)                                    \
52    ap_log_error(APLOG_MARK, APLOG_INFO, APR_EGENERAL, (srv),           \
53                 "Reason for failed OCSP response verification: %s", (str))
54/**
55 * Log all matching reasons for verification failure
56 */
57static void _log_verify_fail_reason(const unsigned int verify, server_rec *s)
58{
59    if (verify & GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND)
60        _log_one_ocsp_fail("Signer cert not found", s);
61
62    if (verify & GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR)
63        _log_one_ocsp_fail("Signer cert keyusage error", s);
64
65    if (verify & GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER)
66        _log_one_ocsp_fail("Signer cert is not trusted", s);
67
68    if (verify & GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM)
69        _log_one_ocsp_fail("Insecure algorithm", s);
70
71    if (verify & GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE)
72        _log_one_ocsp_fail("Signature failure", s);
73
74    if (verify & GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED)
75        _log_one_ocsp_fail("Signer cert not yet activated", s);
76
77    if (verify & GNUTLS_OCSP_VERIFY_CERT_EXPIRED)
78        _log_one_ocsp_fail("Signer cert expired", s);
79}
80
81
82
83const char *mgs_ocsp_stapling_enable(cmd_parms *parms,
84                                     void *dummy __attribute__((unused)),
85                                     const int arg)
86{
87    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
88        ap_get_module_config(parms->server->module_config, &gnutls_module);
89
90    if (arg)
91        sc->ocsp_staple = GNUTLS_ENABLED_TRUE;
92    else
93        sc->ocsp_staple = GNUTLS_ENABLED_FALSE;
94
95    return NULL;
96}
97
98
99
100const char *mgs_set_ocsp_auto_refresh(cmd_parms *parms,
101                                      void *dummy __attribute__((unused)),
102                                      const int arg)
103{
104    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
105        ap_get_module_config(parms->server->module_config, &gnutls_module);
106
107    if (arg)
108        sc->ocsp_auto_refresh = GNUTLS_ENABLED_TRUE;
109    else
110        sc->ocsp_auto_refresh = GNUTLS_ENABLED_FALSE;
111
112    return NULL;
113}
114
115
116
117const char *mgs_set_ocsp_check_nonce(cmd_parms *parms,
118                                     void *dummy __attribute__((unused)),
119                                     const int arg)
120{
121    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
122        ap_get_module_config(parms->server->module_config, &gnutls_module);
123
124    if (arg)
125        sc->ocsp_check_nonce = GNUTLS_ENABLED_TRUE;
126    else
127        sc->ocsp_check_nonce = GNUTLS_ENABLED_FALSE;
128
129    return NULL;
130}
131
132
133
134const char *mgs_store_ocsp_response_path(cmd_parms *parms,
135                                         void *dummy __attribute__((unused)),
136                                         int argc, char *const *argv)
137{
138    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
139        ap_get_module_config(parms->server->module_config, &gnutls_module);
140
141    sc->ocsp_response_file_num = argc;
142    sc->ocsp_response_file = apr_palloc(parms->pool, sizeof(char *) * argc);
143    for (int i = 0; i < argc; i++)
144    {
145        if (strcmp(argv[i], "") == 0)
146            sc->ocsp_response_file[i] = NULL;
147        else
148            sc->ocsp_response_file[i] =
149                ap_server_root_relative(parms->pool, argv[i]);
150    }
151    return NULL;
152}
153
154
155
156/**
157 * Create an OCSP request for the certificate of the given server. The
158 * DER encoded request is stored in 'req' (must be released with
159 * gnutls_free() when no longer needed), its nonce in 'nonce' (same,
160 * if not NULL).
161 *
162 * @param s server reference for logging
163 *
164 * @return GNUTLS_E_SUCCESS, or a GnuTLS error code.
165 */
166static int mgs_create_ocsp_request(server_rec *s,
167                                   mgs_ocsp_data_t req_data,
168                                   gnutls_datum_t *req,
169                                   gnutls_datum_t *nonce)
170    __attribute__((nonnull(1, 3)));
171static int mgs_create_ocsp_request(server_rec *s,
172                                   mgs_ocsp_data_t req_data,
173                                   gnutls_datum_t *req,
174                                   gnutls_datum_t *nonce)
175{
176    gnutls_ocsp_req_t r;
177    int ret = gnutls_ocsp_req_init(&r);
178    if (ret != GNUTLS_E_SUCCESS)
179    {
180        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
181                     "Could not initialize OCSP request structure: %s (%d)",
182                     gnutls_strerror(ret), ret);
183        return ret;
184    }
185
186    /* issuer is set to a reference, so musn't be cleaned up */
187    gnutls_x509_crt_t issuer;
188    ret = gnutls_x509_trust_list_get_issuer(*req_data->trust, req_data->cert,
189                                            &issuer, 0);
190    if (ret != GNUTLS_E_SUCCESS)
191    {
192        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
193                     "Could not get issuer from trust list: %s (%d)",
194                     gnutls_strerror(ret), ret);
195        gnutls_ocsp_req_deinit(r);
196        return ret;
197    }
198
199    /* Use SHA1 for issuer name hash and issuer key hash, for
200     * compliance with "lightweight" OCSP profile specified in RFC
201     * 5019. */
202    ret = gnutls_ocsp_req_add_cert(r, GNUTLS_DIG_SHA1,
203                                   issuer, req_data->cert);
204
205    if (ret != GNUTLS_E_SUCCESS)
206    {
207        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
208                     "Adding certificate to OCSP request for %s:%d "
209                     "failed: %s (%d)",
210                     s->server_hostname, s->addrs->host_port,
211                     gnutls_strerror(ret), ret);
212        gnutls_ocsp_req_deinit(r);
213        return ret;
214    }
215
216    if (nonce != NULL)
217    {
218        ret = gnutls_ocsp_req_randomize_nonce(r);
219        if (ret != GNUTLS_E_SUCCESS)
220        {
221            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
222                         "OCSP nonce creation failed: %s (%d)",
223                         gnutls_strerror(ret), ret);
224            gnutls_ocsp_req_deinit(r);
225            return ret;
226        }
227
228        ret = gnutls_ocsp_req_get_nonce(r, NULL, nonce);
229        if (ret != GNUTLS_E_SUCCESS)
230        {
231            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
232                         "Could not get nonce: %s (%d)",
233                         gnutls_strerror(ret), ret);
234            gnutls_free(nonce->data);
235            nonce->data = NULL;
236            nonce->size = 0;
237            gnutls_ocsp_req_deinit(r);
238            return ret;
239        }
240    }
241
242    ret = gnutls_ocsp_req_export(r, req);
243    if (ret != GNUTLS_E_SUCCESS)
244    {
245        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
246                     "OCSP request export failed: %s (%d)",
247                     gnutls_strerror(ret), ret);
248        gnutls_free(req->data);
249        req->data = NULL;
250        req->size = 0;
251        if (nonce != NULL)
252        {
253            gnutls_free(nonce->data);
254            nonce->data = NULL;
255            nonce->size = 0;
256        }
257        gnutls_ocsp_req_deinit(r);
258        return ret;
259    }
260
261    gnutls_ocsp_req_deinit(r);
262    return ret;
263}
264
265
266
267/**
268 * Check if the provided OCSP response is usable for stapling in
269 * connections to this server. Returns GNUTLS_E_SUCCESS if yes.
270 *
271 * Supports only one certificate status per response.
272 *
273 * If expiry is not NULL, it will be set to the nextUpdate time
274 * contained in the response, or zero if the response does not contain
275 * a nextUpdate field.
276 *
277 * If nonce is not NULL, the response must contain a matching nonce.
278 */
279int check_ocsp_response(server_rec *s, mgs_ocsp_data_t req_data,
280                        const gnutls_datum_t *ocsp_response,
281                        apr_time_t* expiry, const gnutls_datum_t *nonce)
282    __attribute__((nonnull(1, 3)));
283int check_ocsp_response(server_rec *s, mgs_ocsp_data_t req_data,
284                        const gnutls_datum_t *ocsp_response,
285                        apr_time_t* expiry, const gnutls_datum_t *nonce)
286{
287    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
288        ap_get_module_config(s->module_config, &gnutls_module);
289
290    if (req_data->trust == NULL)
291    {
292        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
293                     "No OCSP trust list available for server \"%s\"!",
294                     s->server_hostname);
295        return GNUTLS_E_NO_CERTIFICATE_FOUND;
296    }
297
298    gnutls_ocsp_resp_t resp;
299    int ret = gnutls_ocsp_resp_init(&resp);
300    if (ret != GNUTLS_E_SUCCESS)
301    {
302        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
303                     "Could not initialize OCSP response structure: %s (%d)",
304                     gnutls_strerror(ret), ret);
305        goto resp_cleanup;
306    }
307    ret = gnutls_ocsp_resp_import(resp, ocsp_response);
308    if (ret != GNUTLS_E_SUCCESS)
309    {
310        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
311                     "Importing OCSP response failed: %s (%d)",
312                     gnutls_strerror(ret), ret);
313        goto resp_cleanup;
314    }
315
316    ret = gnutls_ocsp_resp_check_crt(resp, 0, req_data->cert);
317    if (ret != GNUTLS_E_SUCCESS)
318    {
319        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
320                     "OCSP response is not for server certificate: %s (%d)",
321                     gnutls_strerror(ret), ret);
322        goto resp_cleanup;
323    }
324
325    unsigned int verify;
326    ret = gnutls_ocsp_resp_verify(resp, *(req_data->trust), &verify, 0);
327    if (ret != GNUTLS_E_SUCCESS)
328    {
329        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
330                     "OCSP response verification failed: %s (%d)",
331                     gnutls_strerror(ret), ret);
332        goto resp_cleanup;
333    }
334    else
335    {
336        /* verification worked, check the result */
337        if (verify != 0)
338        {
339            _log_verify_fail_reason(verify, s);
340            ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
341            goto resp_cleanup;
342        }
343        else
344            ap_log_error(APLOG_MARK, APLOG_TRACE1, APR_SUCCESS, s,
345                         "OCSP response signature is valid.");
346    }
347
348    /* Even some large CAs do not support nonces, probably because
349     * that way they can cache responses. :-/ */
350    if (nonce != NULL && sc->ocsp_check_nonce)
351    {
352        gnutls_datum_t resp_nonce;
353        ret = gnutls_ocsp_resp_get_nonce(resp, 0, &resp_nonce);
354        if (ret != GNUTLS_E_SUCCESS)
355        {
356            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
357                         "Could not get OCSP response nonce: %s (%d)",
358                         gnutls_strerror(ret), ret);
359            goto resp_cleanup;
360        }
361        if (resp_nonce.size != nonce->size
362            || memcmp(resp_nonce.data, nonce->data, nonce->size))
363        {
364            ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
365            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
366                         "OCSP response invalid: nonce mismatch");
367            gnutls_free(resp_nonce.data);
368            goto resp_cleanup;
369        }
370        ap_log_error(APLOG_MARK, APLOG_TRACE2, APR_SUCCESS, s,
371                     "OCSP response: nonce match");
372        gnutls_free(resp_nonce.data);
373    }
374
375    /* OK, response is for our certificate and valid, let's get the
376     * actual response data. */
377    unsigned int cert_status;
378    time_t this_update;
379    time_t next_update;
380    ret = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL, NULL,
381                                      &cert_status, &this_update,
382                                      &next_update, NULL, NULL);
383    if (ret != GNUTLS_E_SUCCESS)
384    {
385        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
386                     "Could not get OCSP response data: %s (%d)",
387                     gnutls_strerror(ret), ret);
388        goto resp_cleanup;
389    }
390
391    apr_time_t now = apr_time_now();
392    apr_time_t valid_at;
393    apr_time_ansi_put(&valid_at, this_update);
394    /* Buffer for human-readable times produced by apr_rfc822_date,
395     * see apr_time.h */
396    char date_str[APR_RFC822_DATE_LEN];
397    apr_rfc822_date(date_str, valid_at);
398
399    if (now < valid_at)
400    {
401        /* We don't know if our clock or that of the OCSP responder is
402         * out of sync, so warn but continue. */
403        ap_log_error(APLOG_MARK, APLOG_WARNING, APR_EGENERAL, s,
404                     "OSCP response claims to be from future (%s), check "
405                     "time synchronization!", date_str);
406    }
407
408    if (next_update == (time_t) -1)
409    {
410        ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, s,
411                     "OSCP response does not contain nextUpdate info.");
412        if (expiry != NULL)
413            *expiry = 0;
414    }
415    else
416    {
417        apr_time_t valid_to;
418        apr_time_ansi_put(&valid_to, next_update);
419        if (expiry != NULL)
420            *expiry = valid_to;
421        if (now > valid_to)
422        {
423            apr_rfc822_date(date_str, valid_to);
424            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
425                         "OCSP response has expired at %s!", date_str);
426            /* Do not send a stale response */
427            ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
428            goto resp_cleanup;
429        }
430    }
431
432    /* What's the actual status? Will be one of
433     * gnutls_ocsp_cert_status_t as defined in gnutls/ocsp.h. */
434    if (cert_status == GNUTLS_OCSP_CERT_GOOD)
435    {
436        /* Yay, everything's good! */
437        ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, s,
438                     "CA flagged certificate as valid at %s.", date_str);
439    }
440    else
441    {
442        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
443                     "CA flagged certificate as %s at %s.",
444                     cert_status == GNUTLS_OCSP_CERT_REVOKED ?
445                     "revoked" : "unknown", date_str);
446        ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
447    }
448
449 resp_cleanup:
450    gnutls_ocsp_resp_deinit(resp);
451    return ret;
452}
453
454
455
456/*
457 * Returns the certificate fingerprint, memory is allocated from p.
458 */
459static gnutls_datum_t mgs_get_cert_fingerprint(apr_pool_t *p,
460                                               gnutls_x509_crt_t cert)
461{
462    gnutls_datum_t fingerprint = {NULL, 0};
463    size_t fplen = 0;
464    gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, NULL, &fplen);
465    unsigned char * fp = apr_palloc(p, fplen);
466    gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, fp, &fplen);
467    /* Safe integer type conversion: The types of fingerprint.size
468     * (unsigned int) and fplen (size_t) may have different
469     * lengths. */
470#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
471    if (__builtin_expect(fplen <= UINT_MAX, 1))
472    {
473        fingerprint.size = (unsigned int) fplen;
474        fingerprint.data = fp;
475    }
476#else
477    if (__builtin_add_overflow(fplen, 0, &fingerprint.size))
478        fingerprint.size = 0;
479    else
480        fingerprint.data = fp;
481#endif
482    return fingerprint;
483}
484
485
486
487static apr_status_t do_ocsp_request(apr_pool_t *p, server_rec *s,
488                                    apr_uri_t *uri,
489                                    gnutls_datum_t *request,
490                                    gnutls_datum_t *response)
491    __attribute__((nonnull));
492static apr_status_t do_ocsp_request(apr_pool_t *p, server_rec *s,
493                                    apr_uri_t *uri,
494                                    gnutls_datum_t *request,
495                                    gnutls_datum_t *response)
496{
497    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
498        ap_get_module_config(s->module_config, &gnutls_module);
499
500    if (apr_strnatcmp(uri->scheme, "http"))
501    {
502        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
503                     "Scheme \"%s\" is not supported for OCSP requests!",
504                     uri->scheme);
505        return APR_EINVAL;
506    }
507
508    const char* header = http_post_header(p, uri,
509                                          OCSP_REQ_TYPE, OCSP_RESP_TYPE,
510                                          request->size);
511    ap_log_error(APLOG_MARK, APLOG_TRACE2, APR_SUCCESS, s,
512                 "OCSP POST header: %s", header);
513
514    /* Find correct port */
515    apr_port_t port = uri->port ?
516        uri->port : apr_uri_port_of_scheme(uri->scheme);
517
518    apr_sockaddr_t *sa;
519    apr_status_t rv = apr_sockaddr_info_get(&sa, uri->hostname,
520                                            APR_UNSPEC, port, 0, p);
521    if (rv != APR_SUCCESS)
522    {
523        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
524                     "Address resolution for OCSP responder %s failed.",
525                     uri->hostinfo);
526    }
527
528    /* There may be multiple answers, try them in order until one
529     * works. */
530    apr_socket_t *sock;
531    while (sa)
532    {
533        rv = apr_socket_create(&sock, sa->family, SOCK_STREAM,
534                               APR_PROTO_TCP, p);
535        if (rv == APR_SUCCESS)
536        {
537            apr_socket_timeout_set(sock, sc->ocsp_socket_timeout);
538            rv = apr_socket_connect(sock, sa);
539            if (rv == APR_SUCCESS)
540                /* Connected! */
541                break;
542            apr_socket_close(sock);
543        }
544        sa = sa->next;
545    }
546    /* If the socket is connected, 'sa' points at the matching
547     * address. */
548    if (sa == NULL)
549    {
550        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
551                     "Connecting to OCSP responder %s failed.",
552                     uri->hostinfo);
553        return rv;
554    }
555
556    /* Header is generated locally, so strlen() is safe. */
557    rv = sock_send_buf(sock, header, strlen(header));
558    if (rv == APR_SUCCESS)
559        rv = sock_send_buf(sock, (char*) request->data, request->size);
560    /* catches errors from both header and request */
561    if (rv != APR_SUCCESS)
562    {
563        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
564                     "Sending OCSP request failed.");
565        goto exit;
566    }
567
568    /* Prepare bucket brigades to read the response header. BBs make
569     * it easy to split the header into lines. */
570    apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
571    apr_bucket_brigade *bb = apr_brigade_create(p, ba);
572    /* will carry split response headers */
573    apr_bucket_brigade *rh = apr_brigade_create(p, ba);
574
575    APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_socket_create(sock, ba));
576    /* The first line in the response header must be the status, check
577     * for OK status code. Line looks similar to "HTTP/1.0 200 OK". */
578    const char *h = read_line(p, bb, rh);
579    const char *code = 0;
580    if (h == NULL
581        || strncmp(h, "HTTP/", 5)
582        || (code = ap_strchr(h, ' ')) == NULL
583        || apr_atoi64(code + 1) != HTTP_OK)
584    {
585        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
586                     "Invalid HTTP response status from %s: %s",
587                     uri->hostinfo, h);
588        rv = APR_ECONNRESET;
589        goto exit;
590    }
591    /* Read remaining header lines */
592    for (h = read_line(p, bb, rh); h != NULL && apr_strnatcmp(h, "") != 0;
593         h = read_line(p, bb, rh))
594    {
595        ap_log_error(APLOG_MARK, APLOG_TRACE2, APR_SUCCESS, s,
596                     "Received header: %s", h);
597    }
598    /* The last header line should be empty (""), NULL indicates an
599     * error. */
600    if (h == NULL)
601    {
602        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
603                     "Error while reading HTTP response header from %s",
604                     uri->hostinfo);
605        rv = APR_ECONNRESET;
606        goto exit;
607    }
608
609    /* Headers have been consumed, the rest of the available data
610     * should be the actual response. */
611    apr_size_t len = OCSP_RESP_SIZE_MAX;
612    char buf[OCSP_RESP_SIZE_MAX];
613    /* apr_brigade_pflatten() can allocate directly from the pool, but
614     * the documentation does not describe a way to limit the size of
615     * the buffer, which is necessary here to prevent DoS by endless
616     * response. Use apr_brigade_flatten() to read to a stack pool,
617     * then create a copy to return. */
618    rv = apr_brigade_flatten(bb, buf, &len);
619    if (rv != APR_SUCCESS)
620    {
621        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
622                     "Failed to read OCSP response.");
623        goto exit;
624    }
625
626    /* With the length restriction this really should not overflow. */
627#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
628    if (__builtin_expect(len > UINT_MAX, 0))
629#else
630    if (__builtin_add_overflow(len, 0, &response->size))
631#endif
632    {
633        response->data = NULL;
634        rv = APR_ENOMEM;
635    }
636    else
637    {
638#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
639        response->size = (unsigned int) len;
640#endif
641        response->data = apr_pmemdup(p, buf, len);
642    }
643
644 exit:
645    apr_socket_close(sock);
646    return rv;
647}
648
649
650
651/**
652 * Get a fresh OCSP response and put it into the cache.
653 *
654 * @param s server that needs a new response
655 *
656 * @param req_data struct describing the certificate for which to
657 * cache a response
658 *
659 * @param cache_expiry If not `NULL`, this `apr_time_t` will be set to
660 * the expiration time of the cache entry. Remains unchanged on
661 * failure.
662 *
663 * @return APR_SUCCESS or an APR error code
664 */
665static apr_status_t mgs_cache_ocsp_response(server_rec *s,
666                                            mgs_ocsp_data_t req_data,
667                                            apr_time_t *cache_expiry)
668{
669    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
670        ap_get_module_config(s->module_config, &gnutls_module);
671
672    if (sc->ocsp_cache == NULL)
673    {
674        /* OCSP caching requires a cache. */
675        return APR_ENOTIMPL;
676    }
677
678    apr_pool_t *tmp;
679    apr_status_t rv = apr_pool_create(&tmp, NULL);
680    if (rv != APR_SUCCESS)
681    {
682        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
683                     "could not create temporary pool for %s",
684                     __func__);
685        return rv;
686    }
687
688    gnutls_datum_t resp;
689    gnutls_datum_t nonce = { NULL, 0 };
690
691    if (req_data->response_file != NULL)
692    {
693        ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, s,
694                     "Loading OCSP response from %s",
695                     req_data->response_file);
696        rv = datum_from_file(tmp, req_data->response_file, &resp);
697        if (rv != APR_SUCCESS)
698        {
699            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
700                         "Loading OCSP response from %s failed!",
701                         req_data->response_file);
702            apr_pool_destroy(tmp);
703            return rv;
704        }
705    }
706    else
707    {
708        gnutls_datum_t req;
709        int ret = mgs_create_ocsp_request(s, req_data, &req,
710                                          sc->ocsp_check_nonce ? &nonce : NULL);
711        if (ret == GNUTLS_E_SUCCESS)
712        {
713            ap_log_error(APLOG_MARK, APLOG_TRACE2, APR_SUCCESS, s,
714                         "created OCSP request for %s:%d: %s",
715                         s->server_hostname, s->addrs->host_port,
716                         apr_pescape_hex(tmp, req.data, req.size, 0));
717        }
718        else
719        {
720            gnutls_free(req.data);
721            gnutls_free(nonce.data);
722            apr_pool_destroy(tmp);
723            return APR_EGENERAL;
724        }
725
726        rv = do_ocsp_request(tmp, s, req_data->uri, &req, &resp);
727        gnutls_free(req.data);
728        if (rv != APR_SUCCESS)
729        {
730            /* do_ocsp_request() does its own error logging. */
731            gnutls_free(nonce.data);
732            apr_pool_destroy(tmp);
733            return rv;
734        }
735    }
736
737    apr_time_t next_update;
738    if (check_ocsp_response(s, req_data, &resp, &next_update,
739                            nonce.size ? &nonce : NULL)
740        != GNUTLS_E_SUCCESS)
741    {
742        ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_EGENERAL, s,
743                     "OCSP response validation failed, cannot "
744                     "update cache.");
745        apr_pool_destroy(tmp);
746        gnutls_free(nonce.data);
747        return APR_EGENERAL;
748    }
749    gnutls_free(nonce.data);
750
751    apr_time_t expiry = apr_time_now() + sc->ocsp_cache_time;
752    /* Make sure that a response is not cached beyond its nextUpdate
753     * time. If the variable next_update is zero, the response does
754     * not contain a nextUpdate field. */
755    if (next_update != 0 && next_update < expiry)
756    {
757        char date_str[APR_RFC822_DATE_LEN];
758        apr_rfc822_date(date_str, next_update);
759        ap_log_error(APLOG_MARK, APLOG_WARNING, APR_EGENERAL, s,
760                     "OCSP response timeout restricted to nextUpdate time %s. "
761                     "Check if GnuTLSOCSPCacheTimeout is appropriate.",
762                     date_str);
763        expiry = next_update;
764    }
765
766    int r = mgs_cache_store(sc->ocsp_cache, s,
767                            req_data->fingerprint, resp, expiry);
768    /* destroy pool, and original copy of the OCSP response with it */
769    apr_pool_destroy(tmp);
770    if (r != 0)
771    {
772        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
773                      "Storing OCSP response in cache failed.");
774        return APR_EGENERAL;
775    }
776
777    if (cache_expiry != NULL)
778        *cache_expiry = expiry;
779    return APR_SUCCESS;
780}
781
782
783
784/**
785 * Retries after failed OCSP requests must be rate limited. If the
786 * responder is overloaded or buggy we don't want to add too much more
787 * load, and if a MITM is messing with requests a repetition loop
788 * might end up being a self-inflicted denial of service. This
789 * function writes a specially formed entry to the cache to indicate a
790 * recent failure.
791 *
792 * @param s the server for which an OCSP request failed
793 *
794 * @param req_data OCSP data structure for the certificate that could
795 * not be checked
796 *
797 * @param timeout lifetime of the cache entry
798 */
799static void mgs_cache_ocsp_failure(server_rec *s,
800                                   mgs_ocsp_data_t req_data,
801                                   apr_interval_time_t timeout)
802{
803    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
804        ap_get_module_config(s->module_config, &gnutls_module);
805
806    unsigned char c = OCSP_FAILURE_CACHE_DATA;
807    gnutls_datum_t dummy = {
808        .data = &c,
809        .size = sizeof(c)
810    };
811    apr_time_t expiry = apr_time_now() + timeout;
812
813    int r = mgs_cache_store(sc->ocsp_cache, s,
814                            req_data->fingerprint, dummy, expiry);
815    if (r != 0)
816        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
817                     "Caching OCSP failure failed.");
818}
819
820
821
822int mgs_get_ocsp_response(mgs_handle_t *ctxt,
823                          mgs_ocsp_data_t req_data,
824                          gnutls_datum_t *ocsp_response)
825{
826    mgs_srvconf_rec *sc = ctxt->sc;
827
828    if (!sc->ocsp_staple || sc->ocsp_cache == NULL)
829    {
830        /* OCSP must be enabled and caching requires a cache. */
831        return GNUTLS_E_NO_CERTIFICATE_STATUS;
832    }
833
834    // TODO: Large allocation, and the pool system doesn't offer realloc
835    ocsp_response->data = apr_palloc(ctxt->c->pool, OCSP_RESP_SIZE_MAX);
836    ocsp_response->size = OCSP_RESP_SIZE_MAX;
837
838    apr_status_t rv = mgs_cache_fetch(sc->ocsp_cache,
839                                      ctxt->c->base_server,
840                                      req_data->fingerprint,
841                                      ocsp_response,
842                                      ctxt->c->pool);
843    if (rv != APR_SUCCESS)
844    {
845        ap_log_cerror(APLOG_MARK, APLOG_TRACE1, APR_EGENERAL, ctxt->c,
846                      "Fetching OCSP response from cache failed.");
847    }
848    else if (IS_FAILURE_RESPONSE(ocsp_response))
849    {
850        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_EGENERAL, ctxt->c,
851                      "Cached OCSP failure found for %s.",
852                      ctxt->c->base_server->server_hostname);
853        goto fail_cleanup;
854    }
855    else
856    {
857        return GNUTLS_E_SUCCESS;
858    }
859    /* keep response buffer, reset size for reuse */
860    ocsp_response->size = OCSP_RESP_SIZE_MAX;
861
862    /* If the cache had no response or an invalid one, try to update. */
863    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ctxt->c,
864                  "No valid OCSP response in cache, trying to update.");
865
866    rv = apr_global_mutex_trylock(sc->ocsp_mutex);
867    if (APR_STATUS_IS_EBUSY(rv))
868    {
869        /* Another thread is currently holding the mutex, wait. */
870        apr_global_mutex_lock(sc->ocsp_mutex);
871        /* Check if this other thread updated the response we need. It
872         * would be better to have a vhost specific mutex, but at the
873         * moment there's no good way to integrate that with the
874         * Apache Mutex directive. */
875        rv = mgs_cache_fetch(sc->ocsp_cache,
876                             ctxt->c->base_server,
877                             req_data->fingerprint,
878                             ocsp_response,
879                             ctxt->c->pool);
880        if (rv == APR_SUCCESS)
881        {
882            apr_global_mutex_unlock(sc->ocsp_mutex);
883            /* Check if the response is valid. */
884            if (IS_FAILURE_RESPONSE(ocsp_response))
885            {
886                ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_EGENERAL, ctxt->c,
887                              "Cached OCSP failure found for %s.",
888                              ctxt->c->base_server->server_hostname);
889                goto fail_cleanup;
890            }
891            else
892                return GNUTLS_E_SUCCESS;
893        }
894        else
895        {
896            /* keep response buffer, reset size for reuse */
897            ocsp_response->size = OCSP_RESP_SIZE_MAX;
898        }
899    }
900
901    rv = mgs_cache_ocsp_response(ctxt->c->base_server, req_data, NULL);
902    if (rv != APR_SUCCESS)
903    {
904        ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, ctxt->c,
905                      "Caching a fresh OCSP response failed");
906        /* cache failure to rate limit retries */
907        mgs_cache_ocsp_failure(ctxt->c->base_server,
908                               req_data,
909                               sc->ocsp_failure_timeout);
910        apr_global_mutex_unlock(sc->ocsp_mutex);
911        goto fail_cleanup;
912    }
913    apr_global_mutex_unlock(sc->ocsp_mutex);
914
915    /* retry reading from cache */
916    rv = mgs_cache_fetch(sc->ocsp_cache,
917                         ctxt->c->base_server,
918                         req_data->fingerprint,
919                         ocsp_response,
920                         ctxt->c->pool);
921    if (rv != APR_SUCCESS)
922    {
923        ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, ctxt->c,
924                      "Fetching OCSP response from cache failed on retry.");
925    }
926    else
927    {
928        return GNUTLS_E_SUCCESS;
929    }
930
931    /* failure, reset struct, buffer will be released with the
932     * connection pool */
933 fail_cleanup:
934    ocsp_response->size = 0;
935    ocsp_response->data = NULL;
936    return GNUTLS_E_NO_CERTIFICATE_STATUS;
937}
938
939
940
941int mgs_create_ocsp_trust_list(gnutls_x509_trust_list_t *tl,
942                               const gnutls_x509_crt_t *chain,
943                               const int num)
944{
945    int added = 0;
946    int ret = gnutls_x509_trust_list_init(tl, num);
947
948    if (ret == GNUTLS_E_SUCCESS)
949        added = gnutls_x509_trust_list_add_cas(*tl, chain, num, 0);
950
951    if (added != num)
952        ret = GNUTLS_E_CERTIFICATE_ERROR;
953
954    /* Clean up trust list in case of error */
955    if (ret != GNUTLS_E_SUCCESS)
956        gnutls_x509_trust_list_deinit(*tl, 0);
957
958    return ret;
959}
960
961
962
963apr_status_t mgs_cleanup_trust_list(void *data)
964{
965    gnutls_x509_trust_list_t *tl = (gnutls_x509_trust_list_t *) data;
966    gnutls_x509_trust_list_deinit(*tl, 0);
967    return APR_SUCCESS;
968}
969
970
971
972apr_uri_t * mgs_cert_get_ocsp_uri(apr_pool_t *p, gnutls_x509_crt_t cert)
973{
974    apr_pool_t *tmp;
975    apr_status_t rv = apr_pool_create(&tmp, p);
976    if (rv != APR_SUCCESS)
977        return NULL;
978
979    apr_uri_t *ocsp_uri = NULL;
980
981    int ret = GNUTLS_E_SUCCESS;
982    /* search authority info access for OCSP URI */
983    for (int seq = 0; ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; seq++)
984    {
985        gnutls_datum_t ocsp_access_data;
986        ret = gnutls_x509_crt_get_authority_info_access(cert, seq,
987                                                        GNUTLS_IA_OCSP_URI,
988                                                        &ocsp_access_data,
989                                                        NULL);
990        if (ret == GNUTLS_E_SUCCESS)
991        {
992            /* create NULL terminated string */
993            char *ocsp_str =
994                apr_pstrndup(tmp, (const char*) ocsp_access_data.data,
995                             ocsp_access_data.size);
996            gnutls_free(ocsp_access_data.data);
997
998            ocsp_uri = apr_palloc(p, sizeof(apr_uri_t));
999            rv = apr_uri_parse(p, ocsp_str, ocsp_uri);
1000            if (rv == APR_SUCCESS)
1001                break;
1002            else
1003                ocsp_uri = NULL;
1004        }
1005    }
1006
1007    apr_pool_destroy(tmp);
1008    return ocsp_uri;
1009}
1010
1011
1012
1013/** The maximum random fuzz base (half the maximum fuzz) that will not
1014 * overflow. The permitted values are limited to whatever will not
1015 * make an `apr_interval_time_t` variable overflow when multiplied
1016 * with `APR_UINT16_MAX`. With apr_interval_time_t being a 64 bit
1017 * signed integer the maximum fuzz interval is about 4.5 years, which
1018 * should be more than plenty. */
1019#define MAX_FUZZ_BASE (APR_INT64_MAX / APR_UINT16_MAX)
1020
1021/**
1022 * Perform an asynchronous OCSP cache update. This is a callback for
1023 * mod_watchdog, so the API is fixed (except the meaning of data).
1024 *
1025 * @param state watchdog state (starting/running/stopping)
1026 * @param data callback data, contains the server_rec
1027 * @param pool temporary callback pool destroyed after the call
1028 * @return always `APR_SUCCESS` as required by the mod_watchdog API to
1029 * indicate that the callback should be called again
1030 */
1031static apr_status_t mgs_async_ocsp_update(int state,
1032                                          void *data,
1033                                          apr_pool_t *pool)
1034{
1035    /* If the server is stopping there's no need to do an OCSP
1036     * update. */
1037    if (state == AP_WATCHDOG_STATE_STOPPING)
1038        return APR_SUCCESS;
1039
1040    mgs_ocsp_data_t ocsp_data = (mgs_ocsp_data_t) data;
1041    server_rec *server = (server_rec *) ocsp_data->server;
1042    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
1043        ap_get_module_config(server->module_config, &gnutls_module);
1044    apr_time_t expiry = 0;
1045
1046    /* Holding the mutex should help avoiding simultaneous synchronous
1047     * and asynchronous OCSP requests in some edge cases: during
1048     * startup if there's an early request, and if OCSP requests fail
1049     * repeatedly until the cached response expires and a synchronous
1050     * update is triggered before a failure cache entry is
1051     * created. Usually there should be a good OCSP response in the
1052     * cache and the mutex is never touched in
1053     * mgs_get_ocsp_response. */
1054    apr_global_mutex_lock(sc->ocsp_mutex);
1055    apr_status_t rv = mgs_cache_ocsp_response(server, ocsp_data, &expiry);
1056
1057    apr_interval_time_t next_interval;
1058    if (rv != APR_SUCCESS)
1059        next_interval = sc->ocsp_failure_timeout;
1060    else
1061    {
1062        apr_uint16_t random_bytes;
1063        int res = gnutls_rnd(GNUTLS_RND_NONCE, &random_bytes,
1064                             sizeof(random_bytes));
1065        if (__builtin_expect(res < 0, 0))
1066        {
1067            /* Shouldn't ever happen, because a working random number
1068             * generator is required for establishing TLS sessions. */
1069            random_bytes = (apr_uint16_t) apr_time_now();
1070            ap_log_error(APLOG_MARK, APLOG_WARNING, APR_EGENERAL, server,
1071                         "Error getting random number for fuzzy update "
1072                         "interval: %s Falling back on truncated time.",
1073                         gnutls_strerror(res));
1074        }
1075
1076        /* Choose the fuzz interval for the next update between
1077         * `sc->ocsp_fuzz_time` and twice that. */
1078        apr_interval_time_t fuzz = sc->ocsp_fuzz_time
1079            + (sc->ocsp_fuzz_time * random_bytes / APR_UINT16_MAX);
1080
1081        /* With an extremly short timeout or weird nextUpdate value
1082         * next_interval <= 0 might happen. Use the failure timeout to
1083         * avoid endlessly repeating updates. */
1084        next_interval = expiry - apr_time_now();
1085        if (next_interval <= 0)
1086        {
1087            next_interval = sc->ocsp_failure_timeout;
1088            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server,
1089                         "OCSP cache expiration time of the response for "
1090                         "%s:%d is in the past, repeating after failure "
1091                         "timeout (GnuTLSOCSPFailureTimeout).",
1092                         server->server_hostname, server->addrs->host_port);
1093        }
1094
1095        /* It's possible to compare maximum fuzz and configured OCSP
1096         * cache timeout at configuration time, but the interval until
1097         * the nextUpdate value expires (or the failure timeout
1098         * fallback above) might be shorter. Make sure that we don't
1099         * end up with a negative interval. */
1100        while (fuzz > next_interval)
1101            fuzz /= 2;
1102        next_interval -= fuzz;
1103    }
1104
1105    sc->singleton_wd->set_callback_interval(sc->singleton_wd->wd,
1106                                            next_interval,
1107                                            ocsp_data, mgs_async_ocsp_update);
1108
1109    ap_log_error(APLOG_MARK, rv == APR_SUCCESS ? APLOG_DEBUG : APLOG_WARNING,
1110                 rv, server,
1111                 "Async OCSP update %s for %s:%d, next update in "
1112                 "%" APR_TIME_T_FMT " seconds.",
1113                 rv == APR_SUCCESS ? "done" : "failed",
1114                 server->server_hostname, server->addrs->host_port,
1115                 apr_time_sec(next_interval));
1116
1117    /* Check if there's still a response in the cache. If not, add a
1118     * failure entry. If there already is a failure entry, refresh
1119     * it. The lifetime of such entries is twice the error timeout to
1120     * make sure they do not expire before the next scheduled
1121     * update. */
1122    if (rv != APR_SUCCESS)
1123    {
1124        gnutls_datum_t ocsp_response;
1125        ocsp_response.data = apr_palloc(pool, OCSP_RESP_SIZE_MAX);
1126        ocsp_response.size = OCSP_RESP_SIZE_MAX;
1127
1128        rv = mgs_cache_fetch(sc->ocsp_cache, server, ocsp_data->fingerprint,
1129                             &ocsp_response, pool);
1130
1131        if (rv != APR_SUCCESS || (IS_FAILURE_RESPONSE(&ocsp_response)))
1132        {
1133            ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, server,
1134                         "Caching OCSP request failure for %s:%d.",
1135                         server->server_hostname, server->addrs->host_port);
1136            mgs_cache_ocsp_failure(server, ocsp_data,
1137                                   sc->ocsp_failure_timeout * 2);
1138        }
1139    }
1140    apr_global_mutex_unlock(sc->ocsp_mutex);
1141
1142    return APR_SUCCESS;
1143}
1144
1145
1146
1147static const char* configure_cert_staple(mgs_ocsp_data_t ocsp,
1148                                         server_rec *server,
1149                                         mgs_srvconf_rec *sc,
1150                                         int idx,
1151                                         apr_pool_t *pconf)
1152{
1153    ocsp->cert = sc->certs_x509_crt_chain[idx];
1154    ocsp->server = server;
1155
1156    if (sc->ocsp_response_file != NULL && idx < sc->ocsp_response_file_num)
1157        ocsp->response_file = sc->ocsp_response_file[idx];
1158    else
1159        ocsp->response_file = NULL;
1160
1161    ocsp->uri = mgs_cert_get_ocsp_uri(pconf, ocsp->cert);
1162    if (ocsp->uri == NULL && ocsp->response_file == NULL)
1163        return "No OCSP URI in the certificate nor a "
1164            "GnuTLSOCSPResponseFile setting, cannot configure "
1165            "OCSP stapling.";
1166
1167    ocsp->fingerprint =
1168        mgs_get_cert_fingerprint(pconf, sc->certs_x509_crt_chain[idx]);
1169    if (ocsp->fingerprint.data == NULL)
1170        return "Could not read fingerprint from certificate!";
1171
1172    ocsp->trust = apr_palloc(pconf,
1173                             sizeof(gnutls_x509_trust_list_t));
1174    /* Only the direct issuer may sign the OCSP response or an
1175     * OCSP signer. */
1176    int ret = mgs_create_ocsp_trust_list(
1177        ocsp->trust, &(sc->certs_x509_crt_chain[idx + 1]), 1);
1178    if (ret != GNUTLS_E_SUCCESS)
1179    {
1180        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, server,
1181                     "Could not create OCSP trust list: %s (%d)",
1182                     gnutls_strerror(ret), ret);
1183        return "Could not build trust list for OCSP stapling!";
1184    }
1185    /* deinit trust list when the config pool is destroyed */
1186    apr_pool_cleanup_register(pconf, ocsp->trust,
1187                              mgs_cleanup_trust_list,
1188                              apr_pool_cleanup_null);
1189    return NULL;
1190}
1191
1192
1193
1194const char* mgs_ocsp_configure_stapling(apr_pool_t *pconf,
1195                                        apr_pool_t *ptemp __attribute__((unused)),
1196                                        server_rec *server)
1197{
1198    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
1199        ap_get_module_config(server->module_config, &gnutls_module);
1200
1201    if (sc->ocsp_cache == NULL)
1202        return "No OCSP response cache available, please check "
1203            "the GnuTLSOCSPCache setting.";
1204
1205    if (sc->certs_x509_chain_num < 2)
1206        return "No issuer (CA) certificate available, cannot enable "
1207            "stapling. Please add it to the GnuTLSCertificateFile.";
1208
1209    /* array for ocsp data, currently size 1 */
1210    sc->ocsp = apr_palloc(pconf, sizeof(mgs_ocsp_data_t) * (sc->certs_x509_chain_num - 1));
1211
1212    for (unsigned int i = 0; i < (sc->certs_x509_chain_num - 1); i++)
1213    {
1214        mgs_ocsp_data_t ocsp = apr_palloc(pconf, sizeof(struct mgs_ocsp_data));
1215
1216        const char *err = configure_cert_staple(ocsp, server, sc, i, pconf);
1217        if (err != NULL)
1218        {
1219            gnutls_datum_t dn;
1220            gnutls_x509_crt_get_dn3(sc->certs_x509_crt_chain[i], &dn, 0);
1221            /* If stapling is enabled it MUST work for the server
1222             * certificate itself, errors for others are
1223             * ignored. Either way log a warning. */
1224            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, server,
1225                         "Could not create OCSP stapling configuration "
1226                         "for certificate %u in chain (%s): %s",
1227                         i, (char*) dn.data, err);
1228            gnutls_free(dn.data);
1229            if (i == 0)
1230                return err;
1231            else
1232                break;
1233        }
1234
1235        sc->ocsp[i] = ocsp;
1236        sc->ocsp_num = i + 1;
1237    }
1238
1239    ap_log_error(APLOG_MARK, APLOG_INFO, 0, server,
1240                 "Configured OCSP stapling for %u certificates for %s:%d.",
1241                 sc->ocsp_num,
1242                 server->server_hostname, server->addrs->host_port);
1243    return NULL;
1244}
1245
1246
1247
1248/*
1249 * Like in the general post_config hook the HTTP status codes for
1250 * errors are just for fun. What matters is "neither OK nor DECLINED"
1251 * to denote an error.
1252 */
1253int mgs_ocsp_enable_stapling(apr_pool_t *pconf __attribute__((unused)),
1254                             apr_pool_t *ptemp __attribute__((unused)),
1255                             server_rec *server)
1256{
1257    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
1258        ap_get_module_config(server->module_config, &gnutls_module);
1259    if (sc->ocsp == NULL)
1260    {
1261        ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EGENERAL, server,
1262                     "CRITICAL ERROR: %s called with uninitialized OCSP "
1263                     "data structure. This indicates a bug in mod_gnutls.",
1264                     __func__);
1265        return HTTP_INTERNAL_SERVER_ERROR;
1266    }
1267
1268    /* set default values for unset parameters */
1269    if (sc->ocsp_auto_refresh == GNUTLS_ENABLED_UNSET)
1270        sc->ocsp_auto_refresh = GNUTLS_ENABLED_TRUE;
1271    if (sc->ocsp_check_nonce == GNUTLS_ENABLED_UNSET)
1272        sc->ocsp_check_nonce = GNUTLS_ENABLED_FALSE;
1273    if (sc->ocsp_cache_time == MGS_TIMEOUT_UNSET)
1274        sc->ocsp_cache_time = apr_time_from_sec(MGS_OCSP_CACHE_TIMEOUT);
1275    if (sc->ocsp_failure_timeout == MGS_TIMEOUT_UNSET)
1276        sc->ocsp_failure_timeout = apr_time_from_sec(MGS_OCSP_FAILURE_TIMEOUT);
1277    if (sc->ocsp_socket_timeout == MGS_TIMEOUT_UNSET)
1278        sc->ocsp_socket_timeout = apr_time_from_sec(MGS_OCSP_SOCKET_TIMEOUT);
1279    /* Base fuzz is half the configured maximum, the actual fuzz is
1280     * between the maximum and half that. The default maximum is
1281     * sc->ocsp_cache_time / 8, or twice the failure timeout,
1282     * whichever is larger (so the default guarantees at least one
1283     * retry before the cache entry expires).*/
1284    if (sc->ocsp_fuzz_time == MGS_TIMEOUT_UNSET)
1285    {
1286        sc->ocsp_fuzz_time = sc->ocsp_cache_time / 16;
1287        if (sc->ocsp_fuzz_time < sc->ocsp_failure_timeout)
1288            sc->ocsp_fuzz_time = sc->ocsp_failure_timeout;
1289    }
1290    else
1291        sc->ocsp_fuzz_time = sc->ocsp_fuzz_time / 2;
1292
1293    /* This really shouldn't happen considering MAX_FUZZ_BASE is about
1294     * 4.5 years, but better safe than sorry. */
1295    if (sc->ocsp_fuzz_time > MAX_FUZZ_BASE)
1296    {
1297        ap_log_error(APLOG_MARK, APLOG_STARTUP, APR_EINVAL, server,
1298                     "%s: Maximum fuzz time is too large, maximum "
1299                     "supported value is %" APR_INT64_T_FMT " seconds",
1300                     __func__, apr_time_sec(MAX_FUZZ_BASE) * 2);
1301        return HTTP_INTERNAL_SERVER_ERROR;
1302    }
1303
1304    /* The watchdog structure may be NULL if mod_watchdog is
1305     * unavailable. */
1306    if (sc->singleton_wd != NULL
1307        && sc->ocsp_auto_refresh == GNUTLS_ENABLED_TRUE)
1308    {
1309        /* register an update callback for each certificate configured
1310         * for stapling */
1311        for (unsigned int i = 0; i < sc->ocsp_num; i++)
1312        {
1313            apr_status_t rv =
1314                sc->singleton_wd->register_callback(sc->singleton_wd->wd,
1315                                                    sc->ocsp_cache_time,
1316                                                    sc->ocsp[i],
1317                                                    mgs_async_ocsp_update);
1318            if (rv == APR_SUCCESS)
1319                ap_log_error(APLOG_MARK, APLOG_INFO, rv, server,
1320                             "Enabled async OCSP update via watchdog "
1321                             "for %s:%d, cert[%u]",
1322                             server->server_hostname, server->addrs->host_port,
1323                             i);
1324            else
1325                ap_log_error(APLOG_MARK, APLOG_WARNING, rv, server,
1326                             "Enabling async OCSP update via watchdog "
1327                             "for %s:%d, cert[%u] failed!",
1328                             server->server_hostname, server->addrs->host_port,
1329                             i);
1330        }
1331    }
1332
1333    return OK;
1334}
Note: See TracBrowser for help on using the repository browser.