httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j..@apache.org
Subject svn commit: r776281 - in /httpd/httpd/branches/2.2.x: ./ docs/manual/mod/ modules/ssl/
Date Tue, 19 May 2009 11:45:00 GMT
Author: jim
Date: Tue May 19 11:44:59 2009
New Revision: 776281

URL: http://svn.apache.org/viewvc?rev=776281&view=rev
Log:
   * mod_ssl:  Add server name indication support (RFC 4366) and better
     support for name based virtual hosts with SSL. PR 34607

Modified:
    httpd/httpd/branches/2.2.x/CHANGES
    httpd/httpd/branches/2.2.x/STATUS
    httpd/httpd/branches/2.2.x/docs/manual/mod/mod_ssl.xml
    httpd/httpd/branches/2.2.x/modules/ssl/mod_ssl.c
    httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_config.c
    httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_init.c
    httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_io.c
    httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_kernel.c
    httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_vars.c
    httpd/httpd/branches/2.2.x/modules/ssl/ssl_private.h
    httpd/httpd/branches/2.2.x/modules/ssl/ssl_toolkit_compat.h

Modified: httpd/httpd/branches/2.2.x/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/CHANGES?rev=776281&r1=776280&r2=776281&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/CHANGES [utf-8] (original)
+++ httpd/httpd/branches/2.2.x/CHANGES [utf-8] Tue May 19 11:44:59 2009
@@ -11,6 +11,12 @@
      mod_proxy_ajp: Avoid delivering content from a previous request which
      failed to send a request body. PR 46949 [Ruediger Pluem]
 
+  *) mod_ssl: Add server name indication support (RFC 4366) and better
+     support for name based virtual hosts with SSL. PR 34607
+     [Peter Sylvester <peter.sylvester edelweb.fr>,
+      Kaspar Brand <asfbugz velox.ch>, Guenter Knauf, Joe Orton,
+      Ruediger Pluem]
+
   *) mod_negotiation: Escape pathes of filenames in 406 responses to avoid
      HTML injections and HTTP response splitting.  PR 46837.
      [Geoff Keating <geoffk apple.com>]

Modified: httpd/httpd/branches/2.2.x/STATUS
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/STATUS?rev=776281&r1=776280&r2=776281&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/STATUS (original)
+++ httpd/httpd/branches/2.2.x/STATUS Tue May 19 11:44:59 2009
@@ -87,39 +87,6 @@
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ start all new proposals below, under PATCHES PROPOSED. ]
 
- * mod_ssl: Improve and simplify the implementation of SSLProxyCheckPeerExpire
-   by directly using X509_get_notBefore(), X509_get_notAfter() and
-   X509_cmp_current_time().
-    Trunk version of patch:
-       http://svn.apache.org/viewcvs.cgi?rev=769809&view=rev
-    Backport version for 2.2.x of patch:
-       Trunk version of patch works
-    +1: rpluem, jim, pgollucci
-
-   * mod_ssl:  Add server name indication support (RFC 4366) and better
-     support for name based virtual hosts with SSL. PR 34607
-      Trunk version of patches:
-         http://svn.apache.org/viewvc?view=rev&revision=591955
-         http://svn.apache.org/viewvc?view=rev&revision=606190
-         http://svn.apache.org/viewvc?view=rev&revision=607420
-         http://svn.apache.org/viewvc?view=rev&revision=607425
-         http://svn.apache.org/viewvc?view=rev&revision=611216
-         http://svn.apache.org/viewvc?view=rev&revision=620505
-         http://svn.apache.org/viewvc?view=rev&revision=627699
-         http://svn.apache.org/viewvc?view=rev&revision=630436
-         http://svn.apache.org/viewvc?view=rev&revision=662815
-         http://svn.apache.org/viewvc?view=rev&revision=757373
-         http://svn.apache.org/viewvc?view=rev&revision=757463
-         http://svn.apache.org/viewvc?view=rev&revision=757720
-         http://svn.apache.org/viewvc?view=rev&revision=761181
-         http://svn.apache.org/viewvc?view=rev&revision=768499
-         http://svn.apache.org/viewvc?view=rev&revision=768501
-         http://svn.apache.org/viewvc?view=rev&revision=768596
-         http://svn.apache.org/viewvc?view=rev&revision=770907
-         http://svn.apache.org/viewvc?view=rev&revision=771455
-      Backport version for 2.2.x of updated patch:
-         http://people.apache.org/~rpluem/patches/sni_backport_2.2.x.diff
-      +1: rpluem, jim, pgollucci
 
 PATCHES PROPOSED TO BACKPORT FROM TRUNK:
   [ New proposals should be added at the end of the list ]

Modified: httpd/httpd/branches/2.2.x/docs/manual/mod/mod_ssl.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/docs/manual/mod/mod_ssl.xml?rev=776281&r1=776280&r2=776281&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/docs/manual/mod/mod_ssl.xml (original)
+++ httpd/httpd/branches/2.2.x/docs/manual/mod/mod_ssl.xml Tue May 19 11:44:59 2009
@@ -1355,6 +1355,37 @@
 </directivesynopsis>
 
 <directivesynopsis>
