BSDSec

deadsimple BSD Security Advisories and Announcements

fix for nginx SSL session reuse

This issue also affects 5.4, 5.5 and 5.6. Patches available in the
respective directories.

5.5 patch follows.

http://ftp.openbsd.org/pub/OpenBSD/patches/5.5/common/011_nginx.patch.sig

untrusted comment: signature from openbsd 5.5 base secret key
RWRGy8gxk9N93yafiuGu4x20xhAgMsmcjCmHJrYJBolmNu2NJUqcC3s+pOmCbUPPX2GxRlEIotfwpbcVG23OoCHguJSk8FZc+Qk
OpenBSD 5.5 errata 11, Oct 1, 2014:  Fix for the SSL session reuse
vulnerability (CVE-2014-3616).

Apply patch using:

    signify -Vep /etc/signify/openbsd-55-base.pub -x 011_nginx.patch.sig -m - | \
        (cd /usr/src && patch -p0)

Then build and install nginx:

    cd /usr/src/usr.sbin/nginx
    make -f Makefile.bsd-wrapper obj 
    make -f Makefile.bsd-wrapper
    make -f Makefile.bsd-wrapper install

Index: usr.sbin/nginx/src/event/ngx_event_openssl.c
===================================================================
RCS file: /cvs/src/usr.sbin/nginx/src/event/ngx_event_openssl.c,v
retrieving revision 1.12
diff -u -p -u -r1.12 ngx_event_openssl.c
--- usr.sbin/nginx/src/event/ngx_event_openssl.c	1 Jun 2013 16:12:54 -0000	1.12
+++ usr.sbin/nginx/src/event/ngx_event_openssl.c	18 Sep 2014 14:18:24 -0000
@@ -27,6 +27,8 @@ static void ngx_ssl_connection_error(ngx
     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);
@@ -1659,13 +1661,15 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ng
 {
     long  cache_mode;
 
+    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) {
 
         /*
@@ -1769,6 +1773,94 @@ ngx_ssl_session_cache_init(ngx_shm_zone_
     return NGX_OK;
 }
 
+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;
+}
 
 /*
  * The length of the session id is 16 bytes for SSLv2 sessions and