return OK;
}
-#ifndef OPENSSL_NO_TLSEXT
-static int set_ssl_vhost(void *servername, conn_rec *c, server_rec *s)
-{
- SSLSrvConfigRec *sc;
- SSL *ssl;
- BOOL found = FALSE;
- apr_array_header_t *names;
- int i;
-
- /* check ServerName */
- if (!strcasecmp(servername, s->server_hostname))
- found = TRUE;
-
- /* if not matched yet, check ServerAlias entries */
- if (!found) {
- names = s->names;
- if (names) {
- char **name = (char **)names->elts;
- for (i = 0; i < names->nelts; ++i) {
- if (!name[i])
- continue;
- if (!strcasecmp(servername, name[i])) {
- found = TRUE;
- break;
- }
- }
- }
- }
-
- /* if still no match, check ServerAlias entries with wildcards */
- if (!found) {
- names = s->wild_names;
- if (names) {
- char **name = (char **)names->elts;
- for (i = 0; i < names->nelts; ++i) {
- if (!name[i])
- continue;
- if (!ap_strcasecmp_match(servername, name[i])) {
- found = TRUE;
- break;
- }
- }
- }
- }
-
- /* set SSL_CTX (if matched) */
- if (found) {
- if ((ssl = ((SSLConnRec *)myConnConfig(c))->ssl) == NULL)
- return 0;
- if (!(sc = mySrvConfig(s)))
- return 0;
- SSL_set_SSL_CTX(ssl, sc->server->ssl_ctx);
- return 1;
- }
- return 0;
-}
-
-int ssl_set_vhost_ctx(SSL *ssl, const char *servername)
-{
- conn_rec *c;
-
- if (servername == NULL) /* should not occur. */
- return 0;
- SSL_set_SSL_CTX(ssl, NULL);
- if (!(c = (conn_rec *)SSL_get_app_data(ssl)))
- return 0;
- return ap_vhost_iterate_given_conn(c, set_ssl_vhost, (void *)servername);
-}
-
-int ssl_servername_cb(SSL *ssl, int *al, modssl_ctx_t *mctx)
-{
- const char *servername =
- SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
-
- if (servername)
- return ssl_set_vhost_ctx(ssl, servername) ?
- SSL_TLSEXT_ERR_OK : SSL_TLSEXT_ERR_ALERT_FATAL;
- return SSL_TLSEXT_ERR_NOACK;
-}
-#endif
-
/*
* Per-module initialization
*/
}
}
-static void ssl_init_server_extensions(server_rec *s,
- apr_pool_t *p,
- apr_pool_t *ptemp,
- modssl_ctx_t *mctx)
+#ifndef OPENSSL_NO_TLSEXT
+static void ssl_init_ctx_tls_extensions(server_rec *s,
+ apr_pool_t *p,
+ apr_pool_t *ptemp,
+ modssl_ctx_t *mctx)
{
/*
* Configure TLS extensions support
*/
-#ifndef OPENSSL_NO_TLSEXT
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
- "Configuring TLS extensions facility");
+ "Configuring TLS extension handling");
+ /*
+ * Server name indication (SNI)
+ */
if (!SSL_CTX_set_tlsext_servername_callback(mctx->ssl_ctx,
- ssl_servername_cb) ||
+ ssl_callback_ServerNameIndication) ||
!SSL_CTX_set_tlsext_servername_arg(mctx->ssl_ctx, mctx)) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
- "Unable to initialize servername callback - "
- "bad OpenSSL version.");
+ "Unable to initialize TLS servername extension "
+ "callback (incompatible OpenSSL version?)");
ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s);
ssl_die();
}
-#endif
}
+#endif
static void ssl_init_ctx_protocol(server_rec *s,
apr_pool_t *p,
if (mctx->pks) {
/* XXX: proxy support? */
ssl_init_ctx_cert_chain(s, p, ptemp, mctx);
- ssl_init_server_extensions(s, p, ptemp, mctx);
+#ifndef OPENSSL_NO_TLSEXT
+ ssl_init_ctx_tls_extensions(s, p, ptemp, mctx);
+#endif
}
}
void ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p)
{
+ server_rec *s, *ps;
SSLSrvConfigRec *sc;
- server_rec *s;
-#ifdef OPENSSL_NO_TLSEXT
- server_rec *ps;
apr_hash_t *table;
const char *key;
apr_ssize_t klen;
BOOL conflict = FALSE;
-#endif
/*
* Give out warnings when a server has HTTPS configured
}
}
-#ifdef OPENSSL_NO_TLSEXT
/*
* Give out warnings when more than one SSL-aware virtual server uses the
* same IP:port. This doesn't work because mod_ssl then will always use
if ((ps = (server_rec *)apr_hash_get(table, key, klen))) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
base_server,
+#ifdef OPENSSL_NO_TLSEXT
"Init: SSL server IP/port conflict: "
+#else
+ "Init: SSL server IP/port overlap: "
+#endif
"%s (%s:%d) vs. %s (%s:%d)",
ssl_util_vhostid(p, s),
(s->defn_name ? s->defn_name : "unknown"),
if (conflict) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server,
+#ifdef OPENSSL_NO_TLSEXT
"Init: You should not use name-based "
"virtual hosts in conjunction with SSL!!");
- }
+#else
+ "Init: Name-based SSL virtual hosts only "
+ "work for clients with TLS server name indication "
+ "support (RFC 4366)");
#endif
+ }
}
#ifdef SSLC_VERSION_NUMBER
#include "ssl_private.h"
static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn);
+#ifndef OPENSSL_NO_TLSEXT
+static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s);
+#endif
#define SWITCH_STATUS_LINE "HTTP/1.1 101 Switching Protocols"
#define UPGRADE_HEADER "Upgrade: TLS/1.0, HTTP/1.1"
SSLSrvConfigRec *sc = mySrvConfig(r->server);
SSLConnRec *sslconn;
const char *upgrade;
+#ifndef OPENSSL_NO_TLSEXT
+ const char *servername;
+#endif
SSL *ssl;
/* Perform TLS upgrade here if "SSLEngine optional" is configured,
if (!ssl) {
return DECLINED;
}
+#ifndef OPENSSL_NO_TLSEXT
+ if (!r->hostname &&
+ (servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
+ /* Use the SNI extension as the hostname if no Host: header was sent */
+ r->hostname = apr_pstrdup(r->pool, servername);
+ ap_update_vhost_from_headers(r);
+ }
+#endif
SSL_set_app_data2(ssl, r);
/*
* the currently active one.
*/
-#ifndef OPENSSL_NO_TLSEXT
- /*
- * We will force a renegotiation if we switch to another virtualhost.
- */
- if (r->hostname && !SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name)) {
- if (ssl_set_vhost_ctx(ssl, r->hostname) && ctx != SSL_get_SSL_CTX(ssl))
- renegotiate = TRUE;
- }
-#endif
-
/*
* Override of SSLCipherSuite
*
apr_table_t *env = r->subprocess_env;
char *var, *val = "";
#ifndef OPENSSL_NO_TLSEXT
- const char* servername;
+ const char *servername;
#endif
STACK_OF(X509) *peer_certs;
SSL *ssl;
}
}
+#ifndef OPENSSL_NO_TLSEXT
+/*
+ * This callback function is executed when OpenSSL encounters an extended
+ * client hello with a server name indication extension ("SNI", cf. RFC 4366).
+ */
+int ssl_callback_ServerNameIndication(SSL *ssl, int *al, modssl_ctx_t *mctx)
+{
+ const char *servername =
+ SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+
+ if (servername) {
+ conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
+ if (c) {
+ if (ap_vhost_iterate_given_conn(c, ssl_find_vhost,
+ (void *)servername)) {
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+ "SSL virtual host for servername %s found",
+ servername);
+ return SSL_TLSEXT_ERR_OK;
+ }
+ else {
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+ "No matching SSL virtual host for servername "
+ "%s found (using default/first virtual host)",
+ servername);
+ return SSL_TLSEXT_ERR_ALERT_WARNING;
+ }
+ }
+ }
+
+ return SSL_TLSEXT_ERR_NOACK;
+}
+
+/*
+ * Find a (name-based) SSL virtual host where either the ServerName
+ * or one of the ServerAliases matches the supplied name (to be used
+ * with ap_vhost_iterate_given_conn())
+ */
+static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s)
+{
+ SSLSrvConfigRec *sc;
+ SSL *ssl;
+ BOOL found = FALSE;
+ apr_array_header_t *names;
+ int i;
+
+ /* check ServerName */
+ if (!strcasecmp(servername, s->server_hostname)) {
+ found = TRUE;
+ }
+
+ /*
+ * if not matched yet, check ServerAlias entries
+ * (adapted from vhost.c:matches_aliases())
+ */
+ if (!found) {
+ names = s->names;
+ if (names) {
+ char **name = (char **)names->elts;
+ for (i = 0; i < names->nelts; ++i) {
+ if (!name[i])
+ continue;
+ if (!strcasecmp(servername, name[i])) {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ /* if still no match, check ServerAlias entries with wildcards */
+ if (!found) {
+ names = s->wild_names;
+ if (names) {
+ char **name = (char **)names->elts;
+ for (i = 0; i < names->nelts; ++i) {
+ if (!name[i])
+ continue;
+ if (!ap_strcasecmp_match(servername, name[i])) {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ /* set SSL_CTX (if matched) */
+ if (found && (ssl = ((SSLConnRec *)myConnConfig(c))->ssl) &&
+ (sc = mySrvConfig(s))) {
+ SSL_set_SSL_CTX(ssl, sc->server->ssl_ctx);
+ /*
+ * SSL_set_SSL_CTX() only deals with the server cert,
+ * so we need to duplicate a few additional settings
+ * from the ctx by hand
+ */
+ SSL_set_options(ssl, SSL_CTX_get_options(ssl->ctx));
+ if ((SSL_get_verify_mode(ssl) == SSL_VERIFY_NONE) ||
+ (SSL_num_renegotiations(ssl) == 0)) {
+ /*
+ * Only initialize the verification settings from the ctx
+ * if they are not yet set, or if we're called when a new
+ * SSL connection is set up (num_renegotiations == 0).
+ * Otherwise, we would possibly reset a per-directory
+ * configuration which was put into effect by ssl_hook_Access.
+ */
+ SSL_set_verify(ssl, SSL_CTX_get_verify_mode(ssl->ctx),
+ SSL_CTX_get_verify_callback(ssl->ctx));
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+#endif
else if (ssl != NULL && strcEQ(var, "COMPRESS_METHOD")) {
result = ssl_var_lookup_ssl_compress_meth(ssl);
}
+#ifndef OPENSSL_NO_TLSEXT
+ else if (ssl != NULL && strcEQ(var, "TLS_SNI")) {
+ result = apr_pstrdup(p, SSL_get_servername(ssl,
+ TLSEXT_NAMETYPE_host_name));
+ }
+#endif
return result;
}
SSL_SESSION *ssl_callback_GetSessionCacheEntry(SSL *, unsigned char *, int, int *);
void ssl_callback_DelSessionCacheEntry(SSL_CTX *, SSL_SESSION *);
void ssl_callback_LogTracingState(MODSSL_INFO_CB_ARG_TYPE, int, int);
+#ifndef OPENSSL_NO_TLSEXT
+int ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *);
+#endif
/** Session Cache Support */
void ssl_scache_init(server_rec *, apr_pool_t *);
conn_rec *c, apr_pool_t *p);
#endif
-#ifndef OPENSSL_NO_TLSEXT
-int ssl_servername_cb(SSL *ssl, int *al, modssl_ctx_t *mctx);
-int ssl_set_vhost_ctx(SSL *ssl, const char *servername);
-#endif
-
#endif /* SSL_PRIVATE_H */
/** @} */