+<name>SSLStrictSNIVHostCheck</name>
+<description>Whether to allow non SNI clients to access a name based virtual
+host.
+</description>
+<syntax>SSLStrictSNIVHostCheck on|off</syntax>
+<default>SSLStrictSNIVHostCheck off</default>
+<contextlist><context>server config</context>
+<context>virtual host</context></contextlist>
+
+<usage>
+<p>
+This directive sets whether a non SNI client is allowed to access a name based
+virtual host. If set to <code>on</code> in the non default name based virtual
+host, non SNI clients are not allowed to access this particular virtual host.
+If set to <code>on</code> in the default name based virtual host, non SNI
+clients are not allowed to access any name based virtual host belonging to
+this IP / port combination.
+</p>
+
+<note type="warning"><p>
+This option is only available if httpd was compiled against an SNI capable
+version of OpenSSL.
+</p></note>
+
+<example><title>Example</title>
+SSLStrictSNIVHostCheck on
+</example>
+</usage>
+</directivesynopsis>
+
+<directivesynopsis>
 <name>SSLProxyMachineCertificatePath</name>
 <description>Directory of PEM-encoded client certificates and keys to be used by the proxy</description>
 <syntax>SSLProxyMachineCertificatePath <em>directory</em></syntax>

Modified: httpd/httpd/branches/2.2.x/modules/ssl/mod_ssl.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/ssl/mod_ssl.c?rev=776281&r1=776280&r2=776281&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/ssl/mod_ssl.c (original)
+++ httpd/httpd/branches/2.2.x/modules/ssl/mod_ssl.c Tue May 19 11:44:59 2009
@@ -145,6 +145,8 @@
                 "Use the server's cipher ordering preference")
     SSL_CMD_ALL(UserName, TAKE1,
                 "Set user name to SSL variable value")
+    SSL_CMD_SRV(StrictSNIVHostCheck, FLAG,
+                "Strict SNI virtual host checking")
 
     /*
      * Proxy configuration for remote SSL connections
@@ -303,6 +305,8 @@
 
     sslconn = apr_pcalloc(c->pool, sizeof(*sslconn));
 
+    sslconn->server = c->base_server;
+
     myConnConfigSet(c, sslconn);
 
     return sslconn;
@@ -310,9 +314,10 @@
 
 int ssl_proxy_enable(conn_rec *c)
 {
-    SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
+    SSLSrvConfigRec *sc;
 
     SSLConnRec *sslconn = ssl_init_connection_ctx(c);
+    sc = mySrvConfig(sslconn->server);
 
     if (!sc->proxy_enabled) {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
@@ -330,10 +335,16 @@
 
 int ssl_engine_disable(conn_rec *c)
 {
-    SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
+    SSLSrvConfigRec *sc;
 
-    SSLConnRec *sslconn;
+    SSLConnRec *sslconn = myConnConfig(c);
 
+    if (sslconn) {
+        sc = mySrvConfig(sslconn->server);
+    }
+    else {
+        sc = mySrvConfig(c->base_server);
+    }
     if (sc->enabled == SSL_ENABLED_FALSE) {
         return 0;
     }
@@ -347,20 +358,23 @@
 
 int ssl_init_ssl_connection(conn_rec *c)
 {
-    SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
+    SSLSrvConfigRec *sc;
     SSL *ssl;
     SSLConnRec *sslconn = myConnConfig(c);
     char *vhost_md5;
     modssl_ctx_t *mctx;
-
-    /*
-     * Seed the Pseudo Random Number Generator (PRNG)
-     */
-    ssl_rand_seed(c->base_server, c->pool, SSL_RSCTX_CONNECT, "");
+    server_rec *server;
 
     if (!sslconn) {
         sslconn = ssl_init_connection_ctx(c);
     }
+    server = sslconn->server;
+    sc = mySrvConfig(server);
+
+    /*
+     * Seed the Pseudo Random Number Generator (PRNG)
+     */
+    ssl_rand_seed(server, c->pool, SSL_RSCTX_CONNECT, "");
 
     mctx = sslconn->is_proxy ? sc->proxy : sc->server;
 
@@ -373,7 +387,7 @@
         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
                       "Unable to create a new SSL connection from the SSL "
                       "context");
-        ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, c->base_server);
+        ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, server);
 
         c->aborted = 1;
 
@@ -388,7 +402,7 @@
     {
         ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
                       "Unable to set session id context to `%s'", vhost_md5);
-        ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, c->base_server);
+        ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, server);
 
         c->aborted = 1;
 
@@ -437,9 +451,15 @@
 
 static int ssl_hook_pre_connection(conn_rec *c, void *csd)
 {
-    SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
+    SSLSrvConfigRec *sc;
     SSLConnRec *sslconn = myConnConfig(c);
 
+    if (sslconn) {
+        sc = mySrvConfig(sslconn->server);
+    }
+    else {
+        sc = mySrvConfig(c->base_server);
+    }
     /*
      * Immediately stop processing if SSL is disabled for this connection
      */

Modified: httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_config.c?rev=776281&r1=776280&r2=776281&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_config.c (original)
+++ httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_config.c Tue May 19 11:44:59 2009
@@ -171,6 +171,9 @@
     sc->cipher_server_pref     = UNSET;
     sc->proxy_ssl_check_peer_expire = SSL_ENABLED_UNSET;
     sc->proxy_ssl_check_peer_cn     = SSL_ENABLED_UNSET;
+#ifndef OPENSSL_NO_TLSEXT
+    sc->strict_sni_vhost_check = SSL_ENABLED_UNSET;
+#endif
 
     modssl_ctx_init_proxy(sc, p);
 
@@ -261,6 +264,9 @@
     cfgMergeBool(cipher_server_pref);
     cfgMerge(proxy_ssl_check_peer_expire, SSL_ENABLED_UNSET);
     cfgMerge(proxy_ssl_check_peer_cn, SSL_ENABLED_UNSET);
+#ifndef OPENSSL_NO_TLSEXT
+    cfgMerge(strict_sni_vhost_check, SSL_ENABLED_UNSET);
+#endif
 
     modssl_ctx_cfg_merge_proxy(base->proxy, add->proxy, mrg->proxy);
 
@@ -1450,6 +1456,21 @@
     return NULL;
 }
 
