]> granicus.if.org Git - apache/commitdiff
Restructured server name indication support (PR 34607);
authorGuenter Knauf <fuankg@apache.org>
Fri, 11 Jan 2008 16:04:26 +0000 (16:04 +0000)
committerGuenter Knauf <fuankg@apache.org>
Fri, 11 Jan 2008 16:04:26 +0000 (16:04 +0000)
added missing client cert support.
Submitted by: Kaspar Brand <asfbugz velox.ch>

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@611216 13f79535-47bb-0310-9956-ffa450edef68

modules/ssl/ssl_engine_init.c
modules/ssl/ssl_engine_kernel.c
modules/ssl/ssl_engine_vars.c
modules/ssl/ssl_private.h

index ecaf0172ff61844885adb7f73ac42c3b3e2462d1..87ccf2bbaa58c7878aa0fd69384ff23a81398ec6 100644 (file)
@@ -135,87 +135,6 @@ static int ssl_tmp_keys_init(server_rec *s)
     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
  */
@@ -436,29 +355,32 @@ static void ssl_init_server_check(server_rec *s,
     }
 }
 
-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,
@@ -816,7 +738,9 @@ static void ssl_init_ctx(server_rec *s,
     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
     }
 }
 
@@ -1110,16 +1034,13 @@ void ssl_init_ConfigureServer(server_rec *s,
 
 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
@@ -1147,7 +1068,6 @@ void ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p)
         }
     }
 
-#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
@@ -1172,7 +1092,11 @@ void ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p)
         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"),
@@ -1189,10 +1113,15 @@ void ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p)
 
     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
index 84a4806860b345f7d4a1b2935c04245457fdd4ea..e37d903331df16ca8c358216ce5fcaf75b6d2a52 100644 (file)
@@ -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
 
 #define SWITCH_STATUS_LINE "HTTP/1.1 101 Switching Protocols"
 #define UPGRADE_HEADER "Upgrade: TLS/1.0, HTTP/1.1"
@@ -92,6 +95,9 @@ int ssl_hook_ReadReq(request_rec *r)
     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,
@@ -153,6 +159,14 @@ int ssl_hook_ReadReq(request_rec *r)
     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);
 
     /*
@@ -297,16 +311,6 @@ int ssl_hook_Access(request_rec *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
      *
@@ -1074,7 +1078,7 @@ int ssl_hook_Fixup(request_rec *r)
     apr_table_t *env = r->subprocess_env;
     char *var, *val = "";
 #ifndef OPENSSL_NO_TLSEXT
-    const charservername;
+    const char *servername;
 #endif
     STACK_OF(X509) *peer_certs;
     SSL *ssl;
@@ -1909,3 +1913,118 @@ void ssl_callback_LogTracingState(MODSSL_INFO_CB_ARG_TYPE ssl, int where, int rc
     }
 }
 
+#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
index 50b6e460017ed04ab8f11aea8b5d68e3b7d0cb09..3d688cd7389ed191b3431c3fd9769bea380a42ca 100644 (file)
@@ -320,6 +320,12 @@ static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, char *var)
     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;
 }
 
index 5243df80d5bb8d017af8849a399693f32b26152e..eaac13e6ab56ffca96d6a2a4ed9b1b8ad2d8d934 100644 (file)
@@ -581,6 +581,9 @@ int          ssl_callback_NewSessionCacheEntry(SSL *, SSL_SESSION *);
 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 *);
@@ -727,11 +730,6 @@ OCSP_RESPONSE *modssl_dispatch_ocsp_request(const apr_uri_t *uri,
                                             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 */
 /** @} */