diff --git a/CHANGES b/CHANGES index 2b744675e7..4a70dede5c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes with Apache 2.5.0 + *) mod_ssl: Adding option to set a list of addr:port specs, as used in VirtualHosts + to enable SSLEngine for all matching hosts. Updated documentation. [Stefan Eissing] + *) core: Disallow Methods' registration at runtime (.htaccess), they may be used only if registered at init time (httpd.conf). [Yann Ylavic] diff --git a/docs/manual/mod/mod_ssl.xml b/docs/manual/mod/mod_ssl.xml index 90aa076664..87538c0a0d 100644 --- a/docs/manual/mod/mod_ssl.xml +++ b/docs/manual/mod/mod_ssl.xml @@ -550,15 +550,15 @@ SSLSessionCacheTimeout 600 SSLEngine SSL Engine Operation Switch -SSLEngine on|off|optional +SSLEngine on|off|optional|addr[:port] [addr[:port]] ... SSLEngine off server config virtual host

-This directive toggles the usage of the SSL/TLS Protocol Engine. This -is should be used inside a VirtualHost section to enable SSL/TLS for a that virtual host. By default the SSL/TLS Protocol Engine is disabled for both the main server and all configured virtual hosts.

@@ -570,6 +570,18 @@ SSLEngine on </VirtualHost> +

In Apache 2.4 and later, addr:port values should be used in the +global server to enable the SSL/TLS Protocol Engine for all +VirtualHosts +that match one of the addresses in the list.

+Example + +SSLEngine *:443 +<VirtualHost *:443> +#... +</VirtualHost> + +

