Skip to content

Commit 967d943

Browse files
committed
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
1 parent cd66061 commit 967d943

6 files changed

Lines changed: 243 additions & 0 deletions

File tree

CHANGES

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
-*- coding: utf-8 -*-
22
Changes with Apache 2.3.16
33

4+
*) mod_ssl: Add support for RFC 5077 TLS Session tickets.
5+
[Paul Querna]
6+
47
*) mod_usertrack: Use random value instead of remote IP address.
58
[Stefan Fritsch]
69

modules/ssl/mod_ssl.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ static const command_rec ssl_config_cmds[] = {
7979
SSL_CMD_SRV(FIPS, FLAG,
8080
"Enable FIPS-140 mode "
8181
"(`on', `off')")
82+
#ifdef HAVE_TLSEXT_TICKETS
83+
SSL_CMD_SRV(TicketKeyFile, TAKE2,
84+
"Key file to use for encrypting and decrypting the client ticket (RFC 5077) "
85+
"(keyname '/path/to/file')")
86+
SSL_CMD_SRV(TicketKeyDefault, TAKE1,
87+
"Set the key name used by default for new sessions "
88+
"(keyname)")
89+
#endif
8290
SSL_CMD_ALL(CipherSuite, TAKE1,
8391
"Colon-delimited list of permitted SSL Ciphers "
8492
"('XXX:...:XXX' - see manual)")

modules/ssl/ssl_engine_config.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,12 @@ static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p)
200200
sc->fips = UNSET;
201201
#endif
202202

203+
#ifdef HAVE_TLSEXT_TICKETS
204+
sc->default_ticket_name = NULL;
205+
sc->default_ticket = NULL;
206+
sc->tickets = apr_array_make(p, 4, sizeof(modssl_ticket_t*));
207+
#endif
208+
203209
modssl_ctx_init_proxy(sc, p);
204210

205211
modssl_ctx_init_server(sc, p);
@@ -304,6 +310,11 @@ void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv)
304310

305311
cfgMerge(mc, NULL);
306312
cfgMerge(enabled, SSL_ENABLED_UNSET);
313+
#ifdef HAVE_TLSEXT_TICKETS
314+
cfgMergeString(default_ticket_name);
315+
apr_array_cat(mrg->tickets, base->tickets);
316+
apr_array_cat(mrg->tickets, add->tickets);
317+
#endif
307318
cfgMergeBool(proxy_enabled);
308319
cfgMergeInt(session_cache_timeout);
309320
cfgMergeBool(cipher_server_pref);
@@ -584,6 +595,62 @@ const char *ssl_cmd_SSLEngine(cmd_parms *cmd, void *dcfg, const char *arg)
584595
return "Argument must be On, Off, or Optional";
585596
}
586597

