source: mod_gnutls/src/mod_gnutls.c @ 3c6645b

debian/master
Last change on this file since 3c6645b was de3fad3, checked in by Fiona Klute <fiona.klute@…>, 14 months ago

Require handshake and request to use the same server

The new check prevents clients from establishing a TLS connection to
one virtual host and then requesting data from another. This is
particularly important for servers using TLS client authentication as
the only means of access control, because the server context for
certificate validation is selected based on the TLS connection.

  • Property mode set to 100644
File size: 14.2 KB
Line 
1/*
2 *  Copyright 2004-2005 Paul Querna
3 *  Copyright 2008, 2014 Nikos Mavrogiannopoulos
4 *  Copyright 2011 Dash Shendy
5 *  Copyright 2015-2018 Fiona Klute
6 *
7 *  Licensed under the Apache License, Version 2.0 (the "License");
8 *  you may not use this file except in compliance with the License.
9 *  You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 *  Unless required by applicable law or agreed to in writing, software
14 *  distributed under the License is distributed on an "AS IS" BASIS,
15 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 *  See the License for the specific language governing permissions and
17 *  limitations under the License.
18 */
19
20#include "mod_gnutls.h"
21#include "gnutls_config.h"
22#include "gnutls_ocsp.h"
23#include "gnutls_util.h"
24
25#ifdef APLOG_USE_MODULE
26APLOG_USE_MODULE(gnutls);
27#endif
28
29int ssl_engine_set(conn_rec *c,
30                   ap_conf_vector_t *dir_conf __attribute__((unused)),
31                   int proxy, int enable);
32
33#define MOD_HTTP2 "mod_http2.c"
34#define MOD_WATCHDOG "mod_watchdog.c"
35static const char * const mod_proxy[] = { "mod_proxy.c", NULL };
36static const char * const mod_http2[] = { MOD_HTTP2, NULL };
37static const char * const mod_watchdog[] = { MOD_WATCHDOG, NULL };
38
39static void gnutls_hooks(apr_pool_t * p __attribute__((unused)))
40{
41    /* Watchdog callbacks must be configured before post_config of
42     * mod_watchdog runs, or the watchdog won't be started. Similarly,
43     * our child_init hook must run before mod_watchdog's because our
44     * watchdog threads are started there and need some child-specific
45     * resources. */
46    static const char * const post_conf_succ[] =
47        { MOD_HTTP2, MOD_WATCHDOG, NULL };
48    ap_hook_post_config(mgs_hook_post_config, mod_proxy, post_conf_succ,
49                        APR_HOOK_MIDDLE);
50    /* HTTP Scheme Hook */
51    ap_hook_http_scheme(mgs_hook_http_scheme, NULL, NULL, APR_HOOK_MIDDLE);
52    /* Default Port Hook */
53    ap_hook_default_port(mgs_hook_default_port, NULL, NULL, APR_HOOK_MIDDLE);
54    /* Pre-Connect Hook */
55    ap_hook_pre_connection(mgs_hook_pre_connection, mod_http2, NULL,
56                           APR_HOOK_MIDDLE);
57    ap_hook_process_connection(mgs_hook_process_connection,
58                               NULL, mod_http2, APR_HOOK_MIDDLE);
59    /* Pre-Config Hook */
60    ap_hook_pre_config(mgs_hook_pre_config, NULL, NULL,
61                       APR_HOOK_MIDDLE);
62    /* Child-Init Hook */
63    ap_hook_child_init(mgs_hook_child_init, NULL, mod_watchdog,
64                       APR_HOOK_MIDDLE);
65    /* Authentication Hook */
66    ap_hook_access_checker(mgs_hook_authz, NULL, NULL,
67                           APR_HOOK_REALLY_FIRST);
68    /* Fixups Hook */
69    ap_hook_fixups(mgs_hook_fixups, NULL, NULL, APR_HOOK_REALLY_FIRST);
70
71    /* Request hook: Check if TLS connection and request host match */
72    ap_hook_post_read_request(mgs_req_vhost_check, NULL, NULL, APR_HOOK_MIDDLE);
73
74    /* TODO: HTTP Upgrade Filter */
75    /* ap_register_output_filter ("UPGRADE_FILTER",
76     *          ssl_io_filter_Upgrade, NULL, AP_FTYPE_PROTOCOL + 5);
77     */
78
79    /* Input Filter */
80    ap_register_input_filter(GNUTLS_INPUT_FILTER_NAME, mgs_filter_input,
81                             NULL, AP_FTYPE_CONNECTION + 5);
82    /* Output Filter */
83    ap_register_output_filter(GNUTLS_OUTPUT_FILTER_NAME, mgs_filter_output,
84                              NULL, AP_FTYPE_CONNECTION + 5);
85
86    /* mod_proxy calls these functions */
87    APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable);
88    APR_REGISTER_OPTIONAL_FN(ssl_engine_disable);
89    APR_REGISTER_OPTIONAL_FN(ssl_engine_set);
90
91    /* mod_rewrite calls this function to detect HTTPS */
92    APR_REGISTER_OPTIONAL_FN(ssl_is_https);
93    /* some modules look up TLS-related variables */
94    APR_REGISTER_OPTIONAL_FN(ssl_var_lookup);
95}
96
97
98
99/**
100 * Get the connection context, resolving to a master connection if
101 * any.
102 *
103 * @param c the connection handle
104 *
105 * @return mod_gnutls session context, might be `NULL`
106 */
107mgs_handle_t* get_effective_gnutls_ctxt(conn_rec *c)
108{
109    mgs_handle_t *ctxt = (mgs_handle_t *)
110        ap_get_module_config(c->conn_config, &gnutls_module);
111    if (!(ctxt != NULL && ctxt->enabled) && (c->master != NULL))
112    {
113        ctxt = (mgs_handle_t *)
114            ap_get_module_config(c->master->conn_config, &gnutls_module);
115    }
116    return ctxt;
117}
118
119
120
121/**
122 * mod_rewrite calls this function to fill %{HTTPS}.
123 *
124 * @param c the connection to check
125 * @return non-zero value if HTTPS is in use, zero if not
126 */
127int ssl_is_https(conn_rec *c)
128{
129    mgs_handle_t *ctxt = get_effective_gnutls_ctxt(c);
130    mgs_srvconf_rec *sc = (mgs_srvconf_rec *)
131        ap_get_module_config(c->base_server->module_config, &gnutls_module);
132
133    if(sc->enabled == GNUTLS_ENABLED_FALSE
134       || ctxt == NULL
135       || ctxt->enabled == GNUTLS_ENABLED_FALSE)
136    {
137        /* SSL/TLS Disabled or Plain HTTP Connection Detected */
138        return 0;
139    }
140    /* Connection is Using SSL/TLS */
141    return 1;
142}
143
144
145
146/**
147 * Return variables describing the current TLS session (if any).
148 *
149 * mod_ssl doc for this function: "This function must remain safe to
150 * use for a non-SSL connection." mod_http2 uses it to check if an
151 * acceptable TLS session is used.
152 */
153char* ssl_var_lookup(apr_pool_t *p, server_rec *s __attribute__((unused)),
154                     conn_rec *c, request_rec *r, char *var)
155{
156    /*
157     * When no pool is given try to find one
158     */
159    if (p == NULL) {
160        if (r != NULL)
161            p = r->pool;
162        else if (c != NULL)
163            p = c->pool;
164        else
165            return NULL;
166    }
167
168    if (strcmp(var, "HTTPS") == 0)
169    {
170        if (c != NULL && ssl_is_https(c))
171            return "on";
172        else
173            return "off";
174    }
175
176    mgs_handle_t *ctxt = get_effective_gnutls_ctxt(c);
177
178    /* TLS parameters are empty if there is no session */
179    if (ctxt == NULL || ctxt->c == NULL)
180        return NULL;
181
182    if (strcmp(var, "SSL_PROTOCOL") == 0)
183        return apr_pstrdup(p, gnutls_protocol_get_name(gnutls_protocol_get_version(ctxt->session)));
184
185    if (strcmp(var, "SSL_CIPHER") == 0)
186        return apr_pstrdup(p, gnutls_cipher_suite_get_name(gnutls_kx_get(ctxt->session),
187                                                           gnutls_cipher_get(ctxt->session),
188                                                           gnutls_mac_get(ctxt->session)));
189
190    /* mod_ssl supports a LOT more variables */
191    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, c,
192                  "unsupported variable requested: '%s'",
193                  var);
194
195    return NULL;
196}
197
198
199
200/**
201 * In Apache versions from 2.4.33 mod_proxy uses this function to set
202 * up its client connections. Note that mod_gnutls does not (yet)
203 * implement per directory configuration for such connections.
204 *
205 * @param c the connection
206 * @param dir_conf per directory configuration, unused for now
207 * @param proxy Is this a proxy connection?
208 * @param enable Should TLS be enabled on this connection?
209 *
210 * @param `true` (1) if successful, `false` (0) otherwise
211 */
212int ssl_engine_set(conn_rec *c,
213                   ap_conf_vector_t *dir_conf __attribute__((unused)),
214                   int proxy, int enable)
215{
216    mgs_handle_t *ctxt = init_gnutls_ctxt(c);
217
218    /* If TLS proxy has been requested, check if support is enabled
219     * for the server */
220    if (proxy && (ctxt->sc->proxy_enabled != GNUTLS_ENABLED_TRUE))
221    {
222        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
223                      "%s: mod_proxy requested TLS proxy, but not enabled "
224                      "for %s:%d", __func__,
225                      ctxt->c->base_server->server_hostname,
226                      ctxt->c->base_server->addrs->host_port);
227        return 0;
228    }
229
230    if (proxy)
231        ctxt->is_proxy = GNUTLS_ENABLED_TRUE;
232    else
233        ctxt->is_proxy = GNUTLS_ENABLED_FALSE;
234
235    if (enable)
236        ctxt->enabled = GNUTLS_ENABLED_TRUE;
237    else
238        ctxt->enabled = GNUTLS_ENABLED_FALSE;
239
240    return 1;
241}
242
243int ssl_engine_disable(conn_rec *c)
244{
245    return ssl_engine_set(c, NULL, 0, 0);
246}
247
248int ssl_proxy_enable(conn_rec *c)
249{
250    return ssl_engine_set(c, NULL, 1, 1);
251}
252
253#define OPENPGP_REMOVED "OpenPGP support has been removed."
254
255static const command_rec mgs_config_cmds[] = {
256    AP_INIT_FLAG("GnuTLSProxyEngine", mgs_set_proxy_engine,
257    NULL,
258    RSRC_CONF | OR_AUTHCFG,
259    "Enable TLS Proxy Engine"),
260    AP_INIT_TAKE1("GnuTLSP11Module", mgs_set_p11_module,
261    NULL,
262    RSRC_CONF,
263    "Load this specific PKCS #11 provider library"),
264    AP_INIT_RAW_ARGS("GnuTLSPIN", mgs_set_pin,
265    NULL,
266    RSRC_CONF,
267    "The PIN to use in case of encrypted keys or PKCS #11 tokens."),
268    AP_INIT_RAW_ARGS("GnuTLSSRKPIN", mgs_set_srk_pin,
269    NULL,
270    RSRC_CONF,
271    "The SRK PIN to use in case of TPM keys."),
272    AP_INIT_TAKE1("GnuTLSClientVerify", mgs_set_client_verify,
273    NULL,
274    RSRC_CONF | OR_AUTHCFG,
275    "Set Verification Requirements of the Client Certificate"),
276    AP_INIT_TAKE1("GnuTLSClientVerifyMethod", mgs_set_client_verify_method,
277    NULL,
278    RSRC_CONF,
279    "Set Verification Method of the Client Certificate"),
280    AP_INIT_TAKE1("GnuTLSClientCAFile", mgs_set_client_ca_file,
281    NULL,
282    RSRC_CONF,
283    "Set the CA File to verify Client Certificates"),
284    AP_INIT_TAKE1("GnuTLSX509CAFile", mgs_set_client_ca_file,
285    NULL,
286    RSRC_CONF,
287    "Set the CA File to verify Client Certificates"),
288    AP_INIT_TAKE1("GnuTLSDHFile", mgs_set_dh_file,
289    NULL,
290    RSRC_CONF,
291    "Set the file to read Diffie Hellman parameters from"),
292    AP_INIT_TAKE1("GnuTLSCertificateFile", mgs_set_cert_file,
293    NULL,
294    RSRC_CONF,
295    "TLS Server X509 Certificate file"),
296    AP_INIT_TAKE1("GnuTLSKeyFile", mgs_set_key_file,
297    NULL,
298    RSRC_CONF,
299    "TLS Server X509 Private Key file"),
300    AP_INIT_TAKE1("GnuTLSX509CertificateFile", mgs_set_cert_file,
301    NULL,
302    RSRC_CONF,
303    "TLS Server X509 Certificate file"),
304    AP_INIT_TAKE1("GnuTLSX509KeyFile", mgs_set_key_file,
305    NULL,
306    RSRC_CONF,
307    "TLS Server X509 Private Key file"),
308#ifdef ENABLE_SRP
309    AP_INIT_TAKE1("GnuTLSSRPPasswdFile", mgs_set_srp_tpasswd_file,
310    NULL,
311    RSRC_CONF,
312    "TLS Server SRP Password Conf file"),
313    AP_INIT_TAKE1("GnuTLSSRPPasswdConfFile",
314    mgs_set_srp_tpasswd_conf_file,
315    NULL,
316    RSRC_CONF,
317    "TLS Server SRP Parameters file"),
318#endif
319    AP_INIT_TAKE1("GnuTLSCacheTimeout", mgs_set_timeout,
320    NULL,
321    RSRC_CONF,
322    "Cache Timeout"),
323    AP_INIT_TAKE12("GnuTLSCache", mgs_set_cache,
324    NULL,
325    RSRC_CONF,
326    "Session Cache Configuration"),
327    AP_INIT_FLAG("GnuTLSSessionTickets", mgs_set_tickets,
328    NULL,
329    RSRC_CONF,
330    "Session Tickets Configuration"),
331    AP_INIT_RAW_ARGS("GnuTLSPriorities", mgs_set_priorities,
332    NULL,
333    RSRC_CONF,
334    "The priorities to enable (ciphers, Key exchange, macs, compression)."),
335    AP_INIT_FLAG("GnuTLSEnable", mgs_set_enabled,
336    NULL,
337    RSRC_CONF,
338    "Whether this server has GnuTLS Enabled. Default: Off"),
339    AP_INIT_TAKE1("GnuTLSExportCertificates",
340    mgs_set_export_certificates_size,
341    NULL,
342    RSRC_CONF,
343    "Max size to export PEM encoded certificates to CGIs (or off to disable). Default: off"),
344    AP_INIT_TAKE1("GnuTLSProxyKeyFile", mgs_store_cred_path,
345    NULL,
346    RSRC_CONF,
347    "X509 client private file for proxy connections"),
348    AP_INIT_TAKE1("GnuTLSProxyCertificateFile", mgs_store_cred_path,
349    NULL,
350    RSRC_CONF,
351    "X509 client certificate file for proxy connections"),
352    AP_INIT_TAKE1("GnuTLSProxyCAFile", mgs_store_cred_path,
353    NULL,
354    RSRC_CONF,
355    "X509 trusted CA file for proxy connections"),
356    AP_INIT_TAKE1("GnuTLSProxyCRLFile", mgs_store_cred_path,
357    NULL,
358    RSRC_CONF,
359    "X509 CRL file for proxy connections"),
360    AP_INIT_RAW_ARGS("GnuTLSProxyPriorities", mgs_set_priorities,
361    NULL,
362    RSRC_CONF,
363    "The priorities to enable for proxy connections (ciphers, key exchange, "
364    "MACs, compression)."),
365    AP_INIT_FLAG("GnuTLSOCSPStapling", mgs_ocsp_stapling_enable,
366                 NULL, RSRC_CONF,
367                 "Enable OCSP stapling"),
368    AP_INIT_FLAG("GnuTLSOCSPAutoRefresh", mgs_set_ocsp_auto_refresh,
369                 NULL, RSRC_CONF,
370                 "Regularly refresh cached OCSP response independent "
371                 "of TLS handshakes?"),
372    AP_INIT_TAKE12("GnuTLSOCSPCache", mgs_set_cache,
373                   NULL,
374                   RSRC_CONF,
375                  "OCSP Cache Configuration"),
376    AP_INIT_FLAG("GnuTLSOCSPCheckNonce", mgs_set_ocsp_check_nonce,
377                 NULL, RSRC_CONF,
378                 "Check nonce in OCSP responses?"),
379    AP_INIT_TAKE1("GnuTLSOCSPResponseFile", mgs_store_ocsp_response_path,
380                  NULL, RSRC_CONF,
381                  "Read OCSP response for stapling from this file instead "
382                  "of sending a request over HTTP (must be updated "
383                  "externally)"),
384    AP_INIT_TAKE1("GnuTLSOCSPCacheTimeout", mgs_set_timeout,
385                  NULL, RSRC_CONF,
386                  "Cache timeout for OCSP responses"),
387    AP_INIT_TAKE1("GnuTLSOCSPFailureTimeout", mgs_set_timeout,
388                  NULL, RSRC_CONF,
389                  "Wait this many seconds before retrying a failed OCSP "
390                  "request"),
391    AP_INIT_TAKE1("GnuTLSOCSPFuzzTime", mgs_set_timeout,
392                  NULL, RSRC_CONF,
393                  "Update cached OCSP response up to this many seconds "
394                  "before it expires, if GnuTLSOCSPAutoRefresh is enabled."),
395    AP_INIT_TAKE1("GnuTLSOCSPSocketTimeout", mgs_set_timeout,
396                  NULL, RSRC_CONF,
397                  "Socket timeout for OCSP requests"),
398    AP_INIT_RAW_ARGS("GnuTLSPGPKeyringFile",
399                     ap_set_deprecated, NULL, OR_ALL, OPENPGP_REMOVED),
400    AP_INIT_RAW_ARGS("GnuTLSPGPCertificateFile",
401                     ap_set_deprecated, NULL, OR_ALL, OPENPGP_REMOVED),
402    AP_INIT_RAW_ARGS("GnuTLSPGPKeyFile",
403                     ap_set_deprecated, NULL, OR_ALL, OPENPGP_REMOVED),
404#ifdef __clang__
405    /* Workaround for this clang bug:
406     * https://llvm.org/bugs/show_bug.cgi?id=21689 */
407    {},
408#else
409    { NULL },
410#endif
411};
412
413module AP_MODULE_DECLARE_DATA gnutls_module = {
414    STANDARD20_MODULE_STUFF,
415    .create_dir_config = mgs_config_dir_create,
416    .merge_dir_config = mgs_config_dir_merge,
417    .create_server_config = mgs_config_server_create,
418    .merge_server_config = mgs_config_server_merge,
419    .cmds = mgs_config_cmds,
420    .register_hooks = gnutls_hooks
421};
Note: See TracBrowser for help on using the repository browser.