+const char  *ssl_cmd_SSLStrictSNIVHostCheck(cmd_parms *cmd, void *dcfg, int flag)
+{
+#ifndef OPENSSL_NO_TLSEXT
+    SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+
+    sc->strict_sni_vhost_check = flag ? SSL_ENABLED_TRUE : SSL_ENABLED_FALSE;
+
+    return NULL;
+#else
+    return "SSLStrictSNIVHostCheck failed; OpenSSL is not built with support "
+           "for TLS extensions and SNI indication. Refer to the "
+           "documentation, and build a compatible version of OpenSSL.";
+#endif
+}
+
 void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s)
 {
     if (!ap_exists_config_define("DUMP_CERTS")) {

Modified: httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_init.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_init.c?rev=776281&r1=776280&r2=776281&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_init.c (original)
+++ httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_init.c Tue May 19 11:44:59 2009
@@ -358,6 +358,33 @@
     }
 }
 
+#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
+     */
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                 "Configuring TLS extension handling");
+
+    /*
+     * Server name indication (SNI)
+     */
+    if (!SSL_CTX_set_tlsext_servername_callback(mctx->ssl_ctx,
+                          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 TLS servername extension "
+                     "callback (incompatible OpenSSL version?)");
+        ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s);
+        ssl_die();
+    }
+}
+#endif
+
 static void ssl_init_ctx_protocol(server_rec *s,
                                   apr_pool_t *p,
                                   apr_pool_t *ptemp,
@@ -690,6 +717,9 @@
     if (mctx->pks) {
         /* XXX: proxy support? */
         ssl_init_ctx_cert_chain(s, p, ptemp, mctx);
+#ifndef OPENSSL_NO_TLSEXT
+        ssl_init_ctx_tls_extensions(s, p, ptemp, mctx);
+#endif
     }
 }
 
@@ -1039,9 +1069,19 @@
         klen = strlen(key);
 
         if ((ps = (server_rec *)apr_hash_get(table, key, klen))) {
-            ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
+            ap_log_error(APLOG_MARK, 
+#ifdef OPENSSL_NO_TLSEXT
+                         APLOG_WARNING, 
+#else
+                         APLOG_DEBUG, 
+#endif
+                         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"),
@@ -1058,8 +1098,14 @@
 
     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
     }
 }
 

Modified: httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_io.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_io.c?rev=776281&r1=776280&r2=776281&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_io.c (original)
+++ httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_io.c Tue May 19 11:44:59 2009
@@ -696,7 +696,7 @@
                  */
                 ap_log_cerror(APLOG_MARK, APLOG_INFO, inctx->rc, c,
                               "SSL library error %d reading data", ssl_err);
-                ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);
+                ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, mySrvFromConn(c));
 
             }
             if (inctx->rc == APR_SUCCESS) {
@@ -800,7 +800,7 @@
              */
             ap_log_cerror(APLOG_MARK, APLOG_INFO, outctx->rc, c,
                           "SSL library error %d writing data", ssl_err);
-            ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);
+            ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, mySrvFromConn(c));
         }
         if (outctx->rc == APR_SUCCESS) {
             outctx->rc = APR_EGENERAL;
@@ -862,7 +862,7 @@
             ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c,
                          "SSL handshake failed: HTTP spoken on HTTPS port; "
                          "trying to send HTML error page");
-            ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, f->c->base_server);
+            ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, sslconn->server);
 
             sslconn->non_ssl_request = 1;
             ssl_io_filter_disable(sslconn, f);
@@ -972,11 +972,11 @@
     SSL_smart_shutdown(ssl);
 
     /* and finally log the fact that we've closed the connection */
-    if (c->base_server->loglevel >= APLOG_INFO) {
+    if (mySrvFromConn(c)->loglevel >= APLOG_INFO) {
         ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
                       "Connection closed to child %ld with %s shutdown "
                       "(server %s)",
-                      c->id, type, ssl_util_vhostid(c->pool, c->base_server));
+                      c->id, type, ssl_util_vhostid(c->pool, mySrvFromConn(c)));
     }
 
     /* deallocate the SSL connection */
@@ -1022,23 +1022,26 @@
 {
     conn_rec *c         = (conn_rec *)SSL_get_app_data(filter_ctx->pssl);
     SSLConnRec *sslconn = myConnConfig(c);
-    SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
+    SSLSrvConfigRec *sc;
     X509 *cert;
     int n;
     int ssl_err;
     long verify_result;
+    server_rec *server;
 
     if (SSL_is_init_finished(filter_ctx->pssl)) {
         return APR_SUCCESS;
     }
 
+    server = sslconn->server;
     if (sslconn->is_proxy) {
         const char *hostname_note;
 
+        sc = mySrvConfig(server);
         if ((n = SSL_connect(filter_ctx->pssl)) <= 0) {
             ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
                           "SSL Proxy connect failed");
-            ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);
+            ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, server);
             /* ensure that the SSL structures etc are freed, etc: */
             ssl_filter_io_shutdown(filter_ctx, c, 1);
             return HTTP_BAD_GATEWAY;
@@ -1067,7 +1070,7 @@
                  apr_table_get(c->notes, "proxy-request-hostname")) != NULL)) {
             const char *hostname;
 
-            hostname = ssl_var_lookup(NULL, c->base_server, c, NULL,
+            hostname = ssl_var_lookup(NULL, server, c, NULL,
                                       "SSL_CLIENT_S_DN_CN");
             apr_table_unset(c->notes, "proxy-request-hostname");
             if (strcasecmp(hostname, hostname_note)) {
@@ -1132,8 +1135,8 @@
             ap_log_cerror(APLOG_MARK, APLOG_INFO, rc, c,
                           "SSL library error %d in handshake "
                           "(server %s)", ssl_err,
-                          ssl_util_vhostid(c->pool, c->base_server));
-            ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);
+                          ssl_util_vhostid(c->pool, server));
+            ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, server);
 
         }
         if (inctx->rc == APR_SUCCESS) {
@@ -1142,6 +1145,7 @@
 
         return ssl_filter_io_shutdown(filter_ctx, c, 1);
     }