598+
const char *ssl_cmd_SSLTicketKeyDefault(cmd_parms *cmd, void *dcfg, const char *name)
599+
{
600+
#ifdef HAVE_TLSEXT_TICKETS
601+
SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
602+
603+
sc->default_ticket_name = name;
604+
605+
return NULL;
606+
#else
607+
return "TLS Ticket keys are not supported.";
608+
#endif
609+
}
610+
611+
const char *ssl_cmd_SSLTicketKeyFile(cmd_parms *cmd, void *dcfg, const char *name, const char *path)
612+
{
613+
#ifdef HAVE_TLSEXT_TICKETS
614+
apr_status_t rv;
615+
apr_file_t *fp;
616+
apr_size_t len;
617+
char buf[TLSEXT_TICKET_KEYLEN];
618+
modssl_ticket_t* ticket = NULL;
619+
SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
620+
621+
rv = apr_file_open(&fp, path, APR_READ|APR_BINARY,
622+
APR_OS_DEFAULT, cmd->temp_pool);
623+
624+
if (rv != APR_SUCCESS) {
625+
return apr_psprintf(cmd->pool,
626+
"Failed to open %s: (%d) %pm",
627+
path, rv, &rv);
628+
}
629+
630+
rv = apr_file_read_full(fp, &buf[0], TLSEXT_TICKET_KEYLEN, &len);
631+
632+
if (rv != APR_SUCCESS) {
633+
return apr_psprintf(cmd->pool,
634+
"Failed to read at least 48 bytes from %s: (%d) %pm",
635+
path, rv, &rv);
636+
}
637+
638+
ticket = apr_palloc(cmd->pool, sizeof(modssl_ticket_t));
639+
640+
ticket->conf_name = name;
641+
642+
memcpy(ticket->key_name, buf, 16);
643+
memcpy(ticket->hmac_secret, buf + 16, 16);
644+
memcpy(ticket->aes_key, buf + 32, 16);
645+
646+
APR_ARRAY_PUSH(sc->tickets, modssl_ticket_t*) = ticket;
647+
648+
return NULL;
649+
#else
650+
return "TLS Ticket keys are not supported.";
651+
#endif
652+
}
653+
587654
const char *ssl_cmd_SSLFIPS(cmd_parms *cmd, void *dcfg, int flag)
588655
{
589656
#ifdef HAVE_FIPS

modules/ssl/ssl_engine_init.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,43 @@ static void ssl_init_server_certs(server_rec *s,
11431143
#endif
11441144
ssl_die();
11451145
}
1146+
1147+
#ifdef HAVE_TLSEXT_TICKETS
1148+
if (mctx->sc->tickets->nelts > 0) {
1149+
1150+
if (mctx->sc->default_ticket_name != NULL) {
1151+
int i;
1152+
modssl_ticket_t* ticket = NULL;
1153+
mctx->sc->default_ticket = NULL;
1154+
1155+
for (i = 0; i < mctx->sc->tickets->nelts; i++) {
1156+
ticket = APR_ARRAY_IDX(mctx->sc->tickets, i, modssl_ticket_t*);
1157+
if (strcmp(ticket->conf_name, mctx->sc->default_ticket_name) == 0) {
1158+
mctx->sc->default_ticket = ticket;
1159+
}
1160+
}
1161+
1162+
if (mctx->sc->default_ticket == NULL) {
1163+
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
1164+
"Misconfigured TLS Tickets. Couldn't find key named '%s'",
1165+
mctx->sc->default_ticket_name);
1166+
ssl_die();
1167+
}
1168+
}
1169+
else {
1170+
mctx->sc->default_ticket = APR_ARRAY_IDX(mctx->sc->tickets, 0, modssl_ticket_t*);
1171+
}
1172+
1173+
if (!SSL_CTX_set_tlsext_ticket_key_cb(mctx->ssl_ctx, ssl_callback_tlsext_tickets)) {
1174+
ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
1175+
"Unable to initialize TLS session ticket extension "
1176+
"(incompatible OpenSSL version?)");
1177+
ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
1178+
ssl_die();
1179+
}
1180+
}
1181+
#endif
1182+
11461183
}
11471184

11481185
static void ssl_init_proxy_certs(server_rec *s,

modules/ssl/ssl_engine_kernel.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2067,3 +2067,94 @@ static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s)
20672067
return 0;
20682068
}
20692069
#endif
2070+
2071+
#ifdef HAVE_TLSEXT_TICKETS
2072+
2073+
#ifndef tlsext_tick_md
2074+
#ifdef OPENSSL_NO_SHA256
2075+
#define tlsext_tick_md EVP_sha1
2076+
#else
2077+
#define tlsext_tick_md EVP_sha256
2078+
#endif
2079+
#endif
2080+
2081+
int ssl_callback_tlsext_tickets(SSL *ssl,
2082+
char *keyname,
2083+
char *iv,
2084+
EVP_CIPHER_CTX *cipher_ctx,
2085+
HMAC_CTX *hctx,
2086+
int mode)
2087+
{
2088+
conn_rec *conn = (conn_rec *)SSL_get_app_data(ssl);
2089+
server_rec *s = mySrvFromConn(conn);
2090+
SSLSrvConfigRec *sc = mySrvConfig(s);
2091+
2092+
if (mode == 1) {
2093+
modssl_ticket_t* ticket = sc->default_ticket;
2094+
2095+
/* Setting up the stuff for encrypting:
2096+
* - keyname contains at least 16 bytes we can write to.
2097+
* - iv contains at least EVP_MAX_IV_LENGTH (16) bytes we can write to.
2098+
* - hctx is already allocated, we just need to set the
2099+
* secret key via HMAC_Init_ex.
2100+
* - cipher_ctx is also allocated, and we need to configure
2101+
* the cipher and private key.
2102+
*/
2103+
2104+
if (ticket == NULL) {
2105+
/* this should not happen, we always set the default
2106+
* ticket.
2107+
*/
2108+
return -1;
2109+
}
2110+
2111+
memcpy(keyname, ticket->key_name, 16);
2112+
2113+
RAND_pseudo_bytes(iv, EVP_MAX_IV_LENGTH);
2114+
2115+
memcpy(iv, iv, EVP_MAX_IV_LENGTH);
2116+
2117+
EVP_EncryptInit_ex(cipher_ctx, EVP_aes_128_cbc(), NULL,
2118+
ticket->aes_key, iv);
2119+
2120+
HMAC_Init_ex(hctx, ticket->hmac_secret, 16, tlsext_tick_md(), NULL);
2121+
2122+
return 0;
2123+
}
2124+
else if (mode == 0) {
2125+
/* Setup contextes for decryption, based on the keyname input */
2126+
int i;
2127+
modssl_ticket_t* ticket = NULL;
2128+
2129+
for (i = 0; i < sc->tickets->nelts; i++) {
2130+
modssl_ticket_t* itticket = APR_ARRAY_IDX(sc->tickets, i, modssl_ticket_t*);
2131+
if (memcmp(keyname, itticket->key_name, 16) == 0) {
2132+
ticket = itticket;
2133+
break;
2134+
}
2135+
}
2136+
2137+
if (ticket == NULL) {
2138+
/* Ticket key not found, but no error */
2139+
return 0;
2140+
}
2141+
2142+
EVP_DecryptInit_ex(cipher_ctx, EVP_aes_128_cbc(), NULL, ticket->aes_key, iv);
2143+
2144+
HMAC_Init_ex(hctx, ticket->hmac_secret, 16, tlsext_tick_md(), NULL);
2145+
2146+
if (ticket != sc->default_ticket) {
2147+
/* Ticket key found, we did our stuff, but didn't use the default,
2148+
* re-issue a ticket with the default ticket */
2149+
return 2;
2150+
}
2151+
else {
2152+
return 1;
2153+
}
2154+
}
2155+
2156+
/* TODO: log invalid use */
2157+
return -1;
2158+
}
2159+
2160+
#endif

