diff options
Diffstat (limited to 'modules/tls/mod_tls.c')
-rw-r--r-- | modules/tls/mod_tls.c | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/modules/tls/mod_tls.c b/modules/tls/mod_tls.c new file mode 100644 index 0000000..9d79521 --- /dev/null +++ b/modules/tls/mod_tls.c @@ -0,0 +1,288 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <assert.h> +#include <apr_optional.h> +#include <apr_strings.h> + +#include <mpm_common.h> +#include <httpd.h> +#include <http_core.h> +#include <http_connection.h> +#include <http_log.h> +#include <http_protocol.h> +#include <http_ssl.h> +#include <http_request.h> +#include <ap_socache.h> + +#include <rustls.h> + +#include "mod_tls.h" +#include "tls_conf.h" +#include "tls_core.h" +#include "tls_cache.h" +#include "tls_proto.h" +#include "tls_filter.h" +#include "tls_var.h" +#include "tls_version.h" + +#include "mod_proxy.h" + +static void tls_hooks(apr_pool_t *pool); + +AP_DECLARE_MODULE(tls) = { + STANDARD20_MODULE_STUFF, + tls_conf_create_dir, /* create per dir config */ + tls_conf_merge_dir, /* merge per dir config */ + tls_conf_create_svr, /* create per server config */ + tls_conf_merge_svr, /* merge per server config (inheritance) */ + tls_conf_cmds, /* command handlers */ + tls_hooks, +#if defined(AP_MODULE_FLAG_NONE) + AP_MODULE_FLAG_ALWAYS_MERGE +#endif +}; + +static const char* crustls_version(apr_pool_t *p) +{ + struct rustls_str rversion; + + rversion = rustls_version(); + return apr_pstrndup(p, rversion.data, rversion.len); +} + +static int tls_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) +{ + tls_proto_pre_config(pconf, ptemp); + tls_cache_pre_config(pconf, plog, ptemp); + return OK; +} + +static apr_status_t tls_post_config(apr_pool_t *p, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *s) +{ + const char *tls_init_key = "mod_tls_init_counter"; + tls_conf_server_t *sc; + void *data = NULL; + + (void)plog; + sc = tls_conf_server_get(s); + assert(sc); + assert(sc->global); + sc->global->module_version = "mod_tls/" MOD_TLS_VERSION; + sc->global->crustls_version = crustls_version(p); + + apr_pool_userdata_get(&data, tls_init_key, s->process->pool); + if (data == NULL) { + /* At the first start, httpd makes a config check dry run + * to see if the config is ok in principle. + */ + ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, "post config dry run"); + apr_pool_userdata_set((const void *)1, tls_init_key, + apr_pool_cleanup_null, s->process->pool); + } + else { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(10365) + "%s (%s), initializing...", + sc->global->module_version, + sc->global->crustls_version); + } + + return tls_core_init(p, ptemp, s); +} + +static apr_status_t tls_post_proxy_config( + apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) +{ + tls_conf_server_t *sc = tls_conf_server_get(s); + (void)plog; + sc->global->mod_proxy_post_config_done = 1; + return tls_core_init(p, ptemp, s); +} + +#if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) +static int tls_ssl_outgoing(conn_rec *c, ap_conf_vector_t *dir_conf, int enable_ssl) +{ + /* we are not handling proxy connections - for now */ + tls_core_conn_bind(c, dir_conf); + if (enable_ssl && tls_core_setup_outgoing(c) == OK) { + ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, c->base_server, + "accepted ssl_bind_outgoing(enable=%d) for %s", + enable_ssl, c->base_server->server_hostname); + return OK; + } + tls_core_conn_disable(c); + ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, c->base_server, + "declined ssl_bind_outgoing(enable=%d) for %s", + enable_ssl, c->base_server->server_hostname); + return DECLINED; +} + +#else /* #if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) */ + +APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *)); +APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); +APR_DECLARE_OPTIONAL_FN(int, ssl_engine_set, (conn_rec *, + ap_conf_vector_t *, + int proxy, int enable)); +static APR_OPTIONAL_FN_TYPE(ssl_engine_set) *module_ssl_engine_set; + +static int ssl_engine_set( + conn_rec *c, ap_conf_vector_t *dir_conf, int proxy, int enable) +{ + ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, c->base_server, + "ssl_engine_set(proxy=%d, enable=%d) for %s", + proxy, enable, c->base_server->server_hostname); + tls_core_conn_bind(c, dir_conf); + if (enable && tls_core_setup_outgoing(c) == OK) { + if (module_ssl_engine_set) { + module_ssl_engine_set(c, dir_conf, proxy, 0); + } + return 1; + } + if (proxy || !enable) { + /* we are not handling proxy connections - for now */ + tls_core_conn_disable(c); + } + if (module_ssl_engine_set) { + return module_ssl_engine_set(c, dir_conf, proxy, enable); + } + return 0; +} + +static int ssl_proxy_enable(conn_rec *c) +{ + return ssl_engine_set(c, NULL, 1, 1); +} + +static int ssl_engine_disable(conn_rec *c) +{ + return ssl_engine_set(c, NULL, 0, 0); +} + +static apr_status_t tls_post_config_proxy_ssl( + apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) +{ + if (1) { + const char *tls_init_key = "mod_tls_proxy_ssl_counter"; + void *data = NULL; + APR_OPTIONAL_FN_TYPE(ssl_engine_set) *fn_ssl_engine_set; + + (void)p; + (void)plog; + (void)ptemp; + apr_pool_userdata_get(&data, tls_init_key, s->process->pool); + if (data == NULL) { + /* At the first start, httpd makes a config check dry run + * to see if the config is ok in principle. + */ + apr_pool_userdata_set((const void *)1, tls_init_key, + apr_pool_cleanup_null, s->process->pool); + return APR_SUCCESS; + } + + /* mod_ssl (if so loaded, has registered its optional functions. + * When mod_proxy runs in post-config, it looks up those functions and uses + * them to manipulate SSL status for backend connections. + * We provide our own implementations to avoid becoming active on such + * connections for now. + * */ + fn_ssl_engine_set = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_set); + module_ssl_engine_set = (fn_ssl_engine_set + && fn_ssl_engine_set != ssl_engine_set)? fn_ssl_engine_set : NULL; + APR_REGISTER_OPTIONAL_FN(ssl_engine_set); + APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); + APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); + } + return APR_SUCCESS; +} +#endif /* #if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) */ + +static void tls_init_child(apr_pool_t *p, server_rec *s) +{ + tls_cache_init_child(p, s); +} + +static int hook_pre_connection(conn_rec *c, void *csd) +{ + (void)csd; /* mpm specific socket data, not used */ + + /* are we on a primary connection? */ + if (c->master) return DECLINED; + + /* Decide connection TLS stats and install our + * input/output filters for handling TLS/application data + * if enabled. + */ + return tls_filter_pre_conn_init(c); +} + +static int hook_connection(conn_rec* c) +{ + tls_filter_conn_init(c); + /* we do *not* take over. we are not processing requests. */ + return DECLINED; +} + +static const char *tls_hook_http_scheme(const request_rec *r) +{ + return (tls_conn_check_ssl(r->connection) == OK)? "https" : NULL; +} + +static apr_port_t tls_hook_default_port(const request_rec *r) +{ + return (tls_conn_check_ssl(r->connection) == OK) ? 443 : 0; +} + +static const char* const mod_http2[] = { "mod_http2.c", NULL}; + +static void tls_hooks(apr_pool_t *pool) +{ + /* If our request check denies further processing, certain things + * need to be in place for the response to be correctly generated. */ + static const char *dep_req_check[] = { "mod_setenvif.c", NULL }; + static const char *dep_proxy[] = { "mod_proxy.c", NULL }; + + ap_log_perror(APLOG_MARK, APLOG_TRACE1, 0, pool, "installing hooks"); + tls_filter_register(pool); + + ap_hook_pre_config(tls_pre_config, NULL,NULL, APR_HOOK_MIDDLE); + /* run post-config hooks one before, one after mod_proxy, as the + * mod_proxy's own one calls us in its "section_post_config" hook. */ + ap_hook_post_config(tls_post_config, NULL, dep_proxy, APR_HOOK_MIDDLE); + APR_OPTIONAL_HOOK(proxy, section_post_config, + tls_proxy_section_post_config, NULL, NULL, + APR_HOOK_MIDDLE); + ap_hook_post_config(tls_post_proxy_config, dep_proxy, NULL, APR_HOOK_MIDDLE); + ap_hook_child_init(tls_init_child, NULL,NULL, APR_HOOK_MIDDLE); + /* connection things */ + ap_hook_pre_connection(hook_pre_connection, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_process_connection(hook_connection, NULL, mod_http2, APR_HOOK_MIDDLE); + /* request things */ + ap_hook_default_port(tls_hook_default_port, NULL,NULL, APR_HOOK_MIDDLE); + ap_hook_http_scheme(tls_hook_http_scheme, NULL,NULL, APR_HOOK_MIDDLE); + ap_hook_post_read_request(tls_core_request_check, dep_req_check, NULL, APR_HOOK_MIDDLE); + ap_hook_fixups(tls_var_request_fixup, NULL,NULL, APR_HOOK_MIDDLE); + + ap_hook_ssl_conn_is_ssl(tls_conn_check_ssl, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_ssl_var_lookup(tls_var_lookup, NULL, NULL, APR_HOOK_MIDDLE); + +#if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) + ap_hook_ssl_bind_outgoing(tls_ssl_outgoing, NULL, NULL, APR_HOOK_MIDDLE); +#else + ap_hook_post_config(tls_post_config_proxy_ssl, NULL, dep_proxy, APR_HOOK_MIDDLE); +#endif + +} |