Kamesh Jayachandran wrote:
> Reasonable fix for this on the server side is to apply SSL_OP_NO_TICKET 
> patch and enable SSLSessionCache.

There is actually another reason why disabling TLS session tickets makes
sense at the present time: with OpenSSL's current stable version
(0.9.8k), session tickets only work properly for the first/default
vhost. For all other vhosts, mod_ssl will fail to decrypt a
previously-generated ticket, due to the order in which OpenSSL currently
deals with the SNI and ticket extensions (and their callbacks). The
consequence is that with 2.2.x and an SNI configuration, session caching
for clients supporting TLS tickets is not working for all but the first
vhost.

The attached patch (for trunk, plus a backport for 2.2.x) includes two
proposed changes:

1) When configuring a new SSL context (in
ssl_engine_init.c:ssl_init_ctx_tls_extensions), it disables session
ticket support if a server-side session cache is configured. Enabling
both session tickets and a cache for stateful resumption at the same
time doesn't make that much sense anyway, IMO. This change will also
solve the issue with OpenSSL clients (as reported by Kamesh), provided
that a server-side cache is configured.

2) In the SNI callback, it adjusts OpenSSL's session id context - which
makes sure that the session can be properly resumed. (With the current
mod_ssl code, this context is always tied to the first vhost, possibly
resulting in incorrect resumption behavior.)

The first change might later be revised, depending on how future OpenSSL
versions deal with the combination of SNI + session tickets (work is
underway in this area). But given the fact that OpenSSL versions between
0.9.8f and 0.9.8k will stay around for quite some time, I consider this
the appropriate fix for the time being (later on, it could be #if'd
based on OPENSSL_VERSION_NUMBER, or maybe even made configurable through
an additional directive).

Kaspar
Index: httpd-trunk/modules/ssl/ssl_engine_init.c
===================================================================
--- httpd-trunk/modules/ssl/ssl_engine_init.c   (revision 832299)
+++ httpd-trunk/modules/ssl/ssl_engine_init.c   (working copy)
@@ -390,6 +390,13 @@ static void ssl_init_ctx_tls_extensions(
         ssl_die();
     }
 
+    /*
+     * Disable TLS session tickets if a session cache is configured
+     */
+    if ((myModConfig(s))->nSessionCacheMode != SSL_SCMODE_NONE) {
+        SSL_CTX_set_options(mctx->ssl_ctx, SSL_OP_NO_TICKET);
+    }
+
 #ifdef HAVE_OCSP_STAPLING
     /*
      * OCSP Stapling support, status_request extension
Index: httpd-trunk/modules/ssl/ssl_engine_kernel.c
===================================================================
--- httpd-trunk/modules/ssl/ssl_engine_kernel.c (revision 832299)
+++ httpd-trunk/modules/ssl/ssl_engine_kernel.c (working copy)
@@ -29,6 +29,7 @@
                                   time I was too famous.''
                                             -- Unknown                */
 #include "ssl_private.h"
+#include "util_md5.h"
 
 static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn);
 #ifndef OPENSSL_NO_TLSEXT
@@ -1949,6 +1950,7 @@ static int ssl_find_vhost(void *serverna
     apr_array_header_t *names;
     int i;
     SSLConnRec *sslcon;
+    char *sid_ctx;
 
     /* check ServerName */
     if (!strcasecmp(servername, s->server_hostname)) {
@@ -2013,6 +2015,21 @@ static int ssl_find_vhost(void *serverna
             SSL_set_verify(ssl, SSL_CTX_get_verify_mode(ssl->ctx),
                            SSL_CTX_get_verify_callback(ssl->ctx));
         }
+        /*
+         * Adjust the session id context. ssl_init_ssl_connection()
+         * always picks the configuration of the first vhost when
+         * calling SSL_new(), but we want to tie the session to the
+         * vhost we have just switched to. Again, we have to make sure
+         * that we're not overwriting a session id context which was
+         * possibly set in ssl_hook_Access(), before triggering
+         * a renegotation.
+         */
+        if (!SSL_num_renegotiations(ssl)) {
+            sid_ctx = ap_md5_binary(c->pool, (unsigned char*)sc->vhost_id,
+                                    sc->vhost_id_len);
+            SSL_set_session_id_context(ssl, (unsigned char *)sid_ctx,
+                                       APR_MD5_DIGESTSIZE*2);
+        }
 
         /*
          * Save the found server into our SSLConnRec for later
Index: httpd-2.2.x/modules/ssl/ssl_engine_init.c
===================================================================
--- httpd-2.2.x/modules/ssl/ssl_engine_init.c   (revision 831939)
+++ httpd-2.2.x/modules/ssl/ssl_engine_init.c   (working copy)
@@ -382,6 +382,13 @@ static void ssl_init_ctx_tls_extensions(
         ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s);
         ssl_die();
     }
+
+    /*
+     * Disable TLS session tickets if a session cache is configured
+     */
+    if ((myModConfig(s))->nSessionCacheMode != SSL_SCMODE_NONE) {
+        SSL_CTX_set_options(mctx->ssl_ctx, SSL_OP_NO_TICKET);
+    }
 }
 #endif
 
Index: httpd-2.2.x/modules/ssl/ssl_engine_kernel.c
===================================================================
--- httpd-2.2.x/modules/ssl/ssl_engine_kernel.c (revision 831939)
+++ httpd-2.2.x/modules/ssl/ssl_engine_kernel.c (working copy)
@@ -29,6 +29,7 @@
                                   time I was too famous.''
                                             -- Unknown                */
 #include "ssl_private.h"
+#include "util_md5.h"
 
 static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn);
 #ifndef OPENSSL_NO_TLSEXT
@@ -1979,6 +1980,7 @@ static int ssl_find_vhost(void *serverna
     apr_array_header_t *names;
     int i;
     SSLConnRec *sslcon;
+    char *sid_ctx;
 
     /* check ServerName */
     if (!strcasecmp(servername, s->server_hostname)) {
@@ -2043,6 +2045,21 @@ static int ssl_find_vhost(void *serverna
             SSL_set_verify(ssl, SSL_CTX_get_verify_mode(ssl->ctx),
                            SSL_CTX_get_verify_callback(ssl->ctx));
         }
+        /*
+         * Adjust the session id context. ssl_init_ssl_connection()
+         * always picks the configuration of the first vhost when
+         * calling SSL_new(), but we want to tie the session to the
+         * vhost we have just switched to. Again, we have to make sure
+         * that we're not overwriting a session id context which was
+         * possibly set in ssl_hook_Access(), before triggering
+         * a renegotation.
+         */
+        if (!SSL_num_renegotiations(ssl)) {
+            sid_ctx = ap_md5_binary(c->pool, (unsigned char*)sc->vhost_id,
+                                    sc->vhost_id_len);
+            SSL_set_session_id_context(ssl, (unsigned char *)sid_ctx,
+                                       APR_MD5_DIGESTSIZE*2);
+        }
 
         /*
          * Save the found server into our SSLConnRec for later

Reply via email to