-*- 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]
<directivesynopsis>
<name>SSLEngine</name>
<description>SSL Engine Operation Switch</description>
-<syntax>SSLEngine on|off|optional</syntax>
+<syntax>SSLEngine on|off|optional|addr[:port] [addr[:port]] ...</syntax>
<default>SSLEngine off</default>
<contextlist><context>server config</context>
<context>virtual host</context></contextlist>
<usage>
<p>
-This directive toggles the usage of the SSL/TLS Protocol Engine. This
-is should be used inside a <directive module="core"
+This directive toggles the usage of the SSL/TLS Protocol Engine. Values 'on',
+'off' and 'optional' should be used inside a <directive module="core"
type="section">VirtualHost</directive> 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.</p>
</VirtualHost>
</highlight>
</example>
+<p>In Apache 2.4 and later, addr:port values should be used in the
+global server to enable the SSL/TLS Protocol Engine for <em>all</em>
+<directive module="core" type="section">VirtualHost</directive>s
+that match one of the addresses in the list.</p>
+<example><title>Example</title>
+<highlight language="config">
+SSLEngine *:443
+<VirtualHost *:443>
+#...
+</VirtualHost>
+</highlight>
+</example>
<p>In Apache 2.1 and later, <directive>SSLEngine</directive> can be set to
<code>optional</code>. This enables support for
<a href="http://www.ietf.org/rfc/rfc2817.txt">RFC 2817</a>, Upgrading to TLS
/*
* 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,
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) {
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;
}
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)
sc->session_tickets = UNSET;
sc->policies = NULL;
sc->error_policy = NULL;
+ sc->enabled_on = NULL;
modssl_ctx_init_server(sc, p);
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);
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)
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;
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 */
};
/**
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 */
/** @} */