+    sc = mySrvConfig(sslconn->server);
 
     /*
      * Check for failed client authentication
@@ -1167,7 +1171,7 @@
                           "accepting certificate based on "
                           "\"SSLVerifyClient optional_no_ca\" "
                           "configuration");
-            ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);
+            ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, server);
         }
         else {
             const char *error = sslconn->verify_error ?
@@ -1177,7 +1181,7 @@
             ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
                          "SSL client authentication failed: %s",
                          error ? error : "unknown");
-            ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);
+            ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, server);
 
             return ssl_filter_io_shutdown(filter_ctx, c, 1);
         }
@@ -1846,7 +1850,7 @@
         return rc;
     if ((c = (conn_rec *)SSL_get_app_data(ssl)) == NULL)
         return rc;
-    s = c->base_server;
+    s = mySrvFromConn(c);
 
     if (   cmd == (BIO_CB_WRITE|BIO_CB_RETURN)
         || cmd == (BIO_CB_READ |BIO_CB_RETURN) ) {

Modified: httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_kernel.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_kernel.c?rev=776281&r1=776280&r2=776281&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_kernel.c (original)
+++ httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_kernel.c Tue May 19 11:44:59 2009
@@ -31,6 +31,9 @@
 #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
 
 /*
  *  Post Read Request Handler
@@ -38,6 +41,9 @@
 int ssl_hook_ReadReq(request_rec *r)
 {
     SSLConnRec *sslconn = myConnConfig(r->connection);
+#ifndef OPENSSL_NO_TLSEXT
+    const char *servername;
+#endif
     SSL *ssl;
 
     if (!sslconn) {
@@ -87,6 +93,51 @@
     if (!ssl) {
         return DECLINED;
     }
+#ifndef OPENSSL_NO_TLSEXT
+    if ((servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
+        char *host, *scope_id;
+        apr_port_t port;
+        apr_status_t rv;
+
+        /*
+         * The SNI extension supplied a hostname. So don't accept requests
+         * with either no hostname or a different hostname.
+         */
+        if (!r->hostname) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                        "Hostname %s provided via SNI, but no hostname"
+                        " provided in HTTP request", servername);
+            return HTTP_BAD_REQUEST;
+        }
+        rv = apr_parse_addr_port(&host, &scope_id, &port, r->hostname, r->pool);
+        if (rv != APR_SUCCESS || scope_id) {
+            return HTTP_BAD_REQUEST;
+        }
+        if (strcmp(host, servername)) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                        "Hostname %s provided via SNI and hostname %s provided"
+                        " via HTTP are different", servername, host);
+            return HTTP_BAD_REQUEST;
+        }
+    }
+    else if ((((mySrvConfig(r->server))->strict_sni_vhost_check
+              == SSL_ENABLED_TRUE)
+             || (mySrvConfig(sslconn->server))->strict_sni_vhost_check
+                == SSL_ENABLED_TRUE)
+             && r->connection->vhost_lookup_data) {
+        /*
+         * We are using a name based configuration here, but no hostname was
+         * provided via SNI. Don't allow that if are requested to do strict
+         * checking. Check wether this strict checking was setup either in the
+         * server config we used for handshaking or in our current server.
+         * This should avoid insecure configuration by accident.
+         */
+        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                     "No hostname was provided via SNI for a name based"
+                     " virtual host");
+        return HTTP_FORBIDDEN;
+    }
+#endif
     SSL_set_app_data2(ssl, r);
 
     /*
@@ -155,10 +206,11 @@
  */
 int ssl_hook_Access(request_rec *r)
 {
-    SSLDirConfigRec *dc = myDirConfig(r);
-    SSLSrvConfigRec *sc = mySrvConfig(r->server);
-    SSLConnRec *sslconn = myConnConfig(r->connection);
-    SSL *ssl            = sslconn ? sslconn->ssl : NULL;
+    SSLDirConfigRec *dc         = myDirConfig(r);
+    SSLSrvConfigRec *sc         = mySrvConfig(r->server);
+    SSLConnRec *sslconn         = myConnConfig(r->connection);
+    SSL *ssl                    = sslconn ? sslconn->ssl : NULL;
+    server_rec *handshakeserver = sslconn ? sslconn->server : NULL;
     SSL_CTX *ctx = NULL;
     apr_array_header_t *requires;
     ssl_require_t *ssl_requires;
@@ -252,7 +304,7 @@
      *   has to enable this via ``SSLOptions +OptRenegotiate''. So we do no
      *   implicit optimizations.
      */
-    if (dc->szCipherSuite) {
+    if (dc->szCipherSuite || (r->server != handshakeserver)) {
         /* remember old state */
 
         if (dc->nOptions & SSL_OPT_OPTRENEGOTIATE) {
@@ -267,11 +319,13 @@
         }
 
         /* configure new state */
-        if (!modssl_set_cipher_list(ssl, dc->szCipherSuite)) {
-            ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
-                         r->server,
-                         "Unable to reconfigure (per-directory) "
-                         "permitted SSL ciphers");
+        if ((dc->szCipherSuite || sc->server->auth.cipher_suite) &&
+            !modssl_set_cipher_list(ssl, dc->szCipherSuite ?
+                                         dc->szCipherSuite :
+                                         sc->server->auth.cipher_suite)) {
+            ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+                          "Unable to reconfigure (per-directory) "
+                          "permitted SSL ciphers");
             ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, r->server);
 
             if (cipher_list_old) {
@@ -334,9 +388,14 @@
             sk_SSL_CIPHER_free(cipher_list_old);
         }
 
-        /* tracing */
         if (renegotiate) {
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
+            if (sc->cipher_server_pref == TRUE) {
+                SSL_set_options(ssl, SSL_OP_CIPHER_SERVER_PREFERENCE);
+            }
+#endif
+            /* tracing */
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
                          "Reconfigured cipher suite will force renegotiation");
         }
     }
