Commit 414911a5 authored by Kaspar Brand's avatar Kaspar Brand
Browse files

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


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1213380 13f79535-47bb-0310-9956-ffa450edef68
parent 4c136c67
Loading
Loading
Loading
Loading
+1 −1
Changes for docs/log-message-tags/next-number: 1 added line, 1 removed line.
Original line number Diff line number Diff line
2286
2291
+36 −0
Changes for docs/manual/mod/mod_ssl.xml: 36 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -2265,4 +2265,40 @@ Of potential use when going through a proxy for retrieving OCSP queries.</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.4.0 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>
+5 −8
Changes for modules/ssl/mod_ssl.c: 5 added lines, 8 removed lines.
Original line number Diff line number Diff line
@@ -79,14 +79,6 @@ 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)")
@@ -102,6 +94,11 @@ static const command_rec ssl_config_cmds[] = {
    SSL_CMD_SRV(PKCS7CertificateFile, TAKE1,
                "PKCS#7 file containing server certificate and chain"
                " certificates ('/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)")
+30 −69
Changes for modules/ssl/ssl_engine_config.c: 30 added lines, 69 removed lines.
Original line number Diff line number Diff line
@@ -109,6 +109,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;
@@ -177,6 +181,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)
@@ -200,12 +208,6 @@ 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);
@@ -297,6 +299,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
}

/*
@@ -310,11 +316,6 @@ 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);
@@ -595,64 +596,6 @@ 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);

    path = ap_server_root_relative(cmd->pool, path);

    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
@@ -863,6 +806,24 @@ const char *ssl_cmd_SSLPKCS7CertificateFile(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"

+47 −23
Changes for modules/ssl/ssl_engine_init.c: 47 added lines, 23 removed lines.
Original line number Diff line number Diff line
@@ -1134,44 +1134,64 @@ 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;
#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;

            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 (!ticket_key->file_path) {
        return;
    }

            if (mctx->sc->default_ticket == NULL) {
                ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01912)
                            "Misconfigured TLS Tickets.  Couldn't find key named '%s'",
                            mctx->sc->default_ticket_name);
    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, APLOGNO(02286)
                     "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, APLOGNO(02287)
                     "Failed to read %d bytes from %s: (%d) %pm",
                     TLSEXT_TICKET_KEY_LEN, path, rv, &rv);
        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)) {
    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, APLOGNO(01913)
                        "Unable to initialize TLS session ticket extension "
                     "Unable to initialize TLS session ticket key callback "
                     "(incompatible OpenSSL version?)");
        ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s);
        ssl_die();
    }
    }
#endif

    ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02288)
                 "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,
@@ -1322,6 +1342,10 @@ static void ssl_init_server_ctx(server_rec *s,
    ssl_init_ctx(s, p, ptemp, sc->server);

    ssl_init_server_certs(s, p, ptemp, sc->server);

#ifdef HAVE_TLS_SESSION_TICKETS
    ssl_init_ticket_key(s, p, ptemp, sc->server);
#endif
}

/*
Loading