summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Querna <pquerna@apache.org>2011-11-09 23:37:37 +0000
committerPaul Querna <pquerna@apache.org>2011-11-09 23:37:37 +0000
commit8b2e0e56c24779fae6bfcc03749817db241712ad (patch)
tree77b196d6d6706747f7e2cd77497c3ea7e75d78b2
parent1bc9c909bbb60c05a1ab8b3ac0c15f23f44cf64c (diff)
downloadhttpd-8b2e0e56c24779fae6bfcc03749817db241712ad.tar.gz
Add support for RFC 5077 TLS Session tickets. This adds two new directives:
* SSLTicketKeyFile: To store the private information for the encryption of the ticket. * SSLTicketKeyDefault To set the default, otherwise the first listed token is used. This enables key rotation across servers. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1200040 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--CHANGES3
-rw-r--r--modules/ssl/mod_ssl.c8
-rw-r--r--modules/ssl/ssl_engine_config.c67
-rw-r--r--modules/ssl/ssl_engine_init.c37
-rw-r--r--modules/ssl/ssl_engine_kernel.c91
-rw-r--r--modules/ssl/ssl_private.h37
6 files changed, 243 insertions, 0 deletions
diff --git a/CHANGES b/CHANGES
index 335e136824..9b3118eb0a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
-*- coding: utf-8 -*-
Changes with Apache 2.3.16
+ *) mod_ssl: Add support for RFC 5077 TLS Session tickets.
+ [Paul Querna]
+
*) mod_usertrack: Use random value instead of remote IP address.
[Stefan Fritsch]
diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c
index 41717623fb..424a8f66aa 100644
--- a/modules/ssl/mod_ssl.c
+++ b/modules/ssl/mod_ssl.c
@@ -79,6 +79,14 @@ static const command_rec ssl_config_cmds[] = {
SSL_CMD_SRV(FIPS, FLAG,
"Enable FIPS-140 mode "
"(`on', `off')")
+#ifdef HAVE_TLSEXT_TICKETS
+ SSL_CMD_SRV(TicketKeyFile, TAKE2,
+ "Key file to use for encrypting and decrypting the client ticket (RFC 5077) "
+ "(keyname '/path/to/file')")
+ SSL_CMD_SRV(TicketKeyDefault, TAKE1,
+ "Set the key name used by default for new sessions "
+ "(keyname)")
+#endif
SSL_CMD_ALL(CipherSuite, TAKE1,
"Colon-delimited list of permitted SSL Ciphers "
"('XXX:...:XXX' - see manual)")
diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c
index 906d791426..2e36a106ab 100644
--- a/modules/ssl/ssl_engine_config.c
+++ b/modules/ssl/ssl_engine_config.c
@@ -200,6 +200,12 @@ static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p)
sc->fips = UNSET;
#endif
+#ifdef HAVE_TLSEXT_TICKETS
+ sc->default_ticket_name = NULL;
+ sc->default_ticket = NULL;
+ sc->tickets = apr_array_make(p, 4, sizeof(modssl_ticket_t*));
+#endif
+
modssl_ctx_init_proxy(sc, p);
modssl_ctx_init_server(sc, p);
@@ -304,6 +310,11 @@ void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv)
cfgMerge(mc, NULL);
cfgMerge(enabled, SSL_ENABLED_UNSET);
+#ifdef HAVE_TLSEXT_TICKETS
+ cfgMergeString(default_ticket_name);
+ apr_array_cat(mrg->tickets, base->tickets);
+ apr_array_cat(mrg->tickets, add->tickets);
+#endif
cfgMergeBool(proxy_enabled);
cfgMergeInt(session_cache_timeout);
cfgMergeBool(cipher_server_pref);
@@ -584,6 +595,62 @@ const char *ssl_cmd_SSLEngine(cmd_parms *cmd, void *dcfg, const char *arg)
return "Argument must be On, Off, or Optional";
}
+const char *ssl_cmd_SSLTicketKeyDefault(cmd_parms *cmd, void *dcfg, const char *name)
+{
+#ifdef HAVE_TLSEXT_TICKETS
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+
+ sc->default_ticket_name = name;
+
+ return NULL;
+#else
+ return "TLS Ticket keys are not supported.";
+#endif
+}
+
+const char *ssl_cmd_SSLTicketKeyFile(cmd_parms *cmd, void *dcfg, const char *name, const char *path)
+{
+#ifdef HAVE_TLSEXT_TICKETS
+ apr_status_t rv;
+ apr_file_t *fp;
+ apr_size_t len;
+ char buf[TLSEXT_TICKET_KEYLEN];
+ modssl_ticket_t* ticket = NULL;
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+
+ rv = apr_file_open(&fp, path, APR_READ|APR_BINARY,
+ APR_OS_DEFAULT, cmd->temp_pool);
+
+ if (rv != APR_SUCCESS) {
+ return apr_psprintf(cmd->pool,
+ "Failed to open %s: (%d) %pm",
+ path, rv, &rv);
+ }
+
+ rv = apr_file_read_full(fp, &buf[0], TLSEXT_TICKET_KEYLEN, &len);
+
+ if (rv != APR_SUCCESS) {
+ return apr_psprintf(cmd->pool,
+ "Failed to read at least 48 bytes from %s: (%d) %pm",
+ path, rv, &rv);
+ }
+
+ ticket = apr_palloc(cmd->pool, sizeof(modssl_ticket_t));
+
+ ticket->conf_name = name;
+
+ memcpy(ticket->key_name, buf, 16);
+ memcpy(ticket->hmac_secret, buf + 16, 16);
+ memcpy(ticket->aes_key, buf + 32, 16);
+
+ APR_ARRAY_PUSH(sc->tickets, modssl_ticket_t*) = ticket;
+
+ return NULL;
+#else
+ return "TLS Ticket keys are not supported.";
+#endif
+}
+
const char *ssl_cmd_SSLFIPS(cmd_parms *cmd, void *dcfg, int flag)
{
#ifdef HAVE_FIPS
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index ba406de8c4..678a60a6c9 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -1143,6 +1143,43 @@ static void ssl_init_server_certs(server_rec *s,
#endif
ssl_die();
}
+
+#ifdef HAVE_TLSEXT_TICKETS
+ if (mctx->sc->tickets->nelts > 0) {
+
+ if (mctx->sc->default_ticket_name != NULL) {
+ int i;
+ modssl_ticket_t* ticket = NULL;
+ mctx->sc->default_ticket = NULL;
+
+ for (i = 0; i < mctx->sc->tickets->nelts; i++) {
+ ticket = APR_ARRAY_IDX(mctx->sc->tickets, i, modssl_ticket_t*);
+ if (strcmp(ticket->conf_name, mctx->sc->default_ticket_name) == 0) {
+ mctx->sc->default_ticket = ticket;
+ }
+ }
+
+ if (mctx->sc->default_ticket == NULL) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
+ "Misconfigured TLS Tickets. Couldn't find key named '%s'",
+ mctx->sc->default_ticket_name);
+ ssl_die();
+ }
+ }
+ else {
+ mctx->sc->default_ticket = APR_ARRAY_IDX(mctx->sc->tickets, 0, modssl_ticket_t*);
+ }
+
+ if (!SSL_CTX_set_tlsext_ticket_key_cb(mctx->ssl_ctx, ssl_callback_tlsext_tickets)) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
+ "Unable to initialize TLS session ticket extension "
+ "(incompatible OpenSSL version?)");
+ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
+ ssl_die();
+ }
+ }
+#endif
+
}
static void ssl_init_proxy_certs(server_rec *s,
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
index 23e8dc8b8a..5bab98097e 100644
--- a/modules/ssl/ssl_engine_kernel.c
+++ b/modules/ssl/ssl_engine_kernel.c
@@ -2067,3 +2067,94 @@ static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s)
return 0;
}
#endif
+
+#ifdef HAVE_TLSEXT_TICKETS
+
+#ifndef tlsext_tick_md
+#ifdef OPENSSL_NO_SHA256
+#define tlsext_tick_md EVP_sha1
+#else
+#define tlsext_tick_md EVP_sha256
+#endif
+#endif
+
+int ssl_callback_tlsext_tickets(SSL *ssl,
+ char *keyname,
+ char *iv,
+ EVP_CIPHER_CTX *cipher_ctx,
+ HMAC_CTX *hctx,
+ int mode)
+{
+ conn_rec *conn = (conn_rec *)SSL_get_app_data(ssl);
+ server_rec *s = mySrvFromConn(conn);
+ SSLSrvConfigRec *sc = mySrvConfig(s);
+
+ if (mode == 1) {
+ modssl_ticket_t* ticket = sc->default_ticket;
+
+ /* Setting up the stuff for encrypting:
+ * - keyname contains at least 16 bytes we can write to.
+ * - iv contains at least EVP_MAX_IV_LENGTH (16) bytes we can write to.
+ * - hctx is already allocated, we just need to set the
+ * secret key via HMAC_Init_ex.
+ * - cipher_ctx is also allocated, and we need to configure
+ * the cipher and private key.
+ */
+
+ if (ticket == NULL) {
+ /* this should not happen, we always set the default
+ * ticket.
+ */
+ return -1;
+ }
+
+ memcpy(keyname, ticket->key_name, 16);
+
+ RAND_pseudo_bytes(iv, EVP_MAX_IV_LENGTH);
+
+ memcpy(iv, iv, EVP_MAX_IV_LENGTH);
+
+ EVP_EncryptInit_ex(cipher_ctx, EVP_aes_128_cbc(), NULL,
+ ticket->aes_key, iv);
+
+ HMAC_Init_ex(hctx, ticket->hmac_secret, 16, tlsext_tick_md(), NULL);
+
+ return 0;
+ }
+ else if (mode == 0) {
+ /* Setup contextes for decryption, based on the keyname input */
+ int i;
+ modssl_ticket_t* ticket = NULL;
+
+ for (i = 0; i < sc->tickets->nelts; i++) {
+ modssl_ticket_t* itticket = APR_ARRAY_IDX(sc->tickets, i, modssl_ticket_t*);
+ if (memcmp(keyname, itticket->key_name, 16) == 0) {
+ ticket = itticket;
+ break;
+ }
+ }
+
+ if (ticket == NULL) {
+ /* Ticket key not found, but no error */
+ return 0;
+ }
+
+ EVP_DecryptInit_ex(cipher_ctx, EVP_aes_128_cbc(), NULL, ticket->aes_key, iv);
+
+ HMAC_Init_ex(hctx, ticket->hmac_secret, 16, tlsext_tick_md(), NULL);
+
+ if (ticket != sc->default_ticket) {
+ /* Ticket key found, we did our stuff, but didn't use the default,
+ * re-issue a ticket with the default ticket */
+ return 2;
+ }
+ else {
+ return 1;
+ }
+ }
+
+ /* TODO: log invalid use */
+ return -1;
+}
+
+#endif
diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h
index 561168c677..05ec820540 100644
--- a/modules/ssl/ssl_private.h
+++ b/modules/ssl/ssl_private.h
@@ -157,6 +157,12 @@
#endif
#endif
+#ifndef OPENSSL_NO_TLSEXT
+#ifdef SSL_CTX_set_tlsext_ticket_key_cb
+#define HAVE_TLSEXT_TICKETS
+#endif
+#endif
+
/* mod_ssl headers */
#include "ssl_util_ssl.h"
@@ -557,6 +563,21 @@ typedef struct {
ssl_verify_t verify_mode;
} modssl_auth_ctx_t;
+
+#ifdef HAVE_TLSEXT_TICKETS
+
+/* 48 bytes: 16 for keyname, 16 for HMAC secret, 16 for AES private key */
+#define TLSEXT_TICKET_KEYLEN (48)
+
+typedef struct {
+ /* Human readable name, used in the configuration */
+ const char *conf_name;
+ char key_name[16];
+ char hmac_secret[16];
+ char aes_key[16];
+} modssl_ticket_t;
+#endif
+
typedef struct SSLSrvConfigRec SSLSrvConfigRec;
typedef struct {
@@ -625,6 +646,11 @@ struct SSLSrvConfigRec {
#ifdef HAVE_FIPS
BOOL fips;
#endif
+#ifdef HAVE_TLSEXT_TICKETS
+ const char *default_ticket_name;
+ modssl_ticket_t* default_ticket;
+ apr_array_header_t* tickets;
+#endif
};
/**
@@ -716,6 +742,8 @@ const char *ssl_cmd_SSLOCSPResponderTimeout(cmd_parms *cmd, void *dcfg, const ch
const char *ssl_cmd_SSLOCSPEnable(cmd_parms *cmd, void *dcfg, int flag);
const char *ssl_cmd_SSLFIPS(cmd_parms *cmd, void *dcfg, int flag);
+const char *ssl_cmd_SSLTicketKeyDefault(cmd_parms *cmd, void *dcfg, const char *name);
+const char *ssl_cmd_SSLTicketKeyFile(cmd_parms *cmd, void *dcfg, const char *name, const char *path);
/** module initialization */
int ssl_init_Module(apr_pool_t *, apr_pool_t *, apr_pool_t *, server_rec *);
@@ -757,6 +785,15 @@ void ssl_callback_Info(const SSL *, int, int);
int ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *);
#endif
+#ifdef HAVE_TLSEXT_TICKETS
+int ssl_callback_tlsext_tickets(SSL *ssl,
+ char *keyname,
+ char *iv,
+ EVP_CIPHER_CTX *cipher_ctx,
+ HMAC_CTX *hctx,
+ int mode);
+#endif
+
/** Session Cache Support */
void ssl_scache_init(server_rec *, apr_pool_t *);
void ssl_scache_status_register(apr_pool_t *p);