diff options
author | nginx <nginx@nginx.org> | 2014-09-16 14:45:43 +0000 |
---|---|---|
committer | Jon Kolb <kolbyjack@gmail.com> | 2014-09-16 14:45:43 +0000 |
commit | ab9c4cd3a4ed13f61ae572c15042df84d5fb9418 (patch) | |
tree | 80e28a98902c5472a464c642c5702eee4ba2225e | |
parent | 1fdff008eae31a85e7575079a43f1419aba9ba9b (diff) | |
download | nginx-1.6.2.tar.gz |
Changes with nginx 1.6.2 16 Sep 2014v1.6.2
*) Security: it was possible to reuse SSL sessions in unrelated contexts
if a shared SSL session cache or the same TLS session ticket key was
used for multiple "server" blocks (CVE-2014-3616).
Thanks to Antoine Delignat-Lavaud.
*) Bugfix: requests might hang if resolver was used and a DNS server
returned a malformed response; the bug had appeared in 1.5.8.
*) Bugfix: requests might hang if resolver was used and a timeout
occurred during a DNS request.
-rw-r--r-- | CHANGES | 14 | ||||
-rw-r--r-- | CHANGES.ru | 15 | ||||
-rw-r--r-- | src/core/nginx.h | 4 | ||||
-rw-r--r-- | src/core/ngx_resolver.c | 53 | ||||
-rw-r--r-- | src/event/ngx_event_openssl.c | 98 |
5 files changed, 170 insertions, 14 deletions
@@ -1,4 +1,18 @@ +Changes with nginx 1.6.2 16 Sep 2014 + + *) Security: it was possible to reuse SSL sessions in unrelated contexts + if a shared SSL session cache or the same TLS session ticket key was + used for multiple "server" blocks (CVE-2014-3616). + Thanks to Antoine Delignat-Lavaud. + + *) Bugfix: requests might hang if resolver was used and a DNS server + returned a malformed response; the bug had appeared in 1.5.8. + + *) Bugfix: requests might hang if resolver was used and a timeout + occurred during a DNS request. + + Changes with nginx 1.6.1 05 Aug 2014 *) Security: pipelined commands were not discarded after STARTTLS diff --git a/CHANGES.ru b/CHANGES.ru index 509603ca5..aa15be61b 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,19 @@ +Изменения в nginx 1.6.2 16.09.2014 + + *) Безопасность: при использовании общего для нескольких блоков server + разделяемого кэша SSL-сессий или общего ключа для шифрования TLS + session tickets было возможно повторно использовать SSL-сессию в + контексте другого блока server (CVE-2014-3616). + Спасибо Antoine Delignat-Lavaud. + + *) Исправление: запросы могли зависать, если использовался resolver и + DNS-сервер возвращал некорректный ответ; ошибка появилась в 1.5.8. + + *) Исправление: запросы могли зависать, если использовался resolver и в + процессе обращения к DNS-серверу происходил таймаут. + + Изменения в nginx 1.6.1 05.08.2014 *) Безопасность: pipelined-команды не отбрасывались после команды diff --git a/src/core/nginx.h b/src/core/nginx.h index ac9f656e6..20dcd1d78 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1006001 -#define NGINX_VERSION "1.6.1" +#define nginx_version 1006002 +#define NGINX_VERSION "1.6.2" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index 645738ce5..5a944fc79 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -417,7 +417,7 @@ ngx_resolve_name_done(ngx_resolver_ctx_t *ctx) /* lock name mutex */ - if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) { + if (ctx->state == NGX_AGAIN) { hash = ngx_crc32_short(ctx->name.data, ctx->name.len); @@ -664,7 +664,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) } ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; + ctx->event->data = rn; ctx->event->log = r->log; ctx->ident = -1; @@ -857,7 +857,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) } ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; + ctx->event->data = rn; ctx->event->log = r->log; ctx->ident = -1; @@ -949,7 +949,7 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx) /* lock addr mutex */ - if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) { + if (ctx->state == NGX_AGAIN) { switch (ctx->addr.sockaddr->sa_family) { @@ -1467,7 +1467,6 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, goto failed; } - rn->naddrs6 = 0; qident = (rn->query6[0] << 8) + rn->query6[1]; break; @@ -1482,7 +1481,6 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, goto failed; } - rn->naddrs = 0; qident = (rn->query[0] << 8) + rn->query[1]; } @@ -1507,6 +1505,8 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, case NGX_RESOLVE_AAAA: + rn->naddrs6 = 0; + if (rn->naddrs == (u_short) -1) { goto next; } @@ -1519,6 +1519,8 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, default: /* NGX_RESOLVE_A */ + rn->naddrs = 0; + if (rn->naddrs6 == (u_short) -1) { goto next; } @@ -1539,6 +1541,8 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, case NGX_RESOLVE_AAAA: + rn->naddrs6 = 0; + if (rn->naddrs == (u_short) -1) { rn->code = (u_char) code; goto next; @@ -1548,6 +1552,8 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, default: /* NGX_RESOLVE_A */ + rn->naddrs = 0; + if (rn->naddrs6 == (u_short) -1) { rn->code = (u_char) code; goto next; @@ -1817,6 +1823,25 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, } } + switch (qtype) { + +#if (NGX_HAVE_INET6) + case NGX_RESOLVE_AAAA: + + if (rn->naddrs6 == (u_short) -1) { + rn->naddrs6 = 0; + } + + break; +#endif + + default: /* NGX_RESOLVE_A */ + + if (rn->naddrs == (u_short) -1) { + rn->naddrs = 0; + } + } + if (rn->naddrs != (u_short) -1 #if (NGX_HAVE_INET6) && rn->naddrs6 != (u_short) -1 @@ -2766,13 +2791,21 @@ done: static void ngx_resolver_timeout_handler(ngx_event_t *ev) { - ngx_resolver_ctx_t *ctx; + ngx_resolver_ctx_t *ctx, *next; + ngx_resolver_node_t *rn; - ctx = ev->data; + rn = ev->data; + ctx = rn->waiting; + rn->waiting = NULL; - ctx->state = NGX_RESOLVE_TIMEDOUT; + do { + ctx->state = NGX_RESOLVE_TIMEDOUT; + next = ctx->next; - ctx->handler(ctx); + ctx->handler(ctx); + + ctx = next; + } while (ctx); } diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index d8dd3d358..72c255908 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -27,6 +27,8 @@ static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, char *text); static void ngx_ssl_clear_error(ngx_log_t *log); +static ngx_int_t ngx_ssl_session_id_context(ngx_ssl_t *ssl, + ngx_str_t *sess_ctx); ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data); static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess); @@ -1729,13 +1731,15 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, SSL_CTX_set_timeout(ssl->ctx, (long) timeout); + if (ngx_ssl_session_id_context(ssl, sess_ctx) != NGX_OK) { + return NGX_ERROR; + } + if (builtin_session_cache == NGX_SSL_NO_SCACHE) { SSL_CTX_set_session_cache_mode(ssl->ctx, SSL_SESS_CACHE_OFF); return NGX_OK; } - SSL_CTX_set_session_id_context(ssl->ctx, sess_ctx->data, sess_ctx->len); - if (builtin_session_cache == NGX_SSL_NONE_SCACHE) { /* @@ -1792,6 +1796,96 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, } +static ngx_int_t +ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx) +{ + int n, i; + X509 *cert; + X509_NAME *name; + EVP_MD_CTX md; + unsigned int len; + STACK_OF(X509_NAME) *list; + u_char buf[EVP_MAX_MD_SIZE]; + + /* + * Session ID context is set based on the string provided, + * the server certificate, and the client CA list. + */ + + EVP_MD_CTX_init(&md); + + if (EVP_DigestInit_ex(&md, EVP_sha1(), NULL) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "EVP_DigestInit_ex() failed"); + goto failed; + } + + if (EVP_DigestUpdate(&md, sess_ctx->data, sess_ctx->len) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "EVP_DigestUpdate() failed"); + goto failed; + } + + cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index); + + if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "X509_digest() failed"); + goto failed; + } + + if (EVP_DigestUpdate(&md, buf, len) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "EVP_DigestUpdate() failed"); + goto failed; + } + + list = SSL_CTX_get_client_CA_list(ssl->ctx); + + if (list != NULL) { + n = sk_X509_NAME_num(list); + + for (i = 0; i < n; i++) { + name = sk_X509_NAME_value(list, i); + + if (X509_NAME_digest(name, EVP_sha1(), buf, &len) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "X509_NAME_digest() failed"); + goto failed; + } + + if (EVP_DigestUpdate(&md, buf, len) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "EVP_DigestUpdate() failed"); + goto failed; + } + } + } + + if (EVP_DigestFinal_ex(&md, buf, &len) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "EVP_DigestUpdate() failed"); + goto failed; + } + + EVP_MD_CTX_cleanup(&md); + + if (SSL_CTX_set_session_id_context(ssl->ctx, buf, len) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set_session_id_context() failed"); + return NGX_ERROR; + } + + return NGX_OK; + +failed: + + EVP_MD_CTX_cleanup(&md); + + return NGX_ERROR; +} + + ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data) { |