Dr Stephen Henson wrote:
> Yes that looks better. There is an alternative technique if it is easier to
> find
> a "base" SSL_CTX, you can retrieve the auto generated keys using
> SSL_CTX_get_tlsext_ticket_keys() and then copy to the new context as above.
The loop actually iterates over all contexts, so we could just remember
the keys of the first SSL-enabled vhost, we don't have to find the
"base" context. I.e., simply replace
RAND_bytes(tlsext_tick_keys, tick_keys_len);
by
SSL_CTX_get_tlsext_ticket_keys(sc->server->ssl_ctx,
tlsext_tick_keys, tick_keys_len);
I prefer the former, however, because 1) it's shorter, 2) RAND_bytes are
cheap (aren't they? ;-) and 3) ... it would actually need another
workaround, for OpenSSL < 0.9.8l, as I realized in the meantime: I
should have compiled against 0.9.8k for my tests, not 0_9_8-stable -
because this way I missed the TLXEXT_TICKET_KEYS typo :-/ In the
attached patches (v4), I've therefore added a workaround for
SSL_CTRL_SET_TLXEXT_TICKET_KEYS.
And back to the question whether ap_md5_binary should be used or not, I
have now switched to apr_sha1 for the trunk version - maybe that's an
acceptable compromise (use SHA-1 for trunk, stay with MD5 in 2.2.x, for
backward compatibility)?
Could one of the httpd committers take over and make a decision,
therefore...? Help with getting this into the tree would be much
appreciated - thanks!
Kaspar
Index: httpd-trunk/modules/ssl/ssl_private.h
===================================================================
--- httpd-trunk/modules/ssl/ssl_private.h (revision 833672)
+++ httpd-trunk/modules/ssl/ssl_private.h (working copy)
@@ -405,6 +405,9 @@ typedef struct {
#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
const char *szCryptoDevice;
#endif
+#ifndef OPENSSL_NO_TLSEXT
+ ssl_enabled_t session_tickets_enabled;
+#endif
#ifdef HAVE_OCSP_STAPLING
const ap_socache_provider_t *stapling_cache;
@@ -585,6 +588,7 @@ const char *ssl_cmd_SSLUserName(cmd_par
const char *ssl_cmd_SSLLogLevelDebugDump(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_SSLSessionTicketExtension(cmd_parms *cmd, void *cdfg, int
flag);
const char *ssl_cmd_SSLProxyEngine(cmd_parms *cmd, void *dcfg, int flag);
const char *ssl_cmd_SSLProxyProtocol(cmd_parms *, void *, const char *);
Index: httpd-trunk/modules/ssl/ssl_engine_init.c
===================================================================
--- httpd-trunk/modules/ssl/ssl_engine_init.c (revision 833672)
+++ httpd-trunk/modules/ssl/ssl_engine_init.c (working copy)
@@ -363,6 +363,15 @@ static void ssl_init_server_check(server
"(theoretically shouldn't happen!)");
ssl_die();
}
+
+ /*
+ * Session tickets (stateless resumption)
+ */
+ if ((myModConfig(s))->session_tickets_enabled == SSL_ENABLED_FALSE) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+ "Disabling TLS session ticket support");
+ SSL_CTX_set_options(mctx->ssl_ctx, SSL_OP_NO_TICKET);
+ }
}
#ifndef OPENSSL_NO_TLSEXT
@@ -1061,6 +1070,11 @@ void ssl_init_CheckServers(server_rec *b
BOOL conflict = FALSE;
+#if !defined(OPENSSL_NO_TLSEXT) && OPENSSL_VERSION_NUMBER < 0x009080d0
+ unsigned char *tlsext_tick_keys = NULL;
+ long tick_keys_len;
+#endif
+
/*
* Give out warnings when a server has HTTPS configured
* for the HTTP port or vice versa
@@ -1085,6 +1099,27 @@ void ssl_init_CheckServers(server_rec *b
ssl_util_vhostid(p, s),
DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT);
}
+
+#if !defined(OPENSSL_NO_TLSEXT) && OPENSSL_VERSION_NUMBER < 0x009080d0
+/* we have to work around a typo in OpenSSL < 0.9.8l, too */
+#define SSL_CTRL_SET_TLXEXT_TICKET_KEYS SSL_CTRL_SET_TLSEXT_TICKET_KEYS
+ /*
+ * When using OpenSSL versions 0.9.8f through 0.9.8l, configure
+ * the same ticket encryption parameters for every SSL_CTX (workaround
+ * for SNI+SessionTicket extension interoperability issue in these
versions)
+ */
+ if ((sc->enabled == SSL_ENABLED_TRUE) ||
+ (sc->enabled == SSL_ENABLED_OPTIONAL)) {
+ if (!tlsext_tick_keys) {
+ tick_keys_len =
SSL_CTX_set_tlsext_ticket_keys(sc->server->ssl_ctx,
+ NULL, -1);
+ tlsext_tick_keys = (unsigned char *)apr_palloc(p,
tick_keys_len);
+ RAND_bytes(tlsext_tick_keys, tick_keys_len);
+ }
+ SSL_CTX_set_tlsext_ticket_keys(sc->server->ssl_ctx,
+ tlsext_tick_keys, tick_keys_len);
+ }
+#endif
}
/*
Index: httpd-trunk/modules/ssl/ssl_engine_config.c
===================================================================
--- httpd-trunk/modules/ssl/ssl_engine_config.c (revision 833672)
+++ httpd-trunk/modules/ssl/ssl_engine_config.c (working copy)
@@ -80,6 +80,9 @@ SSLModConfigRec *ssl_config_global_creat
mc->stapling_mutex_file = NULL;
mc->stapling_mutex = NULL;
#endif
+#ifndef OPENSSL_NO_TLSEXT
+ mc->session_tickets_enabled = SSL_ENABLED_UNSET;
+#endif
memset(mc->pTmpKeys, 0, sizeof(mc->pTmpKeys));
@@ -1673,6 +1676,26 @@ const char *ssl_cmd_SSLStaplingForceURL(
#endif /* HAVE_OCSP_STAPLING */
+const char *ssl_cmd_SSLSessionTicketExtension(cmd_parms *cmd, void *dcfg, int
flag)
+{
+#ifndef OPENSSL_NO_TLSEXT
+ const char *err;
+ SSLModConfigRec *mc = myModConfig(cmd->server);
+
+ if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
+ return err;
+ }
+
+ mc->session_tickets_enabled = flag ? SSL_ENABLED_TRUE : SSL_ENABLED_FALSE;
+
+ return NULL;
+#else
+ return "SSLSessionTicketExtension failed; OpenSSL is not built with
support "
+ "for TLS extensions. 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")) {
Index: httpd-trunk/modules/ssl/ssl_engine_kernel.c
===================================================================
--- httpd-trunk/modules/ssl/ssl_engine_kernel.c (revision 833672)
+++ 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 "apr_sha1.h"
static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn);
#ifndef OPENSSL_NO_TLSEXT
@@ -2044,6 +2045,26 @@ 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)) {
+ unsigned char vhost_sha1[APR_SHA1_DIGESTSIZE];
+ apr_sha1_ctx_t sha1ctx;
+
+ apr_sha1_init(&sha1ctx);
+ apr_sha1_update_binary(&sha1ctx, (unsigned char *)sc->vhost_id,
+ sc->vhost_id_len);
+ apr_sha1_final(vhost_sha1, &sha1ctx);
+
+ SSL_set_session_id_context(ssl, vhost_sha1, APR_SHA1_DIGESTSIZE);
+ }
/*
* Save the found server into our SSLConnRec for later
Index: httpd-trunk/modules/ssl/mod_ssl.c
===================================================================
--- httpd-trunk/modules/ssl/mod_ssl.c (revision 833672)
+++ httpd-trunk/modules/ssl/mod_ssl.c (working copy)
@@ -26,9 +26,9 @@
#include "ssl_private.h"
#include "mod_ssl.h"
-#include "util_md5.h"
#include "util_mutex.h"
#include "ap_provider.h"
+#include "apr_sha1.h"
#include <assert.h>
@@ -70,6 +70,8 @@ static const command_rec ssl_config_cmds
SSL_CMD_SRV(RandomSeed, TAKE23,
"SSL Pseudo Random Number Generator (PRNG) seeding source "
"('startup|connect builtin|file:/path|exec:/path [bytes]')")
+ SSL_CMD_SRV(SessionTicketExtension, FLAG,
+ "TLS Session Ticket extension support")
/*
* Per-server context configuration directives
@@ -382,9 +384,10 @@ int ssl_init_ssl_connection(conn_rec *c,
SSLSrvConfigRec *sc;
SSL *ssl;
SSLConnRec *sslconn = myConnConfig(c);
- char *vhost_md5;
modssl_ctx_t *mctx;
server_rec *server;
+ unsigned char vhost_sha1[APR_SHA1_DIGESTSIZE];
+ apr_sha1_ctx_t sha1ctx;
if (!sslconn) {
sslconn = ssl_init_connection_ctx(c);
@@ -415,14 +418,15 @@ int ssl_init_ssl_connection(conn_rec *c,
return DECLINED; /* XXX */
}
- vhost_md5 = ap_md5_binary(c->pool, (unsigned char *)sc->vhost_id,
- sc->vhost_id_len);
+ apr_sha1_init(&sha1ctx);
+ apr_sha1_update_binary(&sha1ctx, (unsigned char *)sc->vhost_id,
+ sc->vhost_id_len);
+ apr_sha1_final(vhost_sha1, &sha1ctx);
- if (!SSL_set_session_id_context(ssl, (unsigned char *)vhost_md5,
- APR_MD5_DIGESTSIZE*2))
+ if (!SSL_set_session_id_context(ssl, vhost_sha1, APR_SHA1_DIGESTSIZE))
{
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
- "Unable to set session id context to '%s'", vhost_md5);
+ "Unable to set SSL session id context");
ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, server);
c->aborted = 1;
Index: httpd-trunk/docs/manual/mod/mod_ssl.xml
===================================================================
--- httpd-trunk/docs/manual/mod/mod_ssl.xml (revision 833672)
+++ httpd-trunk/docs/manual/mod/mod_ssl.xml (working copy)
@@ -1849,4 +1849,35 @@ certificate being validated references a
</usage>
</directivesynopsis>
+<directivesynopsis>
+<name>SSLSessionTicketExtension</name>
+<description>Configure TLS session ticket extension support</description>
+<syntax>SSLSessionTicketExtension on|off</syntax>
+<default>SSLSessionTicketExtension on</default>
+<contextlist><context>server config</context></contextlist>
+<compatibility>Available in Apache 2.2.15 and later</compatibility>
+
+<usage>
+<p>
+This directive configures support for TLS session tickets (stateless session
+resumption, cf. RFC 5077). Session tickets are enabled by default when mod_ssl
+is compiled against an OpenSSL version which includes this option. They can
+coexist with a stateful session cache (configured through
+<directive module="mod_ssl">SSLSessionCache</directive>);
+it is then up to the client to choose between stateful and stateless session
+resumption.</p>
+
+<p>
+Clients based on OpenSSL versions 0.9.8f through 0.9.8l are known to
+have problems (<code>parse tlsext</code> errors) when using the SNI and session
+ticket extensions at the same time. As a workaround for interoperability issues
+like these, this directive allows to completely turn off TLS session ticket
support
+at the server side.</p>
+
+<example><title>Example</title>
+SSLSessionTicketExtension off
+</example>
+</usage>
+</directivesynopsis>
+
</modulesynopsis>
Index: httpd-2.2.x/modules/ssl/ssl_private.h
===================================================================
--- httpd-2.2.x/modules/ssl/ssl_private.h (revision 833672)
+++ httpd-2.2.x/modules/ssl/ssl_private.h (working copy)
@@ -395,6 +395,9 @@ typedef struct {
#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
const char *szCryptoDevice;
#endif
+#ifndef OPENSSL_NO_TLSEXT
+ ssl_enabled_t session_tickets_enabled;
+#endif
struct {
void *pV1, *pV2, *pV3, *pV4, *pV5, *pV6, *pV7, *pV8, *pV9, *pV10;
} rCtx;
@@ -545,6 +548,7 @@ const char *ssl_cmd_SSLRequire(cmd_parm
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_SSLSessionTicketExtension(cmd_parms *cmd, void *cdfg, int
flag);
const char *ssl_cmd_SSLProxyEngine(cmd_parms *cmd, void *dcfg, int flag);
const char *ssl_cmd_SSLProxyProtocol(cmd_parms *, void *, const char *);
Index: httpd-2.2.x/modules/ssl/ssl_engine_init.c
===================================================================
--- httpd-2.2.x/modules/ssl/ssl_engine_init.c (revision 833672)
+++ httpd-2.2.x/modules/ssl/ssl_engine_init.c (working copy)
@@ -382,6 +382,15 @@ static void ssl_init_ctx_tls_extensions(
ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s);
ssl_die();
}
+
+ /*
+ * Session tickets (stateless resumption)
+ */
+ if ((myModConfig(s))->session_tickets_enabled == SSL_ENABLED_FALSE) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+ "Disabling TLS session ticket support");
+ SSL_CTX_set_options(mctx->ssl_ctx, SSL_OP_NO_TICKET);
+ }
}
#endif
@@ -1018,6 +1027,11 @@ void ssl_init_CheckServers(server_rec *b
BOOL conflict = FALSE;
+#if !defined(OPENSSL_NO_TLSEXT) && OPENSSL_VERSION_NUMBER < 0x009080d0
+ unsigned char *tlsext_tick_keys = NULL;
+ long tick_keys_len;
+#endif
+
/*
* Give out warnings when a server has HTTPS configured
* for the HTTP port or vice versa
@@ -1042,6 +1056,27 @@ void ssl_init_CheckServers(server_rec *b
ssl_util_vhostid(p, s),
DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT);
}
+
+#if !defined(OPENSSL_NO_TLSEXT) && OPENSSL_VERSION_NUMBER < 0x009080d0
+/* we have to work around a typo in OpenSSL < 0.9.8l, too */
+#define SSL_CTRL_SET_TLXEXT_TICKET_KEYS SSL_CTRL_SET_TLSEXT_TICKET_KEYS
+ /*
+ * When using OpenSSL versions 0.9.8f through 0.9.8l, configure
+ * the same ticket encryption parameters for every SSL_CTX (workaround
+ * for SNI+SessionTicket extension interoperability issue in these
versions)
+ */
+ if ((sc->enabled == SSL_ENABLED_TRUE) ||
+ (sc->enabled == SSL_ENABLED_OPTIONAL)) {
+ if (!tlsext_tick_keys) {
+ tick_keys_len =
SSL_CTX_set_tlsext_ticket_keys(sc->server->ssl_ctx,
+ NULL, -1);
+ tlsext_tick_keys = (unsigned char *)apr_palloc(p,
tick_keys_len);
+ RAND_bytes(tlsext_tick_keys, tick_keys_len);
+ }
+ SSL_CTX_set_tlsext_ticket_keys(sc->server->ssl_ctx,
+ tlsext_tick_keys, tick_keys_len);
+ }
+#endif
}
/*
Index: httpd-2.2.x/modules/ssl/ssl_engine_config.c
===================================================================
--- httpd-2.2.x/modules/ssl/ssl_engine_config.c (revision 833672)
+++ httpd-2.2.x/modules/ssl/ssl_engine_config.c (working copy)
@@ -75,6 +75,9 @@ SSLModConfigRec *ssl_config_global_creat
#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
mc->szCryptoDevice = NULL;
#endif
+#ifndef OPENSSL_NO_TLSEXT
+ mc->session_tickets_enabled = SSL_ENABLED_UNSET;
+#endif
memset(mc->pTmpKeys, 0, sizeof(mc->pTmpKeys));
@@ -1471,6 +1474,26 @@ const char *ssl_cmd_SSLStrictSNIVHostCh
#endif
}
+const char *ssl_cmd_SSLSessionTicketExtension(cmd_parms *cmd, void *dcfg, int
flag)
+{
+#ifndef OPENSSL_NO_TLSEXT
+ const char *err;
+ SSLModConfigRec *mc = myModConfig(cmd->server);
+
+ if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
+ return err;
+ }
+
+ mc->session_tickets_enabled = flag ? SSL_ENABLED_TRUE : SSL_ENABLED_FALSE;
+
+ return NULL;
+#else
+ return "SSLSessionTicketExtension failed; OpenSSL is not built with
support "
+ "for TLS extensions. 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")) {
Index: httpd-2.2.x/modules/ssl/ssl_engine_kernel.c
===================================================================
--- httpd-2.2.x/modules/ssl/ssl_engine_kernel.c (revision 833672)
+++ 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
@@ -2010,6 +2011,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)) {
@@ -2074,6 +2076,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/mod_ssl.c
===================================================================
--- httpd-2.2.x/modules/ssl/mod_ssl.c (revision 833672)
+++ httpd-2.2.x/modules/ssl/mod_ssl.c (working copy)
@@ -92,6 +92,8 @@ static const command_rec ssl_config_cmds
SSL_CMD_SRV(RandomSeed, TAKE23,
"SSL Pseudo Random Number Generator (PRNG) seeding source "
"(`startup|connect builtin|file:/path|exec:/path [bytes]')")
+ SSL_CMD_SRV(SessionTicketExtension, FLAG,
+ "TLS Session Ticket extension support")
/*
* Per-server context configuration directives
Index: httpd-2.2.x/docs/manual/mod/mod_ssl.xml
===================================================================
--- httpd-2.2.x/docs/manual/mod/mod_ssl.xml (revision 833672)
+++ httpd-2.2.x/docs/manual/mod/mod_ssl.xml (working copy)
@@ -1808,4 +1808,35 @@ SSLCryptoDevice ubsec
</usage>
</directivesynopsis>
+<directivesynopsis>
+<name>SSLSessionTicketExtension</name>
+<description>Configure TLS session ticket extension support</description>
+<syntax>SSLSessionTicketExtension on|off</syntax>
+<default>SSLSessionTicketExtension on</default>
+<contextlist><context>server config</context></contextlist>
+<compatibility>Available in Apache 2.2.15 and later</compatibility>
+
+<usage>
+<p>
+This directive configures support for TLS session tickets (stateless session
+resumption, cf. RFC 5077). Session tickets are enabled by default when mod_ssl
+is compiled against an OpenSSL version which includes this option. They can
+coexist with a stateful session cache (configured through
+<directive module="mod_ssl">SSLSessionCache</directive>);
+it is then up to the client to choose between stateful and stateless session
+resumption.</p>
+
+<p>
+Clients based on OpenSSL versions 0.9.8f through 0.9.8l are known to
+have problems (<code>parse tlsext</code> errors) when using the SNI and session
+ticket extensions at the same time. As a workaround for interoperability issues
+like these, this directive allows to completely turn off TLS session ticket
support
+at the server side.</p>
+
+<example><title>Example</title>
+SSLSessionTicketExtension off
+</example>
+</usage>
+</directivesynopsis>
+
</modulesynopsis>