@@ -348,24 +407,22 @@
      * function and not by OpenSSL internally (and our function is aware of
      * both the per-server and per-directory contexts). So we cannot ask
      * OpenSSL about the currently verify depth. Instead we remember it in our
-     * ap_ctx attached to the SSL* of OpenSSL.  We've to force the
+     * SSLConnRec attached to the SSL* of OpenSSL.  We've to force the
      * renegotiation if the reconfigured/new verify depth is less than the
      * currently active/remembered verify depth (because this means more
      * restriction on the certificate chain).
      */
-    if (dc->nVerifyDepth != UNSET) {
-        /* XXX: doesnt look like sslconn->verify_depth is actually used */
-        if (!(n = sslconn->verify_depth)) {
-            sslconn->verify_depth = n = sc->server->auth.verify_depth;
-        }
-
-        /* determine whether a renegotiation has to be forced */
-        if (dc->nVerifyDepth < n) {
-            renegotiate = TRUE;
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                         "Reduced client verification depth will force "
-                         "renegotiation");
-        }
+    n = sslconn->verify_depth ?
+        sslconn->verify_depth :
+        (mySrvConfig(handshakeserver))->server->auth.verify_depth;
+    /* determine the new depth */
+    sslconn->verify_depth = (dc->nVerifyDepth != UNSET) ?
+                            dc->nVerifyDepth : sc->server->auth.verify_depth;
+    if (sslconn->verify_depth < n) {
+        renegotiate = TRUE;
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                     "Reduced client verification depth will force "
+                     "renegotiation");
     }
 
     /*
@@ -382,18 +439,22 @@
      * verification but at least skip the I/O-intensive renegotation
      * handshake.
      */
-    if (dc->nVerifyClient != SSL_CVERIFY_UNSET) {
+    if ((dc->nVerifyClient != SSL_CVERIFY_UNSET) ||
+        (sc->server->auth.verify_mode != SSL_CVERIFY_UNSET)) {
         /* remember old state */
         verify_old = SSL_get_verify_mode(ssl);
         /* configure new state */
         verify = SSL_VERIFY_NONE;
 
-        if (dc->nVerifyClient == SSL_CVERIFY_REQUIRE) {
+        if ((dc->nVerifyClient == SSL_CVERIFY_REQUIRE) ||
+            (sc->server->auth.verify_mode == SSL_CVERIFY_REQUIRE)) {
             verify |= SSL_VERIFY_PEER_STRICT;
         }
 
         if ((dc->nVerifyClient == SSL_CVERIFY_OPTIONAL) ||
-            (dc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_CA))
+            (dc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_CA) ||
+            (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL) ||
+            (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA))
         {
             verify |= SSL_VERIFY_PEER;
         }
@@ -423,13 +484,51 @@
                     X509_free(peercert);
                 }
 
-                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
-                             r->server,
-                             "Changed client verification type will force "
-                             "%srenegotiation",
-                             renegotiate_quick ? "quick " : "");
+                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                              "Changed client verification type will force "
+                              "%srenegotiation",
+                              renegotiate_quick ? "quick " : "");
              }
         }
+        /* If we're handling a request for a vhost other than the default one,
+         * then we need to make sure that client authentication is properly
+         * enforced. For clients supplying an SNI extension, the peer
+         * certificate verification has happened in the handshake already
+         * (and r->server == handshakeserver). For non-SNI requests,
+         * an additional check is needed here. If client authentication
+         * is configured as mandatory, then we can only proceed if the
+         * CA list doesn't have to be changed (OpenSSL doesn't provide
+         * an option to change the list for an existing session).
+         */
+        if ((r->server != handshakeserver)
+            && renegotiate
+            && ((verify & SSL_VERIFY_PEER) ||
+                (verify & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))) {
+            SSLSrvConfigRec *hssc = mySrvConfig(handshakeserver);
+
+#define MODSSL_CFG_CA_NE(f, sc1, sc2) \
+            (sc1->server->auth.f && \
+             (!sc2->server->auth.f || \
+              strNE(sc1->server->auth.f, sc2->server->auth.f)))
+
+            if (MODSSL_CFG_CA_NE(ca_cert_file, sc, hssc) ||
+                MODSSL_CFG_CA_NE(ca_cert_path, sc, hssc)) {
+                if (verify & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+                    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+                         "Non-default virtual host with SSLVerify set to "
+                         "'require' and VirtualHost-specific CA certificate "
+                         "list is only available to clients with TLS server "
+                         "name indication (SNI) support");
+                    modssl_set_verify(ssl, verify_old, NULL);
+                    return HTTP_FORBIDDEN;
+                } else
+                    /* let it pass, possibly with an "incorrect" peer cert,
+                     * so make sure the SSL_CLIENT_VERIFY environment variable
+                     * will indicate partial success only, later on.
+                     */
+                    sslconn->verify_info = "GENEROUS";
+            }
+        }
     }
 
     /*
@@ -461,9 +560,9 @@
         cert_store = X509_STORE_new();
 
         if (!X509_STORE_load_locations(cert_store, ca_file, ca_path)) {
-            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
-                         "Unable to reconfigure verify locations "
-                         "for client authentication");
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                          "Unable to reconfigure verify locations "
+                          "for client authentication");
             ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, r->server);
 
             X509_STORE_free(cert_store);
@@ -487,9 +586,9 @@
         SSL_set_client_CA_list(ssl, ca_list);
         renegotiate = TRUE;
 
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                     "Changed client verification locations will force "
-                     "renegotiation");
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                      "Changed client verification locations will force "
+                      "renegotiation");
     }
 #endif /* HAVE_SSL_SET_CERT_STORE */
 
