source: mod_gnutls/src/gnutls_ocsp.c @ 04addef

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

Create OCSP requests when updating the cached response

Actually sending the requests is not yet implemented, but request
creation works.

  • Property mode set to 100644
File size: 21.4 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"
[d35b98e]20
[47a909e]21#include <apr_escape.h>
[d35b98e]22#include <apr_lib.h>
23#include <apr_time.h>
24#include <gnutls/ocsp.h>
25#include <time.h>
[94cb972]26
27#ifdef APLOG_USE_MODULE
28APLOG_USE_MODULE(gnutls);
29#endif
30
[d35b98e]31
32
[08817d0]33#define _log_one_ocsp_fail(str, srv)                                    \
34    ap_log_error(APLOG_MARK, APLOG_INFO, APR_EGENERAL, (srv),           \
35                 "Reason for failed OCSP response verification: %s", (str))
[d35b98e]36/*
37 * Log all matching reasons for verification failure
38 */
[08817d0]39static void _log_verify_fail_reason(const unsigned int verify, server_rec *s)
[d35b98e]40{
41    if (verify & GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND)
[08817d0]42        _log_one_ocsp_fail("Signer cert not found", s);
[d35b98e]43
44    if (verify & GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR)
[08817d0]45        _log_one_ocsp_fail("Signer cert keyusage error", s);
[d35b98e]46
47    if (verify & GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER)
[08817d0]48        _log_one_ocsp_fail("Signer cert is not trusted", s);
[d35b98e]49
50    if (verify & GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM)
[08817d0]51        _log_one_ocsp_fail("Insecure algorithm", s);
[d35b98e]52
53    if (verify & GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE)
[08817d0]54        _log_one_ocsp_fail("Signature failure", s);
[d35b98e]55
56    if (verify & GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED)
[08817d0]57        _log_one_ocsp_fail("Signer cert not yet activated", s);
[d35b98e]58
59    if (verify & GNUTLS_OCSP_VERIFY_CERT_EXPIRED)
[08817d0]60        _log_one_ocsp_fail("Signer cert expired", s);
[d35b98e]61}
62
63
64
[94cb972]65const char *mgs_store_ocsp_response_path(cmd_parms *parms,
66                                         void *dummy __attribute__((unused)),
67                                         const char *arg)
68{
69    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
70        ap_get_module_config(parms->server->module_config, &gnutls_module);
71
72    sc->ocsp_response_file = ap_server_root_relative(parms->pool, arg);
73    return NULL;
74}
75
[d35b98e]76
77
78/**
[47a909e]79 * Create an OCSP request for the certificate of the given server. The
80 * DER encoded request is stored in 'req' (must be released with
81 * gnutls_free() when no longer needed), its nonce in 'nonce' (same,
82 * if not NULL).
83 *
84 * Returns GNUTLS_E_SUCCESS, or a GnuTLS error code.
85 */
86int mgs_create_ocsp_request(server_rec *s, gnutls_datum_t *req,
87                            gnutls_datum_t *nonce)
88{
89    if (req == NULL || s == NULL)
90        return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
91
92    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
93        ap_get_module_config(s->module_config, &gnutls_module);
94
95    gnutls_ocsp_req_t r;
96    int ret = gnutls_ocsp_req_init(&r);
97    if (ret != GNUTLS_E_SUCCESS)
98    {
99        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
100                     "Could not initialize OCSP request structure: %s (%d)",
101                     gnutls_strerror(ret), ret);
102        return ret;
103    }
104
105    /* GnuTLS doc says that the digest is "normally"
106     * GNUTLS_DIG_SHA1. */
107    ret = gnutls_ocsp_req_add_cert(r, GNUTLS_DIG_SHA256,
108                                   sc->certs_x509_crt_chain[1],
109                                   sc->certs_x509_crt_chain[0]);
110
111    if (ret != GNUTLS_E_SUCCESS)
112    {
113        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
114                     "Adding certificate to OCSP request for %s:%d "
115                     "failed: %s (%d)",
116                     s->server_hostname, s->addrs->host_port,
117                     gnutls_strerror(ret), ret);
118        gnutls_ocsp_req_deinit(r);
119        return ret;
120    }
121
122    ret = gnutls_ocsp_req_randomize_nonce(r);
123    if (ret != GNUTLS_E_SUCCESS)
124    {
125        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
126                     "OCSP nonce creation failed: %s (%d)",
127                     gnutls_strerror(ret), ret);
128        gnutls_ocsp_req_deinit(r);
129        return ret;
130    }
131
132    if (nonce != NULL)
133    {
134        ret = gnutls_ocsp_req_get_nonce(r, NULL, nonce);
135        if (ret != GNUTLS_E_SUCCESS)
136        {
137            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
138                         "Could not get nonce: %s (%d)",
139                         gnutls_strerror(ret), ret);
140            gnutls_free(nonce->data);
141            nonce->data = NULL;
142            nonce->size = 0;
143            gnutls_ocsp_req_deinit(r);
144            return ret;
145        }
146    }
147
148    ret = gnutls_ocsp_req_export(r, req);
149    if (ret != GNUTLS_E_SUCCESS)
150    {
151        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
152                     "OCSP request export failed: %s (%d)",
153                     gnutls_strerror(ret), ret);
154        gnutls_free(req->data);
155        req->data = NULL;
156        req->size = 0;
157        if (nonce != NULL)
158        {
159            gnutls_free(nonce->data);
160            nonce->data = NULL;
161            nonce->size = 0;
162        }
163        gnutls_ocsp_req_deinit(r);
164        return ret;
165    }
166
167    gnutls_ocsp_req_deinit(r);
168    return ret;
169}
170
171
172/**
[08817d0]173 * Check if the provided OCSP response is usable for stapling in
174 * connections to this server. Returns GNUTLS_E_SUCCESS if yes.
175 *
176 * Supports only one certificate status per response.
[366d1a1]177 *
178 * If expiry is not NULL, it will be set to the nextUpdate time
[5559aa6]179 * contained in the response, or zero if the response does not contain
180 * a nextUpdate field.
[d35b98e]181 */
[366d1a1]182int check_ocsp_response(server_rec *s, const gnutls_datum_t *ocsp_response,
183                        apr_time_t* expiry)
[d35b98e]184{
[08817d0]185    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
186        ap_get_module_config(s->module_config, &gnutls_module);
187
[cc74801e]188    if (sc->ocsp->trust == NULL)
[d35b98e]189    {
[08817d0]190        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
191                     "No OCSP trust list available for server \"%s\"!",
192                     s->server_hostname);
[d35b98e]193        return GNUTLS_E_NO_CERTIFICATE_FOUND;
194    }
[2a1ffd6]195
[d35b98e]196    gnutls_ocsp_resp_t resp;
[fad7695]197    int ret = gnutls_ocsp_resp_init(&resp);
[d35b98e]198    if (ret != GNUTLS_E_SUCCESS)
199    {
[08817d0]200        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
201                     "Could not initialize OCSP response structure: %s (%d)",
202                     gnutls_strerror(ret), ret);
[d35b98e]203        goto resp_cleanup;
204    }
205    ret = gnutls_ocsp_resp_import(resp, ocsp_response);
206    if (ret != GNUTLS_E_SUCCESS)
207    {
[08817d0]208        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
209                     "Importing OCSP response failed: %s (%d)",
210                     gnutls_strerror(ret), ret);
[d35b98e]211        goto resp_cleanup;
212    }
213
[08817d0]214    ret = gnutls_ocsp_resp_check_crt(resp, 0, sc->certs_x509_crt_chain[0]);
[d35b98e]215    if (ret != GNUTLS_E_SUCCESS)
216    {
[08817d0]217        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
218                     "OCSP response is not for server certificate: %s (%d)",
219                     gnutls_strerror(ret), ret);
[d35b98e]220        goto resp_cleanup;
221    }
222
223    unsigned int verify;
[cc74801e]224    ret = gnutls_ocsp_resp_verify(resp, *(sc->ocsp->trust), &verify, 0);
[d35b98e]225    if (ret != GNUTLS_E_SUCCESS)
226    {
[08817d0]227        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
228                     "OCSP response verification failed: %s (%d)",
229                     gnutls_strerror(ret), ret);
[d35b98e]230        goto resp_cleanup;
231    }
232    else
233    {
234        /* verification worked, check the result */
235        if (verify != 0)
236        {
[08817d0]237            _log_verify_fail_reason(verify, s);
[d35b98e]238            ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
239            goto resp_cleanup;
240        }
241        else
[08817d0]242            ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, s,
243                         "OCSP response is valid.");
[d35b98e]244    }
245
246    /* OK, response is for our certificate and valid, let's get the
247     * actual response data. */
248    unsigned int cert_status;
249    time_t this_update;
250    time_t next_update;
251    ret = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL, NULL,
252                                      &cert_status, &this_update,
253                                      &next_update, NULL, NULL);
254    if (ret != GNUTLS_E_SUCCESS)
255    {
[08817d0]256        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
257                     "Could not get OCSP response data: %s (%d)",
258                     gnutls_strerror(ret), ret);
[d35b98e]259        goto resp_cleanup;
260    }
261
262    apr_time_t now = apr_time_now();
263    apr_time_t valid_at;
264    apr_time_ansi_put(&valid_at, this_update);
265    /* Buffer for human-readable times produced by apr_rfc822_date,
266     * see apr_time.h */
267    char date_str[APR_RFC822_DATE_LEN];
268    apr_rfc822_date(date_str, valid_at);
269
270    if (now < valid_at)
271    {
272        /* We don't know if our clock or that of the OCSP responder is
273         * out of sync, so warn but continue. */
[08817d0]274        ap_log_error(APLOG_MARK, APLOG_WARNING, APR_EGENERAL, s,
275                     "OSCP response claims to be from future (%s), check "
276                     "time synchronization!", date_str);
[d35b98e]277    }
278
279    if (next_update == (time_t) -1)
[366d1a1]280    {
[08817d0]281        ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, s,
282                     "OSCP response does not contain nextUpdate info.");
[366d1a1]283        if (expiry != NULL)
284            *expiry = 0;
285    }
[d35b98e]286    else
287    {
288        apr_time_t valid_to;
289        apr_time_ansi_put(&valid_to, next_update);
[366d1a1]290        if (expiry != NULL)
291            *expiry = valid_to;
[d35b98e]292        if (now > valid_to)
293        {
294            apr_rfc822_date(date_str, valid_to);
[08817d0]295            ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
296                         "OCSP response has expired at %s!", date_str);
[2a1ffd6]297            /* Do not send a stale response */
[d35b98e]298            ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
299            goto resp_cleanup;
300        }
301    }
302
303    /* What's the actual status? Will be one of
304     * gnutls_ocsp_cert_status_t as defined in gnutls/ocsp.h. */
305    if (cert_status == GNUTLS_OCSP_CERT_GOOD)
306    {
307        /* Yay, everything's good! */
[08817d0]308        ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, s,
309                     "CA flagged certificate as valid at %s.", date_str);
[d35b98e]310    }
311    else
312    {
[08817d0]313        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
314                     "CA flagged certificate as %s at %s.",
315                     cert_status == GNUTLS_OCSP_CERT_REVOKED ?
316                     "revoked" : "unknown", date_str);
[d35b98e]317        ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
318    }
319
320 resp_cleanup:
321    gnutls_ocsp_resp_deinit(resp);
322    return ret;
323}
324
325
326
[6b4136c]327/*
328 * Returns the certificate fingerprint, memory is allocated from p.
329 */
330static gnutls_datum_t mgs_get_cert_fingerprint(apr_pool_t *p,
331                                               gnutls_x509_crt_t cert)
332{
333    gnutls_datum_t fingerprint = {NULL, 0};
334    size_t fplen;
335    gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, NULL, &fplen);
336    unsigned char * fp = apr_palloc(p, fplen);
337    gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, fp, &fplen);
[4bf4ce2]338    /* Safe integer type conversion: The types of fingerprint.size
339     * (unsigned int) and fplen (size_t) may have different
340     * lengths. */
341    if (__builtin_add_overflow(fplen, 0, &fingerprint.size))
342        fingerprint.size = 0;
343    else
344        fingerprint.data = fp;
[6b4136c]345    return fingerprint;
346}
347
348
349
350apr_status_t mgs_cache_ocsp_response(server_rec *s)
351{
352    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
353        ap_get_module_config(s->module_config, &gnutls_module);
354
[e809fb3]355    if (sc->cache == NULL)
[6b4136c]356    {
[e809fb3]357        /* OCSP caching requires a cache. */
[6b4136c]358        return APR_ENOTIMPL;
359    }
360
361    apr_pool_t *tmp;
362    apr_status_t rv = apr_pool_create(&tmp, NULL);
[366d1a1]363    if (rv != APR_SUCCESS)
364    {
365        ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
366                     "could not create temporary pool for %s",
367                     __func__);
368        return rv;
369    }
[6b4136c]370
[47a909e]371    /* TODO: actually send this request to sc->ocsp->uri and parse the
372     * received response (including nonce) */
373    gnutls_datum_t req;
374    int ret = mgs_create_ocsp_request(s, &req, NULL);
375    if (ret == GNUTLS_E_SUCCESS)
376    {
377        ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, s,
378                     "created OCSP request for %s:%d: %s",
379                     s->server_hostname, s->addrs->host_port,
380                     apr_pescape_hex(tmp, req.data, req.size, 0));
381        gnutls_free(req.data);
382    }
383
[6b4136c]384    ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, s,
385                 "Loading OCSP response from %s",
386                 sc->ocsp_response_file);
387    apr_file_t *file;
388    apr_finfo_t finfo;
389    apr_size_t br = 0;
390    rv = apr_file_open(&file, sc->ocsp_response_file,
391                       APR_READ | APR_BINARY, APR_OS_DEFAULT, tmp);
392    if (rv != APR_SUCCESS)
393    {
394        apr_pool_destroy(tmp);
395        return rv;
396    }
397    rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, file);
398    if (rv != APR_SUCCESS)
399    {
400        apr_pool_destroy(tmp);
401        return rv;
402    }
403
404    gnutls_datum_t resp;
405    resp.data = apr_palloc(tmp, finfo.size);
406    rv = apr_file_read_full(file, resp.data, finfo.size, &br);
407    if (rv != APR_SUCCESS)
408    {
409        apr_pool_destroy(tmp);
410        return rv;
411    }
412    apr_file_close(file);
[4bf4ce2]413    /* safe integer type conversion */
414    if (__builtin_add_overflow(br, 0, &resp.size))
415    {
416        apr_pool_destroy(tmp);
417        return APR_EINVAL;
418    }
[6b4136c]419
[366d1a1]420    apr_time_t expiry;
421    if (check_ocsp_response(s, &resp, &expiry) != GNUTLS_E_SUCCESS)
[08817d0]422    {
423        ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_EGENERAL, s,
424                     "OCSP response validation failed, cannot "
425                     "update cache.");
426        apr_pool_destroy(tmp);
427        return APR_EGENERAL;
428    }
[c6572ec]429    /* If expiry is zero, the response does not contain a nextUpdate
430     * field. Use the default cache timeout. */
[366d1a1]431    if (expiry == 0)
[c6572ec]432        expiry = apr_time_now() + sc->cache_timeout;
[70a1e5a]433    /* Apply grace time otherwise. */
434    else
435        expiry -= sc->ocsp_grace_time;
[366d1a1]436
[a372379]437    int r = sc->cache->store(s, sc->ocsp->fingerprint, resp, expiry);
[6b4136c]438    /* destroy pool, and original copy of the OCSP response with it */
439    apr_pool_destroy(tmp);
440    if (r != 0)
441    {
442        ap_log_error(APLOG_MARK, APLOG_ERR, APR_EGENERAL, s,
443                      "Storing OCSP response in cache failed.");
444        return APR_EGENERAL;
445    }
446    return APR_SUCCESS;
447}
448
449
450
[94cb972]451int mgs_get_ocsp_response(gnutls_session_t session __attribute__((unused)),
452                          void *ptr,
453                          gnutls_datum_t *ocsp_response)
454{
455    mgs_handle_t *ctxt = (mgs_handle_t *) ptr;
[e809fb3]456    if (ctxt->sc->cache == NULL)
457    {
458        /* OCSP caching requires a cache. */
459        return GNUTLS_E_NO_CERTIFICATE_STATUS;
460    }
[94cb972]461
[a372379]462    *ocsp_response = ctxt->sc->cache->fetch(ctxt,
463                                            ctxt->sc->ocsp->fingerprint);
[6b4136c]464    if (ocsp_response->size == 0)
[94cb972]465    {
[d18afb8]466        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_EGENERAL, ctxt->c,
[6b4136c]467                      "Fetching OCSP response from cache failed.");
[68ce93c]468    }
469    else
470    {
[5559aa6]471        return GNUTLS_E_SUCCESS;
[94cb972]472    }
[368e581]473    /* get rid of invalid response (if any) */
474    gnutls_free(ocsp_response->data);
[08817d0]475    ocsp_response->data = NULL;
[368e581]476
477    /* If the cache had no response or an invalid one, try to update. */
478    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ctxt->c,
479                  "No valid OCSP response in cache, trying to update.");
[d6834e0]480
[47a909e]481    /* TODO: Once sending OCSP requests is implemented we need a rate
482     * limit for retries on error. If the responder is overloaded or
483     * buggy we don't want to add too much more load, and if a MITM is
484     * messing with requests a repetition loop might end up being a
485     * self-inflicted denial of service. */
[d6834e0]486    apr_status_t rv = apr_global_mutex_trylock(ctxt->sc->ocsp_mutex);
487    if (APR_STATUS_IS_EBUSY(rv))
488    {
489        /* Another thread is currently holding the mutex, wait. */
490        apr_global_mutex_lock(ctxt->sc->ocsp_mutex);
491        /* Check if this other thread updated the response we need. It
492         * would be better to have a vhost specific mutex, but at the
493         * moment there's no good way to integrate that with the
494         * Apache Mutex directive. */
[a372379]495        *ocsp_response = ctxt->sc->cache->fetch(ctxt,
496                                                ctxt->sc->ocsp->fingerprint);
[5559aa6]497        if (ocsp_response->size > 0)
[d6834e0]498        {
499            /* Got a valid response now, unlock mutex and return. */
500            apr_global_mutex_unlock(ctxt->sc->ocsp_mutex);
501            return GNUTLS_E_SUCCESS;
502        }
503        else
504        {
505            gnutls_free(ocsp_response->data);
506            ocsp_response->data = NULL;
507        }
508    }
509
510    rv = mgs_cache_ocsp_response(ctxt->c->base_server);
[368e581]511    if (rv != APR_SUCCESS)
512    {
513        ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, ctxt->c,
514                      "Updating OCSP response cache failed");
[d6834e0]515        apr_global_mutex_unlock(ctxt->sc->ocsp_mutex);
[368e581]516        goto fail_cleanup;
517    }
[d6834e0]518    apr_global_mutex_unlock(ctxt->sc->ocsp_mutex);
[368e581]519
520    /* retry reading from cache */
[a372379]521    *ocsp_response = ctxt->sc->cache->fetch(ctxt,
522                                            ctxt->sc->ocsp->fingerprint);
[368e581]523    if (ocsp_response->size == 0)
524    {
525        ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, ctxt->c,
526                      "Fetching OCSP response from cache failed on retry.");
527    }
528    else
529    {
[5559aa6]530        return GNUTLS_E_SUCCESS;
[368e581]531    }
[94cb972]532
[68ce93c]533    /* failure, clean up response data */
[368e581]534 fail_cleanup:
[d35b98e]535    gnutls_free(ocsp_response->data);
536    ocsp_response->size = 0;
537    ocsp_response->data = NULL;
538    return GNUTLS_E_NO_CERTIFICATE_STATUS;
[94cb972]539}
[2a1ffd6]540
541
542
543int mgs_create_ocsp_trust_list(gnutls_x509_trust_list_t *tl,
544                               const gnutls_x509_crt_t *chain,
545                               const int num)
546{
547    int added = 0;
548    int ret = gnutls_x509_trust_list_init(tl, num);
549
550    if (ret == GNUTLS_E_SUCCESS)
551        added = gnutls_x509_trust_list_add_cas(*tl, chain, num, 0);
552
553    if (added != num)
554        ret = GNUTLS_E_CERTIFICATE_ERROR;
555
556    /* Clean up trust list in case of error */
557    if (ret != GNUTLS_E_SUCCESS)
558        gnutls_x509_trust_list_deinit(*tl, 0);
559
560    return ret;
561}
[fad7695]562
563
564
565apr_status_t mgs_cleanup_trust_list(void *data)
566{
567    gnutls_x509_trust_list_t *tl = (gnutls_x509_trust_list_t *) data;
568    gnutls_x509_trust_list_deinit(*tl, 0);
569    return APR_SUCCESS;
570}
571
572
573
[fd6bb19]574apr_uri_t * mgs_cert_get_ocsp_uri(apr_pool_t *p, gnutls_x509_crt_t cert)
575{
576    apr_pool_t *tmp;
577    apr_status_t rv = apr_pool_create(&tmp, p);
578    if (rv != APR_SUCCESS)
579        return NULL;
580
581    apr_uri_t *ocsp_uri = NULL;
582
583    int ret = GNUTLS_E_SUCCESS;
584    /* search authority info access for OCSP URI */
585    for (int seq = 0; ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; seq++)
586    {
587        gnutls_datum_t ocsp_access_data;
588        ret = gnutls_x509_crt_get_authority_info_access(cert, seq,
589                                                        GNUTLS_IA_OCSP_URI,
590                                                        &ocsp_access_data,
591                                                        NULL);
592        if (ret == GNUTLS_E_SUCCESS)
593        {
594            /* create NULL terminated string */
595            char *ocsp_str =
596                apr_pstrndup(tmp, (const char*) ocsp_access_data.data,
597                             ocsp_access_data.size);
598            gnutls_free(ocsp_access_data.data);
599
600            ocsp_uri = apr_palloc(p, sizeof(apr_uri_t));
601            rv = apr_uri_parse(p, ocsp_str, ocsp_uri);
602            if (rv == APR_SUCCESS)
603                break;
604            else
605                ocsp_uri = NULL;
606        }
607    }
608
609    apr_pool_destroy(tmp);
610    return ocsp_uri;
611}
612
613
614
[fad7695]615/*
616 * Like in the general post_config hook the HTTP status codes for
617 * errors are just for fun. What matters is "neither OK nor DECLINED"
618 * to denote an error.
619 */
[fd6bb19]620int mgs_ocsp_post_config_server(apr_pool_t *pconf,
621                                apr_pool_t *ptemp __attribute__((unused)),
622                                server_rec *server)
[fad7695]623{
[fd6bb19]624    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
625        ap_get_module_config(server->module_config, &gnutls_module);
[fad7695]626
627    if (sc->certs_x509_chain_num < 2)
628    {
629        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, server,
630                     "OCSP stapling is enabled but no CA certificate "
[4ae7810]631                     "available for %s:%d, make sure it is included in "
632                     "GnuTLSCertificateFile!",
633                     server->server_hostname, server->addrs->host_port);
[fad7695]634        return HTTP_NOT_FOUND;
635    }
[fd6bb19]636
[cc74801e]637    sc->ocsp = apr_palloc(pconf, sizeof(struct mgs_ocsp_data));
[fd6bb19]638
[a372379]639    sc->ocsp->fingerprint =
640        mgs_get_cert_fingerprint(pconf, sc->certs_x509_crt_chain[0]);
641    if (sc->ocsp->fingerprint.data == NULL)
642        return HTTP_INTERNAL_SERVER_ERROR;
643
[cc74801e]644    sc->ocsp->uri = mgs_cert_get_ocsp_uri(pconf,
645                                          sc->certs_x509_crt_chain[0]);
646
647    sc->ocsp->trust = apr_palloc(pconf,
648                                 sizeof(gnutls_x509_trust_list_t));
[fad7695]649     /* Only the direct issuer may sign the OCSP response or an OCSP
650      * signer. */
[cc74801e]651    int ret = mgs_create_ocsp_trust_list(sc->ocsp->trust,
[fad7695]652                                         &(sc->certs_x509_crt_chain[1]),
653                                         1);
654    if (ret != GNUTLS_E_SUCCESS)
655    {
656        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, server,
657                     "Could not create OCSP trust list: %s (%d)",
658                     gnutls_strerror(ret), ret);
659        return HTTP_INTERNAL_SERVER_ERROR;
660    }
661    /* deinit trust list when the config pool is destroyed */
[cc74801e]662    apr_pool_cleanup_register(pconf, sc->ocsp->trust,
[fad7695]663                              mgs_cleanup_trust_list,
664                              apr_pool_cleanup_null);
665
666    return OK;
667}
Note: See TracBrowser for help on using the repository browser.