In Apache 2.1 and later, SSLEngine can be set to optional. This enables support for RFC 2817, Upgrading to TLS diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c index d6c87edd8d..8505b29903 100644 --- a/modules/ssl/mod_ssl.c +++ b/modules/ssl/mod_ssl.c @@ -91,7 +91,7 @@ static const command_rec ssl_config_cmds[] = { /* * Per-server context configuration directives */ - SSL_CMD_SRV(Engine, TAKE1, + SSL_CMD_SRV(Engine, RAW_ARGS, "SSL switch for the protocol engine " "('on', 'off')") SSL_CMD_SRV(FIPS, FLAG, @@ -490,6 +490,75 @@ static SSLConnRec *ssl_init_connection_ctx(conn_rec *c, return sslconn; } +static int ssl_server_addr_matches(server_addr_rec *sar, apr_sockaddr_t *sa) +{ + /* Determine if the list of server_addr_rec's matches the given socket address. + * IP Address/port may be wilcard/0 for a match to occur. */ + while (sar) { + if (apr_sockaddr_is_wildcard(sar->host_addr) + || apr_sockaddr_equal(sar->host_addr, sa)) { + if (sar->host_addr->port == sa->port + || sar->host_addr->port == 0 + || sa->port == 0) { + return 1; + } + } + sar = sar->next; + } + return 0; +} + +int ssl_server_addr_overlap(server_addr_rec *sar1, server_addr_rec *sar2) +{ + if (sar1) { + while (sar2) { + if (ssl_server_addr_matches(sar1, sar2->host_addr)) { + return 1; + } + sar2 = sar2->next; + } + } + return 0; +} + +static ssl_enabled_t ssl_srv_enabled_on(server_rec *s, apr_sockaddr_t *sa) +{ + SSLSrvConfigRec *sc = mySrvConfig(s); + if (sc->enabled == SSL_ENABLED_TRUE && sc->enabled_on) { + if (!ssl_server_addr_matches(sc->enabled_on, sa)) { + return SSL_ENABLED_FALSE; + } + } + return sc->enabled; +} + +static ssl_enabled_t ssl_conn_enabled(conn_rec *c) +{ + if (c->master) { + return ssl_conn_enabled(c->master); + } + else { + SSLConnRec *sslconn = myConnConfig(c); + if (sslconn) { + if (sslconn->disabled) { + return SSL_ENABLED_FALSE; + } + if (sslconn->is_proxy) { + if (!sslconn->dc->proxy_enabled) { + return SSL_ENABLED_FALSE; + } + } + else { + return ssl_srv_enabled_on(sslconn->server, c->local_addr); + } + } + else { + return ssl_srv_enabled_on(c->base_server, c->local_addr); + } + } + return SSL_ENABLED_TRUE; +} + static int ssl_engine_status(conn_rec *c, SSLConnRec *sslconn) { if (c->master) { @@ -504,17 +573,13 @@ static int ssl_engine_status(conn_rec *c, SSLConnRec *sslconn) return DECLINED; } } - else { - if (mySrvConfig(sslconn->server)->enabled != SSL_ENABLED_TRUE) { - return DECLINED; - } - } - } - else { - if (mySrvConfig(c->base_server)->enabled != SSL_ENABLED_TRUE) { + else if (ssl_srv_enabled_on(sslconn->server, c->local_addr) != SSL_ENABLED_TRUE) { return DECLINED; } } + else if (ssl_srv_enabled_on(c->base_server, c->local_addr) != SSL_ENABLED_TRUE) { + return DECLINED; + } return OK; } @@ -632,26 +697,29 @@ int ssl_init_ssl_connection(conn_rec *c, request_rec *r) return APR_SUCCESS; } +/* FIXME: if we ever want to server http: requests over TLS, this + * needs to change. We probably need the scheme in request_rec and + * return that iff it is set. */ static const char *ssl_hook_http_scheme(const request_rec *r) { - SSLSrvConfigRec *sc = mySrvConfig(r->server); - - if (sc->enabled == SSL_ENABLED_FALSE || sc->enabled == SSL_ENABLED_OPTIONAL) { - return NULL; + switch (ssl_conn_enabled(r->connection)) { + case SSL_ENABLED_FALSE: + case SSL_ENABLED_OPTIONAL: + return NULL; + default: + return "https"; } - - return "https"; } static apr_port_t ssl_hook_default_port(const request_rec *r) { - SSLSrvConfigRec *sc = mySrvConfig(r->server); - - if (sc->enabled == SSL_ENABLED_FALSE || sc->enabled == SSL_ENABLED_OPTIONAL) { - return 0; + switch (ssl_conn_enabled(r->connection)) { + case SSL_ENABLED_FALSE: + case SSL_ENABLED_OPTIONAL: + return 0; + default: + return 443; } - - return 443; } static int ssl_hook_pre_connection(conn_rec *c, void *csd) diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c index 7b1c778d88..419e7e0030 100644 --- a/modules/ssl/ssl_engine_config.c +++ b/modules/ssl/ssl_engine_config.c @@ -231,6 +231,7 @@ static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p) sc->session_tickets = UNSET; sc->policies = NULL; sc->error_policy = NULL; + sc->enabled_on = NULL; modssl_ctx_init_server(sc, p); @@ -375,6 +376,8 @@ void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv) mrg->policies = NULL; cfgMergeString(error_policy); + + mrg->enabled_on = (add->enabled == SSL_ENABLED_UNSET)? base->enabled_on : add->enabled_on; modssl_ctx_cfg_merge_server(p, base->server, add->server, mrg->server); @@ -1010,24 +1013,54 @@ const char *ssl_cmd_SSLRandomSeed(cmd_parms *cmd, return NULL; } -const char *ssl_cmd_SSLEngine(cmd_parms *cmd, void *dcfg, const char *arg) +const char *ssl_cmd_SSLEngine(cmd_parms *cmd, void *dcfg, const char *args) { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *w, *err; + server_addr_rec **psar; + server_rec s; + + w = ap_getword_conf(cmd->pool, &args); - if (!strcasecmp(arg, "On")) { - sc->enabled = SSL_ENABLED_TRUE; - return NULL; + if (*w == '\0') { + return "SSLEngine takes at least one argument"; } - else if (!strcasecmp(arg, "Off")) { - sc->enabled = SSL_ENABLED_FALSE; - return NULL; + + if (*args == 0) { + if (!strcasecmp(w, "On")) { + sc->enabled = SSL_ENABLED_TRUE; + sc->enabled_on = NULL; + return NULL; + } + else if (!strcasecmp(w, "Off")) { + sc->enabled = SSL_ENABLED_FALSE; + sc->enabled_on = NULL; + return NULL; + } + else if (!strcasecmp(w, "Optional")) { + sc->enabled = SSL_ENABLED_OPTIONAL; + sc->enabled_on = NULL; + return NULL; + } } - else if (!strcasecmp(arg, "Optional")) { - sc->enabled = SSL_ENABLED_OPTIONAL; - return NULL; + + memset(&s, 0, sizeof(s)); + err = ap_parse_vhost_addrs(cmd->pool, w, &s); + sc->enabled_on = s.addrs; + sc->enabled = SSL_ENABLED_TRUE; + + if (!err && *args) { + s.addrs = NULL; + err = ap_parse_vhost_addrs(cmd->pool, args, &s); + if (!err && s.addrs) { + psar = &sc->enabled_on; + while (*psar) { + psar = &(*psar)->next; + } + *psar = s.addrs; + } } - - return "Argument must be On, Off, or Optional"; + return err; } const char *ssl_cmd_SSLFIPS(cmd_parms *cmd, void *dcfg, int flag) diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c index 8920d50cc5..7a5b26b23e 100644 --- a/modules/ssl/ssl_engine_init.c +++ b/modules/ssl/ssl_engine_init.c @@ -269,6 +269,13 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, if (sc->enabled == SSL_ENABLED_UNSET) { sc->enabled = SSL_ENABLED_FALSE; } + /* Check if conditions to enable apply to this server at all. Conditions + * might be inherited from base server and never match a vhost. */ + if (sc->enabled_on && sc->enabled == SSL_ENABLED_TRUE) { + if (!ssl_server_addr_overlap(sc->enabled_on, s->addrs)) { + sc->enabled = SSL_ENABLED_FALSE; + } + } if (sc->session_cache_timeout == UNSET) { sc->session_cache_timeout = SSL_SESSION_CACHE_TIMEOUT; diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h index a6bb59f04c..732670b3c9 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -740,6 +740,7 @@ struct SSLSrvConfigRec { apr_array_header_t *policies; /* policy that shall be applied to this config */ const char *error_policy; /* error in policy merge, bubble up */ + server_addr_rec *enabled_on; /* optional list of addresses where ssl is enabled */ }; /** @@ -1091,6 +1092,8 @@ extern int ssl_running_on_valgrind; int ssl_is_challenge(conn_rec *c, const char *servername, X509 **pcert, EVP_PKEY **pkey); +int ssl_server_addr_overlap(server_addr_rec *sar1, server_addr_rec *sar2); + #endif /* SSL_PRIVATE_H */ /** @} */