@@ -548,14 +647,14 @@
          * here because it resets too much of the connection.  So we set the
          * state explicitly and continue the handshake manually.
          */
-        ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
-                     "Requesting connection re-negotiation");
+        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+                      "Requesting connection re-negotiation");
 
         if (renegotiate_quick) {
             STACK_OF(X509) *cert_stack;
 
             /* perform just a manual re-verification of the peer */
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
                          "Performing quick renegotiation: "
                          "just re-verifying the peer");
 
@@ -574,8 +673,8 @@
             }
 
             if (!cert_stack || (sk_X509_num(cert_stack) == 0)) {
-                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
-                             "Cannot find peer certificate chain");
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                              "Cannot find peer certificate chain");
 
                 return HTTP_FORBIDDEN;
             }
@@ -583,8 +682,8 @@
             if (!(cert_store ||
                   (cert_store = SSL_CTX_get_cert_store(ctx))))
             {
-                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
-                             "Cannot find certificate storage");
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                              "Cannot find certificate storage");
 
                 return HTTP_FORBIDDEN;
             }
@@ -605,8 +704,8 @@
                                        (char *)ssl);
 
             if (!modssl_X509_verify_cert(&cert_store_ctx)) {
-                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
-                             "Re-negotiation verification step failed");
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                              "Re-negotiation verification step failed");
                 ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, r->server);
             }
 
@@ -622,9 +721,9 @@
             request_rec *id = r->main ? r->main : r;
 
             /* do a full renegotiation */
-            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
-                         "Performing full renegotiation: "
-                         "complete handshake protocol");
+            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                          "Performing full renegotiation: "
+                          "complete handshake protocol");
 
             SSL_set_session_id_context(ssl,
                                        (unsigned char *)&id,
@@ -634,15 +733,15 @@
             SSL_do_handshake(ssl);
 
             if (SSL_get_state(ssl) != SSL_ST_OK) {
-                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
-                             "Re-negotiation request failed");
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                              "Re-negotiation request failed");
 
                 r->connection->aborted = 1;
                 return HTTP_FORBIDDEN;
             }
 
-            ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
-                         "Awaiting re-negotiation handshake");
+            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+                          "Awaiting re-negotiation handshake");
 
             /* XXX: Should replace SSL_set_state with SSL_renegotiate(ssl);
              * However, this causes failures in perl-framework currently,
@@ -652,9 +751,9 @@
             SSL_do_handshake(ssl);
 
             if (SSL_get_state(ssl) != SSL_ST_OK) {
-                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
-                             "Re-negotiation handshake failed: "
-                        "Not accepted by client!?");
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                              "Re-negotiation handshake failed: "
+                              "Not accepted by client!?");
 
                 r->connection->aborted = 1;
                 return HTTP_FORBIDDEN;
@@ -675,22 +774,24 @@
         /*
          * Finally check for acceptable renegotiation results
          */
-        if (dc->nVerifyClient != SSL_CVERIFY_NONE) {
-            BOOL do_verify = (dc->nVerifyClient == SSL_CVERIFY_REQUIRE);
+        if ((dc->nVerifyClient != SSL_CVERIFY_NONE) ||
+            (sc->server->auth.verify_mode != SSL_CVERIFY_NONE)) {
+            BOOL do_verify = ((dc->nVerifyClient == SSL_CVERIFY_REQUIRE) ||
+                              (sc->server->auth.verify_mode == SSL_CVERIFY_REQUIRE));
 
             if (do_verify && (SSL_get_verify_result(ssl) != X509_V_OK)) {
-                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
-                             "Re-negotiation handshake failed: "
-                             "Client verification failed");
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                              "Re-negotiation handshake failed: "
+                              "Client verification failed");
 
                 return HTTP_FORBIDDEN;
             }
 
             if (do_verify) {
                 if ((peercert = SSL_get_peer_certificate(ssl)) == NULL) {
-                    ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
-                                 "Re-negotiation handshake failed: "
-                                 "Client certificate missing");
+                    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                                  "Re-negotiation handshake failed: "
+                                  "Client certificate missing");
 
                     return HTTP_FORBIDDEN;
                 }
@@ -756,13 +857,13 @@
         }
 
         if (ok != 1) {
-            ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
-                         "Access to %s denied for %s "
-                         "(requirement expression not fulfilled)",
-                         r->filename, r->connection->remote_ip);
+            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+                          "Access to %s denied for %s "
+                          "(requirement expression not fulfilled)",
+                          r->filename, r->connection->remote_ip);
 
-            ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
-                         "Failed expression: %s", req->cpExpr);
+            ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+                          "Failed expression: %s", req->cpExpr);
 
             ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                           "access to %s failed, reason: %s",
@@ -887,9 +988,9 @@
                             NULL);
     apr_table_set(r->headers_in, "Authorization", auth_line);
 
-    ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
-                 "Faking HTTP Basic Auth header: \"Authorization: %s\"",
-                 auth_line);
+    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+                  "Faking HTTP Basic Auth header: \"Authorization: %s\"",
+                  auth_line);
 
     return DECLINED;
 }
@@ -1006,6 +1107,9 @@
     SSLDirConfigRec *dc = myDirConfig(r);
     apr_table_t *env = r->subprocess_env;
     char *var, *val = "";
+#ifndef OPENSSL_NO_TLSEXT
+    const char *servername;
+#endif
     STACK_OF(X509) *peer_certs;
     SSL *ssl;
     int i;
