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 *);