modules/ssl/ssl_private.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,12 @@
157157
#endif
158158
#endif
159159

160+
#ifndef OPENSSL_NO_TLSEXT
161+
#ifdef SSL_CTX_set_tlsext_ticket_key_cb
162+
#define HAVE_TLSEXT_TICKETS
163+
#endif
164+
#endif
165+
160166
/* mod_ssl headers */
161167
#include "ssl_util_ssl.h"
162168

@@ -557,6 +563,21 @@ typedef struct {
557563
ssl_verify_t verify_mode;
558564
} modssl_auth_ctx_t;
559565

566+
567+
#ifdef HAVE_TLSEXT_TICKETS
568+
569+
/* 48 bytes: 16 for keyname, 16 for HMAC secret, 16 for AES private key */
570+
#define TLSEXT_TICKET_KEYLEN (48)
571+
572+
typedef struct {
573+
/* Human readable name, used in the configuration */
574+
const char *conf_name;
575+
char key_name[16];
576+
char hmac_secret[16];
577+
char aes_key[16];
578+
} modssl_ticket_t;
579+
#endif
580+
560581
typedef struct SSLSrvConfigRec SSLSrvConfigRec;
561582

562583
typedef struct {
@@ -625,6 +646,11 @@ struct SSLSrvConfigRec {
625646
#ifdef HAVE_FIPS
626647
BOOL fips;
627648
#endif
649+
#ifdef HAVE_TLSEXT_TICKETS
650+
const char *default_ticket_name;
651+
modssl_ticket_t* default_ticket;
652+
apr_array_header_t* tickets;
653+
#endif
628654
};
629655

630656
/**
@@ -716,6 +742,8 @@ const char *ssl_cmd_SSLOCSPResponderTimeout(cmd_parms *cmd, void *dcfg, const ch
716742
const char *ssl_cmd_SSLOCSPEnable(cmd_parms *cmd, void *dcfg, int flag);
717743

718744
const char *ssl_cmd_SSLFIPS(cmd_parms *cmd, void *dcfg, int flag);
745+
const char *ssl_cmd_SSLTicketKeyDefault(cmd_parms *cmd, void *dcfg, const char *name);
746+
const char *ssl_cmd_SSLTicketKeyFile(cmd_parms *cmd, void *dcfg, const char *name, const char *path);
719747

720748
/** module initialization */
721749
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);
757785
int ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *);
758786
#endif
759787

788+
#ifdef HAVE_TLSEXT_TICKETS
789+
int ssl_callback_tlsext_tickets(SSL *ssl,
790+
char *keyname,
791+
char *iv,
792+
EVP_CIPHER_CTX *cipher_ctx,
793+
HMAC_CTX *hctx,
794+
int mode);
795+
#endif
796+
760797
/** Session Cache Support */
761798
void ssl_scache_init(server_rec *, apr_pool_t *);
762799
void ssl_scache_status_register(apr_pool_t *p);

0 commit comments

Comments
 (0)