source: mod_gnutls/src/gnutls_proxy.c @ 68b5156

debian/masterproxy-ticket
Last change on this file since 68b5156 was 68b5156, checked in by Fiona Klute <fiona.klute@…>, 20 months ago

Move proxy-only functions from gnutls_hooks.c to a dedicated file

  • Property mode set to 100644
File size: 10.8 KB
Line 
1/*
2 *  Copyright 2015-2018 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 "mod_gnutls.h"
18#include "gnutls_proxy.h"
19#include "gnutls_util.h"
20
21#include <gnutls/gnutls.h>
22
23/*
24 * Callback to check the server certificate for proxy HTTPS
25 * connections, to be used with
26 * gnutls_certificate_set_verify_function.
27
28 * Returns: 0 if certificate check was successful (certificate
29 * trusted), non-zero otherwise (error during check or untrusted
30 * certificate).
31 */
32static int gtls_check_server_cert(gnutls_session_t session)
33{
34    mgs_handle_t *ctxt = (mgs_handle_t *) gnutls_session_get_ptr(session);
35    unsigned int status;
36
37    /* Get peer hostname from a note left by mod_proxy */
38    const char *peer_hostname =
39        apr_table_get(ctxt->c->notes, PROXY_SNI_NOTE);
40    if (peer_hostname == NULL)
41        ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, ctxt->c,
42                      "%s: " PROXY_SNI_NOTE " NULL, cannot check "
43                      "peer's hostname", __func__);
44
45    /* Verify certificate, including hostname match. Should
46     * peer_hostname be NULL for some reason, the name is not
47     * checked. */
48    int err = gnutls_certificate_verify_peers3(session, peer_hostname,
49                                               &status);
50    if (err != GNUTLS_E_SUCCESS)
51    {
52        ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, ctxt->c,
53                      "%s: server certificate check failed: %s (%d)",
54                      __func__, gnutls_strerror(err), err);
55        return err;
56    }
57
58    if (status == 0)
59        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, ctxt->c,
60                      "%s: server certificate is trusted.",
61                      __func__);
62    else
63    {
64        gnutls_datum_t out;
65        /* GNUTLS_CRT_X509: ATM, only X509 is supported for proxy
66         * certs 0: according to function API, the last argument
67         * should be 0 */
68        err = gnutls_certificate_verification_status_print(status,
69                                                           GNUTLS_CRT_X509,
70                                                           &out, 0);
71        if (err != GNUTLS_E_SUCCESS)
72            ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, ctxt->c,
73                          "%s: server verify print failed: %s (%d)",
74                          __func__, gnutls_strerror(err), err);
75        else
76            ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, ctxt->c,
77                          "%s: %s",
78                          __func__, out.data);
79        gnutls_free(out.data);
80    }
81
82    return status;
83}
84
85
86
87static apr_status_t cleanup_proxy_x509_credentials(void *arg)
88{
89    mgs_srvconf_rec *sc = (mgs_srvconf_rec *) arg;
90
91    if (sc->proxy_x509_creds)
92    {
93        /* This implicitly releases the associated trust list
94         * sc->proxy_x509_tl, too. */
95        gnutls_certificate_free_credentials(sc->proxy_x509_creds);
96        sc->proxy_x509_creds = NULL;
97        sc->proxy_x509_tl = NULL;
98    }
99
100    if (sc->anon_client_creds)
101    {
102        gnutls_anon_free_client_credentials(sc->anon_client_creds);
103        sc->anon_client_creds = NULL;
104    }
105
106    /* Deinit proxy priorities only if set from
107     * sc->proxy_priorities_str. Otherwise the server is using the
108     * default global priority cache, which must not be deinitialized
109     * here. */
110    if (sc->proxy_priorities_str && sc->proxy_priorities)
111    {
112        gnutls_priority_deinit(sc->proxy_priorities);
113        sc->proxy_priorities = NULL;
114    }
115
116    return APR_SUCCESS;
117}
118
119
120
121apr_status_t load_proxy_x509_credentials(apr_pool_t *pconf,
122                                         apr_pool_t *ptemp,
123                                         server_rec *s)
124{
125    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
126        ap_get_module_config(s->module_config, &gnutls_module);
127
128    if (sc == NULL)
129        return APR_EGENERAL;
130
131    apr_status_t ret = APR_EINIT;
132    int err = GNUTLS_E_SUCCESS;
133
134    /* Cleanup function for the GnuTLS structures allocated below */
135    apr_pool_cleanup_register(pconf, sc, cleanup_proxy_x509_credentials,
136                              apr_pool_cleanup_null);
137
138    /* Function pool, gets destroyed before exit. */
139    apr_pool_t *pool;
140    ret = apr_pool_create(&pool, ptemp);
141    if (ret != APR_SUCCESS)
142    {
143        ap_log_error(APLOG_MARK, APLOG_ERR, ret, s,
144                     "%s: failed to allocate function memory pool.", __func__);
145        return ret;
146    }
147
148    /* allocate credentials structures */
149    err = gnutls_certificate_allocate_credentials(&sc->proxy_x509_creds);
150    if (err != GNUTLS_E_SUCCESS)
151    {
152        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
153                     "%s: Failed to initialize proxy credentials: (%d) %s",
154                     __func__, err, gnutls_strerror(err));
155        return APR_EGENERAL;
156    }
157    err = gnutls_anon_allocate_client_credentials(&sc->anon_client_creds);
158    if (err != GNUTLS_E_SUCCESS)
159    {
160        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
161                     "%s: Failed to initialize anon credentials for proxy: "
162                     "(%d) %s", __func__, err, gnutls_strerror(err));
163        return APR_EGENERAL;
164    }
165
166    /* Check if the proxy priorities have been set, fail immediately
167     * if not */
168    if (sc->proxy_priorities_str == NULL)
169    {
170        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
171                     "No GnuTLSProxyPriorities directive for host '%s:%d', "
172                     "using default '%s'.",
173                     s->server_hostname, s->addrs->host_port,
174                     MGS_DEFAULT_PRIORITY);
175        sc->proxy_priorities = mgs_get_default_prio();
176    }
177    else
178    {
179        /* parse proxy priorities */
180        const char *err_pos = NULL;
181        err = gnutls_priority_init(&sc->proxy_priorities,
182                                   sc->proxy_priorities_str, &err_pos);
183        if (err != GNUTLS_E_SUCCESS)
184        {
185            if (ret == GNUTLS_E_INVALID_REQUEST)
186                ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
187                             "%s: Syntax error parsing proxy priorities "
188                             "string at: %s",
189                             __func__, err_pos);
190            else
191                ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
192                             "Error setting proxy priorities: %s (%d)",
193                             gnutls_strerror(err), err);
194            ret = APR_EGENERAL;
195        }
196    }
197
198    /* load certificate and key for client auth, if configured */
199    if (sc->proxy_x509_key_file && sc->proxy_x509_cert_file)
200    {
201        char* cert_file = ap_server_root_relative(pool,
202                                                  sc->proxy_x509_cert_file);
203        char* key_file = ap_server_root_relative(pool,
204                                                 sc->proxy_x509_key_file);
205        err = gnutls_certificate_set_x509_key_file(sc->proxy_x509_creds,
206                                                   cert_file,
207                                                   key_file,
208                                                   GNUTLS_X509_FMT_PEM);
209        if (err != GNUTLS_E_SUCCESS)
210        {
211            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
212                         "%s: loading proxy client credentials failed: %s (%d)",
213                         __func__, gnutls_strerror(err), err);
214            ret = APR_EGENERAL;
215        }
216    }
217    else if (!sc->proxy_x509_key_file && sc->proxy_x509_cert_file)
218    {
219        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
220                     "%s: proxy key file not set!", __func__);
221        ret = APR_EGENERAL;
222    }
223    else if (!sc->proxy_x509_cert_file && sc->proxy_x509_key_file)
224    {
225        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
226                     "%s: proxy certificate file not set!", __func__);
227        ret = APR_EGENERAL;
228    }
229    else
230        /* if both key and cert are NULL, client auth is not used */
231        ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
232                     "%s: no client credentials for proxy", __func__);
233
234    /* must be set if the server certificate is to be checked */
235    if (sc->proxy_x509_ca_file)
236    {
237        /* initialize the trust list */
238        err = gnutls_x509_trust_list_init(&sc->proxy_x509_tl, 0);
239        if (err != GNUTLS_E_SUCCESS)
240        {
241            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
242                         "%s: gnutls_x509_trust_list_init failed: %s (%d)",
243                         __func__, gnutls_strerror(err), err);
244            ret = APR_EGENERAL;
245        }
246
247        char* ca_file = ap_server_root_relative(pool,
248                                                sc->proxy_x509_ca_file);
249        /* if no CRL is used, sc->proxy_x509_crl_file is NULL */
250        char* crl_file = NULL;
251        if (sc->proxy_x509_crl_file)
252            crl_file = ap_server_root_relative(pool,
253                                               sc->proxy_x509_crl_file);
254
255        /* returns number of loaded elements */
256        err = gnutls_x509_trust_list_add_trust_file(sc->proxy_x509_tl,
257                                                    ca_file,
258                                                    crl_file,
259                                                    GNUTLS_X509_FMT_PEM,
260                                                    0 /* tl_flags */,
261                                                    0 /* tl_vflags */);
262        if (err > 0)
263            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
264                         "%s: proxy CA trust list: %d structures loaded",
265                         __func__, err);
266        else if (err == 0)
267            ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
268                         "%s: proxy CA trust list is empty (%d)",
269                         __func__, err);
270        else /* err < 0 */
271        {
272            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
273                         "%s: error loading proxy CA trust list: %s (%d)",
274                         __func__, gnutls_strerror(err), err);
275            ret = APR_EGENERAL;
276        }
277
278        /* attach trust list to credentials */
279        gnutls_certificate_set_trust_list(sc->proxy_x509_creds,
280                                          sc->proxy_x509_tl, 0);
281    }
282    else
283        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s,
284                     "%s: no CA trust list for proxy connections, "
285                     "TLS connections will fail!", __func__);
286
287    gnutls_certificate_set_verify_function(sc->proxy_x509_creds,
288                                           gtls_check_server_cert);
289    apr_pool_destroy(pool);
290    return ret;
291}
Note: See TracBrowser for help on using the repository browser.