[PATCH] SSL: added support for TLS Session Tickets (RFC5077).
Maxim Dounin
mdounin at mdounin.ru
Fri Oct 11 14:26:47 UTC 2013
Hello!
On Thu, Oct 10, 2013 at 04:33:34PM -0700, Piotr Sikora wrote:
> Oops, one line was 81 chars long... Fixed patch below.
>
> # HG changeset patch
> # User Piotr Sikora <piotr at cloudflare.com>
> # Date 1381447913 25200
> # Thu Oct 10 16:31:53 2013 -0700
> # Node ID 4617733b2d7130313241253ef22958790d6fc902
> # Parent 5483d9e77b3287b00b1104a07688bda37bc7351e
> SSL: added ability to set keys used for Session Tickets (RFC5077).
>
> In order to support key rollover, ssl_session_ticket_key can be defined
> multiple times. The first key will be used to issue and resume Session
> Tickets, while the rest will be used only to resume them.
>
> ssl_session_ticket_key session_ticket_current.key;
> ssl_session_ticket_key session_ticket_curr-1h.key;
> ssl_session_ticket_key session_ticket_curr-2h.key;
>
> Please note that nginx supports Session Tickets even without explicit
> configuration of the keys and this feature should be only used in setups
> where SSL traffic is distributed across multiple nginx servers.
Looks almost good, see some minor nits below.
[...]
> --- a/src/event/ngx_event_openssl.c Wed Oct 02 15:07:17 2013 +0400
> +++ b/src/event/ngx_event_openssl.c Thu Oct 10 16:31:53 2013 -0700
> @@ -38,6 +38,18 @@ static void ngx_ssl_expire_sessions(ngx_
> static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
> ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
>
> +#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
> +static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn,
> + unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx,
> + HMAC_CTX *hctx, int enc);
> +
> +#ifdef OPENSSL_NO_SHA256
> +#define ngx_ssl_session_ticket_md EVP_sha1
> +#else
> +#define ngx_ssl_session_ticket_md EVP_sha256
> +#endif
> +#endif
> +
Wouldn't it better to move ngx_ssl_session_ticket_md defines
to ngx_ssl_session_ticket_key_callback() implementation?
[...]
> @@ -84,6 +96,9 @@ int ngx_ssl_server_conf_index;
> int ngx_ssl_session_cache_index;
> int ngx_ssl_certificate_index;
> int ngx_ssl_stapling_index;
> +#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
> +int ngx_ssl_session_ticket_keys_index;
> +#endif
>
>
> ngx_int_t
> @@ -155,6 +170,18 @@ ngx_ssl_init(ngx_log_t *log)
> return NGX_ERROR;
> }
>
> +#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
> +
> + ngx_ssl_session_ticket_keys_index = SSL_CTX_get_ex_new_index(0, NULL, NULL,
> + NULL, NULL);
> + if (ngx_ssl_session_ticket_keys_index == -1) {
> + ngx_ssl_error(NGX_LOG_ALERT, log, 0,
> + "SSL_CTX_get_ex_new_index() failed");
> + return NGX_ERROR;
> + }
> +
> +#endif
> +
Do we really need these #ifdef's? I don't think saving several
bytes in ancient OpenSSL versions worth it (and the
ngx_ssl_stapling_index doesn't have #ifdef's).
[...]
> +ngx_int_t
> +ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths)
> +{
> + u_char buf[48];
> + ssize_t n;
> + ngx_str_t *path;
> + ngx_file_t file;
> + ngx_uint_t i;
> + ngx_array_t *keys;
> + ngx_file_info_t fi;
> + ngx_ssl_session_ticket_key_t *key;
Wouldn't ngx_ssl_ticket_key_t be better? Up to you, but
"ngx_ssl_session_ticket_key_t" looks a bit too long.
[...]
> + if (enc == 1) {
> + /* encrypt session ticket */
> +
> +#if (NGX_DEBUG)
> + ngx_hex_dump(buf, key[0].name, 16);
> +
> + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
> + "ssl session ticket encrypt, key: \"%*s\" (%s session)",
> + 32, buf,
> + SSL_session_reused(ssl_conn) ? "reused" : "new");
> +#endif
What about something like this:
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
"ssl session ticket encrypt, key: \"%*s\" (%s session)",
ngx_hex_dump(buf, key[0].name, 16) - buf, buf,
SSL_session_reused(ssl_conn) ? "reused" : "new");
?
(Well, actually I'm not sure we need key name logged, but it
probably doesn't matter much.)
> +
> + RAND_pseudo_bytes(iv, 16);
> + EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, key[0].aes_key, iv);
> + HMAC_Init_ex(hctx, key[0].hmac_key, 16, ngx_ssl_session_ticket_md(),
> + NULL);
Just in case, using a shorter name "ngx_ssl_ticket_md()" would
save us from wrapping here and in decrypt case.
> + memcpy(name, key[0].name, 16);
> +
> + return 0;
> +
> + } else {
> + /* decrypt session ticket */
> +
> + for (i = 0; i < keys->nelts; i++) {
> + if (ngx_strncmp(name, key[i].name, 16) == 0) {
Shouldn't it be ngx_memcmp(), as it checks binary data now?
> + break;
> + }
> + }
> +
> + if (i == keys->nelts) {
Adding "goto found" instead of "break" would allow to avoid this
additional check. Up to you though.
> + ngx_hex_dump(buf, name, 16);
> +
> + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
> + "ssl session ticket decrypt, key: \"%*s\" "
> + "not found", 32, buf);
> + return 0;
> + }
> +
> +#if (NGX_DEBUG)
> + ngx_hex_dump(buf, key[i].name, 16);
> +
> + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
> + "ssl session ticket decrypt, key: \"%*s\"%s",
> + 32, buf, (i == 0) ? " (default)" : "");
> +#endif
> +
> + HMAC_Init_ex(hctx, key[i].hmac_key, 16, ngx_ssl_session_ticket_md(),
> + NULL);
> + EVP_DecryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, key[i].aes_key, iv);
> +
> + return (i == 0) ? 1 : 2 /* renew */;
[...]
--
Maxim Dounin
http://nginx.org/en/donation.html
More information about the nginx-devel
mailing list