@@ -1027,6 +1131,13 @@
     /* the always present HTTPS (=HTTP over SSL) flag! */
     apr_table_setn(env, "HTTPS", "on");
 
+#ifndef OPENSSL_NO_TLSEXT
+    /* add content of SNI TLS extension (if supplied with ClientHello) */
+    if ((servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
+        apr_table_set(env, "SSL_TLS_SNI", servername);
+    }
+#endif
+
     /* standard SSL environment variables */
     if (dc->nOptions & SSL_OPT_STDENVVARS) {
         for (i = 0; ssl_hook_Fixup_vars[i]; i++) {
@@ -1114,7 +1225,7 @@
 RSA *ssl_callback_TmpRSA(SSL *ssl, int export, int keylen)
 {
     conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
-    SSLModConfigRec *mc = myModConfig(c->base_server);
+    SSLModConfigRec *mc = myModConfigFromConn(c);
     int idx;
 
     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
@@ -1146,7 +1257,7 @@
 DH *ssl_callback_TmpDH(SSL *ssl, int export, int keylen)
 {
     conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
-    SSLModConfigRec *mc = myModConfig(c->base_server);
+    SSLModConfigRec *mc = myModConfigFromConn(c);
     int idx;
 
     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
@@ -1175,8 +1286,8 @@
     SSL *ssl = X509_STORE_CTX_get_ex_data(ctx,
                                           SSL_get_ex_data_X509_STORE_CTX_idx());
     conn_rec *conn      = (conn_rec *)SSL_get_app_data(ssl);
-    server_rec *s       = conn->base_server;
     request_rec *r      = (request_rec *)SSL_get_app_data2(ssl);
+    server_rec *s       = r ? r->server : mySrvFromConn(conn);
 
     SSLSrvConfigRec *sc = mySrvConfig(s);
     SSLDirConfigRec *dc = r ? myDirConfig(r) : NULL;
@@ -1196,12 +1307,12 @@
         char *sname = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
         char *iname = X509_NAME_oneline(X509_get_issuer_name(cert),  NULL, 0);
 
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                     "Certificate Verification: "
-                     "depth: %d, subject: %s, issuer: %s",
-                     errdepth,
-                     sname ? sname : "-unknown-",
-                     iname ? iname : "-unknown-");
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, conn,
+                      "Certificate Verification: "
+                      "depth: %d, subject: %s, issuer: %s",
+                      errdepth,
+                      sname ? sname : "-unknown-",
+                      iname ? iname : "-unknown-");
 
         if (sname) {
             modssl_free(sname);
@@ -1234,10 +1345,10 @@
     if (ssl_verify_error_is_optional(errnum) &&
         (verify == SSL_CVERIFY_OPTIONAL_NO_CA))
     {
-        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
-                     "Certificate Verification: Verifiable Issuer is "
-                     "configured as optional, therefore we're accepting "
-                     "the certificate");
+        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, conn,
+                      "Certificate Verification: Verifiable Issuer is "
+                      "configured as optional, therefore we're accepting "
+                      "the certificate");
 
         sslconn->verify_info = "GENEROUS";
         ok = TRUE;
@@ -1256,9 +1367,9 @@
      * If we already know it's not ok, log the real reason
      */
     if (!ok) {
-        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
-                     "Certificate Verification: Error (%d): %s",
-                     errnum, X509_verify_cert_error_string(errnum));
+        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, conn,
+                      "Certificate Verification: Error (%d): %s",
+                      errnum, X509_verify_cert_error_string(errnum));
 
         if (sslconn->client_cert) {
             X509_free(sslconn->client_cert);
@@ -1279,11 +1390,11 @@
     }
 
     if (errdepth > depth) {
-        ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
-                     "Certificate Verification: Certificate Chain too long "
-                     "(chain has %d certificates, but maximum allowed are "
-                     "only %d)",
-                     errdepth, depth);
+        ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, conn,
+                      "Certificate Verification: Certificate Chain too long "
+                      "(chain has %d certificates, but maximum allowed are "
+                      "only %d)",
+                      errdepth, depth);
 
         errnum = X509_V_ERR_CERT_CHAIN_TOO_LONG;
         sslconn->verify_error = X509_verify_cert_error_string(errnum);
@@ -1299,7 +1410,10 @@
 
 int ssl_callback_SSLVerify_CRL(int ok, X509_STORE_CTX *ctx, conn_rec *c)
 {
-    server_rec *s       = c->base_server;
+    SSL *ssl = X509_STORE_CTX_get_ex_data(ctx,
+                                          SSL_get_ex_data_X509_STORE_CTX_idx());
+    request_rec *r      = (request_rec *)SSL_get_app_data2(ssl);
+    server_rec *s       = r ? r->server : mySrvFromConn(c);
     SSLSrvConfigRec *sc = mySrvConfig(s);
     SSLConnRec *sslconn = myConnConfig(c);
     modssl_ctx_t *mctx  = myCtxConfig(sslconn, sc);
@@ -1524,7 +1638,7 @@
 int ssl_callback_proxy_cert(SSL *ssl, MODSSL_CLIENT_CERT_CB_ARG_TYPE **x509, EVP_PKEY **pkey)
 {
     conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
-    server_rec *s = c->base_server;
+    server_rec *s = mySrvFromConn(c);
     SSLSrvConfigRec *sc = mySrvConfig(s);
     X509_NAME *ca_name, *issuer;
     X509_INFO *info;
@@ -1622,7 +1736,7 @@
 {
     /* Get Apache context back through OpenSSL context */
     conn_rec *conn      = (conn_rec *)SSL_get_app_data(ssl);
-    server_rec *s       = conn->base_server;
+    server_rec *s       = mySrvFromConn(conn);
     SSLSrvConfigRec *sc = mySrvConfig(s);
     long timeout        = sc->session_cache_timeout;
     BOOL rc;
@@ -1670,7 +1784,7 @@
 {
     /* Get Apache context back through OpenSSL context */
     conn_rec *conn = (conn_rec *)SSL_get_app_data(ssl);
-    server_rec *s  = conn->base_server;
+    server_rec *s  = mySrvFromConn(conn);
     SSL_SESSION *session;
 
     /*
@@ -1748,7 +1862,7 @@
         return;
     }
 
-    s = c->base_server;
+    s = mySrvFromConn(c);
     if (!(sc = mySrvConfig(s))) {
         return;
     }
@@ -1819,3 +1933,138 @@
     }
 }
 
+#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;
+    SSLConnRec *sslcon;
+
+    /* 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) */
+    sslcon = myConnConfig(c);
+    if (found && (ssl = sslcon->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));
+        }
+
+        /*
+         * Save the found server into our SSLConnRec for later
+         * retrieval
+         */
+        sslcon->server = s;
+
+        /*
+         * There is one special filter callback, which is set
+         * very early depending on the base_server's log level.
+         * If this is not the first vhost we're now selecting
+         * (and the first vhost doesn't use APLOG_DEBUG), then
+         * we need to set that callback here.
+         */
+        if (s->loglevel >= APLOG_DEBUG) {
+            BIO_set_callback(SSL_get_rbio(ssl), ssl_io_data_cb);
+            BIO_set_callback_arg(SSL_get_rbio(ssl), (void *)ssl);
+        }
+
+        return 1;
+    }
+
+    return 0;
+}
+#endif

Modified: httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_vars.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_vars.c?rev=776281&r1=776280&r2=776281&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_vars.c (original)
+++ httpd/httpd/branches/2.2.x/modules/ssl/ssl_engine_vars.c Tue May 19 11:44:59 2009
@@ -320,6 +320,12 @@
     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;
 }
 
@@ -589,7 +595,7 @@
     vrc   = SSL_get_verify_result(ssl);
     xs    = SSL_get_peer_certificate(ssl);
 
-    if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs == NULL)
+    if (vrc == X509_V_OK && verr == NULL && xs == NULL)
         /* no client verification done at all */
         result = "NONE";
     else if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs != NULL)

