]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Merge r1200040, r1200372, r1200374, r1213380 from trunk.
authorYann Ylavic <ylavic@apache.org>
Thu, 21 May 2015 15:27:54 +0000 (15:27 +0000)
committerYann Ylavic <ylavic@apache.org>
Thu, 21 May 2015 15:27:54 +0000 (15:27 +0000)
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

CHANGES
STATUS
docs/manual/mod/mod_ssl.xml
modules/ssl/mod_ssl.c
modules/ssl/ssl_engine_config.c
modules/ssl/ssl_engine_init.c
modules/ssl/ssl_engine_kernel.c
modules/ssl/ssl_private.h

diff --git a/CHANGES b/CHANGES
index 73a9def457a20b1f1c453627b7b482f98af4ede9..35acc3361305ff718070c39023dfcbdd462a2efa 100644 (file)
--- 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 858841328ffe0c2ca3f5f3f21b52fc32f23ffe80..2687247dee9e82d6f9ac11351b6679f30c4b258b 100644 (file)
--- 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.
index 4e2914a40ce5d2d046a0030316e287381d9524bd..68c39e3807699c82720bd1a2e8e14d4aa00ad3d2 100644 (file)
@@ -1947,4 +1947,40 @@ forward secrecy.</p>
 </usage>
 </directivesynopsis>
 
+<directivesynopsis>
+<name>SSLSessionTicketKeyFile</name>
+<description>Persistent encryption/decryption key for TLS session tickets</description>
+<syntax>SSLSessionTicketKeyFile <em>file-path</em></syntax>
+<contextlist><context>server config</context>
+<context>virtual host</context></contextlist>
+<compatibility>Available in httpd 2.2.30 and later, if using OpenSSL 0.9.8h or later</compatibility>
+<usage>
+<p>Optionally configures a secret key for encrypting and decrypting
+TLS session tickets, as defined in
+<a href="http://www.ietf.org/rfc/rfc5077.txt">RFC 5077</a>.
+Primarily suitable for clustered environments where TLS sessions information
+should be shared between multiple nodes. For single-instance httpd setups,
+it is recommended to <em>not</em> configure a ticket key file, but to
+rely on (random) keys generated by mod_ssl at startup, instead.</p>
+<p>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:</p>
+
+<example>
+dd if=/dev/random of=/path/to/file.tkey bs=1 count=48
+</example>
+
+<p>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.</p>
+
+<note type="warning">
+<p>The ticket key file contains sensitive keying material and should
+be protected with file permissions similar to those used for
+<directive module="mod_ssl">SSLCertificateKeyFile</directive>.</p>
+</note>
+</usage>
+</directivesynopsis>
+
 </modulesynopsis>
index df0f2dc9741f483aa50849030129206c8e68e948..072e6d41413fa46a1651052358c765318df4f280 100644 (file)
@@ -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)")
index 9b0d1992bad03a04dfbd180baab25de2e7537053..379de8033f0ae3ace465b67d939403a79f173ef6 100644 (file)
@@ -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"
 
index 6e552bb8bc149bd12bb548460f5daf9fa5d21da2..6095971b97397d83cd30943bb43aff26ce1c4dc1 100644 (file)
@@ -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);
index e3afc53a0585a230cc81bce4562ab6c7d152a307..13baf49997aec10cb3bfe8d298af79866d8f850e 100644 (file)
@@ -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
index d2d82d4f1e520fb37fd5d8eeaea23f3cc9571e9c..8087f30159b43985f386a82eae57daaf9aaa5bf7 100644 (file)
 #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 *);