From: Yann Ylavic
Date: Thu, 21 May 2015 15:27:54 +0000 (+0000)
Subject: Merge r1200040, r1200372, r1200374, r1213380 from trunk.
X-Git-Tag: 2.2.30~90
X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=902175ea53568a45e3f1357cdde1fe20027f4a96;p=thirdparty%2Fapache%2Fhttpd.git
Merge r1200040, r1200372, r1200374, r1213380 from trunk.
r1200040 | pquerna | 2011-11-10 00:37:37 +0100 (Thu, 10 Nov 2011) | 5 lines
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.
r1200372 | pquerna | 2011-11-10 16:17:18 +0100 (Thu, 10 Nov 2011) | 4 lines
Apply ap_server_root_relative to the path used for the ticket secrets file.
Suggested by: Rüdiger Plüm
r1200374 | pquerna | 2011-11-10 16:19:15 +0100 (Thu, 10 Nov 2011) | 4 lines
Remove unneeded memcpy.
Spotted by: Rüdiger Plüm
r1213380 | kbrand | 2011-12-12 20:21:35 +0100 (Mon, 12 Dec 2011) | 9 lines
Streamline TLS session ticket key handling (added in r1200040):
- drop the SSLTicketKeyDefault directive, and only support a single
ticket key per server/vhost
- rename the SSLTicketKeyFile directive to SSLSessionTicketKeyFile,
remove the keyname parameter
- move ticket key parameters from SSLSrvConfigRec to modssl_ctx_t
- configure the tlsext_ticket_key_cb only when in server mode
- add documentation for SSLSessionTicketKeyFile
Reviewed by: ylavic, wrowe, rjung
Backported by: ylavic
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@1680905 13f79535-47bb-0310-9956-ffa450edef68
---
diff --git a/CHANGES b/CHANGES
index 73a9def457a..35acc336130 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,10 @@
-*- coding: utf-8 -*-
Changes with Apache 2.2.30
+ *) mod_ssl: Add support for configuring persistent TLS session ticket
+ encryption/decryption keys (useful for clustered environments).
+ [Paul Querna, Kaspar Brand]
+
*) SSLProtocol and SSLCipherSuite recommendations in the example/default
conf/extra/httpd-ssl.conf file are now global in scope, affecting all
VirtualHosts (matching 2.4 default configuration). [William Rowe]
diff --git a/STATUS b/STATUS
index 858841328ff..2687247dee9 100644
--- a/STATUS
+++ b/STATUS
@@ -108,24 +108,6 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
ylavic: trunk/2.4.x not concerned, 2.2.x only.
+1: ylavic, jkaluza, wrowe
- * mod_ssl: Add support for configuring persistent TLS session ticket
- encryption/decryption keys (useful for clustered environments).
- [Paul Querna, Kaspar Brand]
- trunk patch: http://svn.apache.org/r1200040
- http://svn.apache.org/r1200372
- http://svn.apache.org/r1200374
- http://svn.apache.org/r1213380
- 2.2.x patch: http://people.apache.org/~ylavic/httpd-2.2.x-SSLSessionTicketKeyFile.patch
- +1: ylavic, wrowe, rjung
- rjung: Minor nits you can IMHO apply as CTR:
- - in mod_ssl.c the info string for SessionTicketKeyFile contains
- '/path/to/file', whereas existing directives use `/path/to/file'.
- The first quotation mark is of different style.
- - enhance docs note about frequent key file rotation by info that one also needs
- to restart the web server in order for the changed file to take effect
- (either gracefully or not). Would be useful for 2.4/trunk as well
- - mention RFC 5077 in CHANGES
-
* mod_ssl: Improve handling of ephemeral DH and ECDH keys by
allowing custom parameters to be configured via SSLCertificateFile,
and by adding standardized DH parameters for 1024/2048/3072/4096 bits.
diff --git a/docs/manual/mod/mod_ssl.xml b/docs/manual/mod/mod_ssl.xml
index 4e2914a40ce..68c39e38076 100644
--- a/docs/manual/mod/mod_ssl.xml
+++ b/docs/manual/mod/mod_ssl.xml
@@ -1947,4 +1947,40 @@ forward secrecy.
+
+SSLSessionTicketKeyFile
+Persistent encryption/decryption key for TLS session tickets
+SSLSessionTicketKeyFile file-path
+server config
+virtual host
+Available in httpd 2.2.30 and later, if using OpenSSL 0.9.8h or later
+
+
+Optionally configures a secret key for encrypting and decrypting
+TLS session tickets, as defined in
+RFC 5077.
+Primarily suitable for clustered environments where TLS sessions information
+should be shared between multiple nodes. For single-instance httpd setups,
+it is recommended to not configure a ticket key file, but to
+rely on (random) keys generated by mod_ssl at startup, instead.
+The ticket key file must contain 48 bytes of random data,
+preferrably created from a high-entropy source. On a Unix-based system,
+a ticket key file can be created as follows:
+
+
+dd if=/dev/random of=/path/to/file.tkey bs=1 count=48
+
+
+Ticket keys should be rotated (replaced) on a frequent basis,
+as this is the only way to invalidate an existing session ticket -
+OpenSSL currently doesn't allow to specify a limit for ticket lifetimes.
+
+
+The ticket key file contains sensitive keying material and should
+be protected with file permissions similar to those used for
+SSLCertificateKeyFile.
+
+
+
+
diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c
index df0f2dc9741..072e6d41413 100644
--- a/modules/ssl/mod_ssl.c
+++ b/modules/ssl/mod_ssl.c
@@ -114,6 +114,11 @@ static const command_rec ssl_config_cmds[] = {
SSL_CMD_SRV(CertificateChainFile, TAKE1,
"SSL Server CA Certificate Chain file "
"(`/path/to/file' - PEM encoded)")
+#ifdef HAVE_TLS_SESSION_TICKETS
+ SSL_CMD_SRV(SessionTicketKeyFile, TAKE1,
+ "TLS session ticket encryption/decryption key file (RFC 5077) "
+ "('/path/to/file' - file with 48 bytes of random data)")
+#endif
SSL_CMD_ALL(CACertificatePath, TAKE1,
"SSL CA Certificate path "
"(`/path/to/dir' - contains PEM encoded files)")
diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c
index 9b0d1992bad..379de8033f0 100644
--- a/modules/ssl/ssl_engine_config.c
+++ b/modules/ssl/ssl_engine_config.c
@@ -110,6 +110,10 @@ static void modssl_ctx_init(modssl_ctx_t *mctx)
mctx->pks = NULL;
mctx->pkp = NULL;
+#ifdef HAVE_TLS_SESSION_TICKETS
+ mctx->ticket_key = NULL;
+#endif
+
mctx->protocol = SSL_PROTOCOL_ALL;
mctx->pphrase_dialog_type = SSL_PPTYPE_UNSET;
@@ -158,6 +162,10 @@ static void modssl_ctx_init_server(SSLSrvConfigRec *sc,
mctx->pks = apr_pcalloc(p, sizeof(*mctx->pks));
/* mctx->pks->... certs/keys are set during module init */
+
+#ifdef HAVE_TLS_SESSION_TICKETS
+ mctx->ticket_key = apr_pcalloc(p, sizeof(*mctx->ticket_key));
+#endif
}
static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p)
@@ -257,6 +265,10 @@ static void modssl_ctx_cfg_merge_server(modssl_ctx_t *base,
cfgMergeString(pks->ca_name_path);
cfgMergeString(pks->ca_name_file);
+
+#ifdef HAVE_TLS_SESSION_TICKETS
+ cfgMergeString(ticket_key->file_path);
+#endif
}
/*
@@ -874,6 +886,24 @@ const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *cmd,
return NULL;
}
+#ifdef HAVE_TLS_SESSION_TICKETS
+const char *ssl_cmd_SSLSessionTicketKeyFile(cmd_parms *cmd,
+ void *dcfg,
+ const char *arg)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+ const char *err;
+
+ if ((err = ssl_cmd_check_file(cmd, &arg))) {
+ return err;
+ }
+
+ sc->server->ticket_key->file_path = arg;
+
+ return NULL;
+}
+#endif
+
#define NO_PER_DIR_SSL_CA \
"Your ssl library does not have support for per-directory CA"
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index 6e552bb8bc1..6095971b973 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -1111,6 +1111,63 @@ static void ssl_init_server_certs(server_rec *s,
}
}
+#ifdef HAVE_TLS_SESSION_TICKETS
+static void ssl_init_ticket_key(server_rec *s,
+ apr_pool_t *p,
+ apr_pool_t *ptemp,
+ modssl_ctx_t *mctx)
+{
+ apr_status_t rv;
+ apr_file_t *fp;
+ apr_size_t len;
+ char buf[TLSEXT_TICKET_KEY_LEN];
+ char *path;
+ modssl_ticket_key_t *ticket_key = mctx->ticket_key;
+
+ if (!ticket_key->file_path) {
+ return;
+ }
+
+ path = ap_server_root_relative(p, ticket_key->file_path);
+
+ rv = apr_file_open(&fp, path, APR_READ|APR_BINARY,
+ APR_OS_DEFAULT, ptemp);
+
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
+ "Failed to open ticket key file %s: (%d) %pm",
+ path, rv, &rv);
+ ssl_die();
+ }
+
+ rv = apr_file_read_full(fp, &buf[0], TLSEXT_TICKET_KEY_LEN, &len);
+
+ if (rv != APR_SUCCESS) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
+ "Failed to read %d bytes from %s: (%d) %pm",
+ TLSEXT_TICKET_KEY_LEN, path, rv, &rv);
+ ssl_die();
+ }
+
+ memcpy(ticket_key->key_name, buf, 16);
+ memcpy(ticket_key->hmac_secret, buf + 16, 16);
+ memcpy(ticket_key->aes_key, buf + 32, 16);
+
+ if (!SSL_CTX_set_tlsext_ticket_key_cb(mctx->ssl_ctx,
+ ssl_callback_SessionTicket)) {
+ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
+ "Unable to initialize TLS session ticket key callback "
+ "(incompatible OpenSSL version?)");
+ ssl_log_ssl_error(APLOG_MARK, APLOG_EMERG, s);
+ ssl_die();
+ }
+
+ ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
+ "TLS session ticket key for %s successfully loaded from %s",
+ (mySrvConfig(s))->vhost_id, path);
+}
+#endif
+
static void ssl_init_proxy_certs(server_rec *s,
apr_pool_t *p,
apr_pool_t *ptemp,
@@ -1275,6 +1332,10 @@ static void ssl_init_server_ctx(server_rec *s,
ssl_init_server_certs(s, p, ptemp, sc->server);
+#ifdef HAVE_TLS_SESSION_TICKETS
+ ssl_init_ticket_key(s, p, ptemp, sc->server);
+#endif
+
SSL_CTX_set_timeout(sc->server->ssl_ctx,
sc->session_cache_timeout == UNSET ?
SSL_SESSION_CACHE_TIMEOUT : sc->session_cache_timeout);
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
index e3afc53a058..13baf49997a 100644
--- a/modules/ssl/ssl_engine_kernel.c
+++ b/modules/ssl/ssl_engine_kernel.c
@@ -2141,3 +2141,73 @@ static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s)
return 0;
}
#endif
+
+#ifdef HAVE_TLS_SESSION_TICKETS
+/*
+ * This callback function is executed when OpenSSL needs a key for encrypting/
+ * decrypting a TLS session ticket (RFC 5077) and a ticket key file has been
+ * configured through SSLSessionTicketKeyFile.
+ */
+int ssl_callback_SessionTicket(SSL *ssl,
+ unsigned char *keyname,
+ unsigned char *iv,
+ EVP_CIPHER_CTX *cipher_ctx,
+ HMAC_CTX *hctx,
+ int mode)
+{
+ conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
+ server_rec *s = mySrvFromConn(c);
+ SSLSrvConfigRec *sc = mySrvConfig(s);
+ SSLConnRec *sslconn = myConnConfig(c);
+ modssl_ctx_t *mctx = myCtxConfig(sslconn, sc);
+ modssl_ticket_key_t *ticket_key = mctx->ticket_key;
+
+ if (mode == 1) {
+ /*
+ * OpenSSL is asking for a key for encrypting a ticket,
+ * see s3_srvr.c:ssl3_send_newsession_ticket()
+ */
+
+ if (ticket_key == NULL) {
+ /* should never happen, but better safe than sorry */
+ return -1;
+ }
+
+ memcpy(keyname, ticket_key->key_name, 16);
+ RAND_pseudo_bytes(iv, EVP_MAX_IV_LENGTH);
+ EVP_EncryptInit_ex(cipher_ctx, EVP_aes_128_cbc(), NULL,
+ ticket_key->aes_key, iv);
+ HMAC_Init_ex(hctx, ticket_key->hmac_secret, 16, tlsext_tick_md(), NULL);
+
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+ "TLS session ticket key for %s successfully set, "
+ "creating new session ticket", sc->vhost_id);
+
+ return 0;
+ }
+ else if (mode == 0) {
+ /*
+ * OpenSSL is asking for the decryption key,
+ * see t1_lib.c:tls_decrypt_ticket()
+ */
+
+ /* check key name */
+ if (ticket_key == NULL || memcmp(keyname, ticket_key->key_name, 16)) {
+ return 0;
+ }
+
+ EVP_DecryptInit_ex(cipher_ctx, EVP_aes_128_cbc(), NULL,
+ ticket_key->aes_key, iv);
+ HMAC_Init_ex(hctx, ticket_key->hmac_secret, 16, tlsext_tick_md(), NULL);
+
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+ "TLS session ticket key for %s successfully set, "
+ "decrypting existing session ticket", sc->vhost_id);
+
+ return 1;
+ }
+
+ /* OpenSSL is not expected to call us with modes other than 1 or 0 */
+ return -1;
+}
+#endif
diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h
index d2d82d4f1e5..8087f30159b 100644
--- a/modules/ssl/ssl_private.h
+++ b/modules/ssl/ssl_private.h
@@ -69,6 +69,20 @@
#define OPENSSL_NO_COMP
#endif
+#ifndef OPENSSL_NO_TLSEXT
+#ifdef SSL_CTX_set_tlsext_ticket_key_cb
+#define HAVE_TLS_SESSION_TICKETS
+#define TLSEXT_TICKET_KEY_LEN 48
+#ifndef tlsext_tick_md
+#ifdef OPENSSL_NO_SHA256
+#define tlsext_tick_md EVP_sha1
+#else
+#define tlsext_tick_md EVP_sha256
+#endif
+#endif
+#endif
+#endif
+
#include "ssl_util_ssl.h"
/** The #ifdef macros are only defined AFTER including the above
@@ -483,6 +497,15 @@ typedef struct {
ssl_verify_t verify_mode;
} modssl_auth_ctx_t;
+#ifdef HAVE_TLS_SESSION_TICKETS
+typedef struct {
+ const char *file_path;
+ unsigned char key_name[16];
+ unsigned char hmac_secret[16];
+ unsigned char aes_key[16];
+} modssl_ticket_key_t;
+#endif
+
typedef struct SSLSrvConfigRec SSLSrvConfigRec;
typedef struct {
@@ -493,6 +516,10 @@ typedef struct {
modssl_pk_server_t *pks;
modssl_pk_proxy_t *pkp;
+#ifdef HAVE_TLS_SESSION_TICKETS
+ modssl_ticket_key_t *ticket_key;
+#endif
+
ssl_proto_t protocol;
/** config for handling encrypted keys */
@@ -615,6 +642,9 @@ const char *ssl_cmd_SSLProxyCARevocationFile(cmd_parms *, void *, const char *)
const char *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *, void *, const char *);
const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *, void *, const char *);
const char *ssl_cmd_SSLProxyMachineCertificateChainFile(cmd_parms *, void *, const char *);
+#ifdef HAVE_TLS_SESSION_TICKETS
+const char *ssl_cmd_SSLSessionTicketKeyFile(cmd_parms *cmd, void *dcfg, const char *arg);
+#endif
const char *ssl_cmd_SSLProxyCheckPeerExpire(cmd_parms *cmd, void *dcfg, int flag);
const char *ssl_cmd_SSLProxyCheckPeerCN(cmd_parms *cmd, void *dcfg, int flag);
@@ -655,6 +685,10 @@ void ssl_callback_Info(MODSSL_INFO_CB_ARG_TYPE, int, int);
#ifndef OPENSSL_NO_TLSEXT
int ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *);
#endif
+#ifdef HAVE_TLS_SESSION_TICKETS
+int ssl_callback_SessionTicket(SSL *, unsigned char *, unsigned char *,
+ EVP_CIPHER_CTX *, HMAC_CTX *, int);
+#endif
/** Session Cache Support */
void ssl_scache_init(server_rec *, apr_pool_t *);