Modified: httpd/httpd/branches/2.2.x/modules/ssl/ssl_private.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/ssl/ssl_private.h?rev=776281&r1=776280&r2=776281&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/ssl/ssl_private.h (original)
+++ httpd/httpd/branches/2.2.x/modules/ssl/ssl_private.h Tue May 19 11:44:59 2009
@@ -35,6 +35,7 @@
 #include "http_connection.h"
 #include "http_request.h"
 #include "http_protocol.h"
+#include "http_vhost.h"
 #include "util_script.h"
 #include "util_filter.h"
 #include "util_ebcdic.h"
@@ -129,6 +130,9 @@
 #define mySrvConfig(srv) (SSLSrvConfigRec *)ap_get_module_config(srv->module_config,  &ssl_module)
 #define myDirConfig(req) (SSLDirConfigRec *)ap_get_module_config(req->per_dir_config, &ssl_module)
 #define myModConfig(srv) (mySrvConfig((srv)))->mc
+#define mySrvFromConn(c) (myConnConfig(c))->server
+#define mySrvConfigFromConn(c) mySrvConfig(mySrvFromConn(c))
+#define myModConfigFromConn(c) myModConfig(mySrvFromConn(c))
 
 #define myCtxVarSet(mc,num,val)  mc->rCtx.pV##num = val
 #define myCtxVarGet(mc,num,type) (type)(mc->rCtx.pV##num)
@@ -352,6 +356,7 @@
     int is_proxy;
     int disabled;
     int non_ssl_request;
+    server_rec *server;
 } SSLConnRec;
 
 typedef struct {
@@ -456,6 +461,9 @@
     modssl_ctx_t    *proxy;
     ssl_enabled_t    proxy_ssl_check_peer_expire;
     ssl_enabled_t    proxy_ssl_check_peer_cn;
+#ifndef OPENSSL_NO_TLSEXT
+    ssl_enabled_t    strict_sni_vhost_check;
+#endif
 };
 
 /**
@@ -522,6 +530,7 @@
 const char  *ssl_cmd_SSLRequire(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLUserName(cmd_parms *, void *, const char *);
 const char  *ssl_cmd_SSLRenegBufferSize(cmd_parms *cmd, void *dcfg, const char *arg);
+const char  *ssl_cmd_SSLStrictSNIVHostCheck(cmd_parms *cmd, void *dcfg, int flag);
 
 const char  *ssl_cmd_SSLProxyEngine(cmd_parms *cmd, void *dcfg, int flag);
 const char  *ssl_cmd_SSLProxyProtocol(cmd_parms *, void *, const char *);
@@ -566,6 +575,9 @@
 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 *);

Modified: httpd/httpd/branches/2.2.x/modules/ssl/ssl_toolkit_compat.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/modules/ssl/ssl_toolkit_compat.h?rev=776281&r1=776280&r2=776281&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/modules/ssl/ssl_toolkit_compat.h (original)
+++ httpd/httpd/branches/2.2.x/modules/ssl/ssl_toolkit_compat.h Tue May 19 11:44:59 2009
@@ -264,6 +264,12 @@
 #define SSL_SESS_CACHE_NO_INTERNAL  SSL_SESS_CACHE_NO_INTERNAL_LOOKUP
 #endif
 
+#ifndef OPENSSL_NO_TLSEXT
+#ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME
+#define OPENSSL_NO_TLSEXT
+#endif
+#endif
+
 #endif /* SSL_TOOLKIT_COMPAT_H */
 
 /** @} */



Mime
View raw message