summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES14
-rw-r--r--CHANGES.ru15
-rw-r--r--src/core/nginx.h4
-rw-r--r--src/core/ngx_resolver.c53
-rw-r--r--src/event/ngx_event_openssl.c98
5 files changed, 170 insertions, 14 deletions
diff --git a/CHANGES b/CHANGES
index 1c0cd724a..5b1242a43 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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)
{