[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

nss: CVE-2015-2730 and CVE-2015-2721



Hi,
packages that fix the above two CVEs are here:

    http://honk.dyn.sigxcpu.org/projects/squeeze-lts/

I'd be great to have some feedback if this version doesn't introduce any
regressions. I've attached the debdiff as well for review.

Salvatore suggested to move to newer nss versions with future uploads
and I think that's a great idea if we do this with jessie and wheezy in
lockstep.
Cheers,
 -- Guido
diff --git a/debian/changelog b/debian/changelog
index 606d70e..ac35603 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,14 @@
+nss (3.12.8-1+squeeze8~agx0) squeeze-security; urgency=medium
+
+  * Non-maintainer upload by the LTS Security Team.
+  * Add CVE-2015-2730:
+    CVE-2015-2730: ECDSA signature validation fails to handle some
+    signatures correctly.
+  * Add CVE-2015-2721.patch:
+    CVE-2015-2721: NSS incorrectly permits skipping of ServerKeyExchange.
+
+ -- Guido Günther <agx@sigxcpu.org>  Sat, 26 Sep 2015 14:29:48 +0200
+
 nss (3.12.8-1+squeeze7) squeeze-security; urgency=high
 
   * Non-maintainer upload by the Security Team.
diff --git a/debian/patches/CVE-2015-2721.patch b/debian/patches/CVE-2015-2721.patch
new file mode 100644
index 0000000..346f7b1
--- /dev/null
+++ b/debian/patches/CVE-2015-2721.patch
@@ -0,0 +1,240 @@
+From: =?utf-8?q?Guido_G=C3=BCnther?= <agx@sigxcpu.org>
+Date: Sun, 26 Jul 2015 17:46:09 +0200
+Subject: CVE-2015-2721
+
+---
+ mozilla/security/nss/lib/ssl/ssl3con.c | 135 +++++++++++++++++----------------
+ mozilla/security/nss/lib/ssl/sslimpl.h |   6 ++
+ 2 files changed, 74 insertions(+), 67 deletions(-)
+
+diff --git a/mozilla/security/nss/lib/ssl/ssl3con.c b/mozilla/security/nss/lib/ssl/ssl3con.c
+index da6c8a3..e316047 100644
+--- a/mozilla/security/nss/lib/ssl/ssl3con.c
++++ b/mozilla/security/nss/lib/ssl/ssl3con.c
+@@ -268,28 +268,28 @@ static const ssl3BulkCipherDef bulk_cipher_defs[] = {
+ 
+ static const ssl3KEADef kea_defs[] = 
+ { /* indexed by SSL3KeyExchangeAlgorithm */
+-    /* kea              exchKeyType signKeyType is_limited limit  tls_keygen */
+-    {kea_null,           kt_null,     sign_null, PR_FALSE,   0, PR_FALSE},
+-    {kea_rsa,            kt_rsa,      sign_rsa,  PR_FALSE,   0, PR_FALSE},
+-    {kea_rsa_export,     kt_rsa,      sign_rsa,  PR_TRUE,  512, PR_FALSE},
+-    {kea_rsa_export_1024,kt_rsa,      sign_rsa,  PR_TRUE, 1024, PR_FALSE},
+-    {kea_dh_dss,         kt_dh,       sign_dsa,  PR_FALSE,   0, PR_FALSE},
+-    {kea_dh_dss_export,  kt_dh,       sign_dsa,  PR_TRUE,  512, PR_FALSE},
+-    {kea_dh_rsa,         kt_dh,       sign_rsa,  PR_FALSE,   0, PR_FALSE},
+-    {kea_dh_rsa_export,  kt_dh,       sign_rsa,  PR_TRUE,  512, PR_FALSE},
+-    {kea_dhe_dss,        kt_dh,       sign_dsa,  PR_FALSE,   0, PR_FALSE},
+-    {kea_dhe_dss_export, kt_dh,       sign_dsa,  PR_TRUE,  512, PR_FALSE},
+-    {kea_dhe_rsa,        kt_dh,       sign_rsa,  PR_FALSE,   0, PR_FALSE},
+-    {kea_dhe_rsa_export, kt_dh,       sign_rsa,  PR_TRUE,  512, PR_FALSE},
+-    {kea_dh_anon,        kt_dh,       sign_null, PR_FALSE,   0, PR_FALSE},
+-    {kea_dh_anon_export, kt_dh,       sign_null, PR_TRUE,  512, PR_FALSE},
+-    {kea_rsa_fips,       kt_rsa,      sign_rsa,  PR_FALSE,   0, PR_TRUE },
++    /* kea            exchKeyType signKeyType is_limited limit tls_keygen ephemeral */
++    {kea_null,           kt_null, sign_null,  PR_FALSE,   0, PR_FALSE, PR_FALSE},
++    {kea_rsa,            kt_rsa,  sign_rsa,   PR_FALSE,   0, PR_FALSE, PR_FALSE},
++    {kea_rsa_export,     kt_rsa,  sign_rsa,   PR_TRUE,  512, PR_FALSE, PR_TRUE},
++    {kea_rsa_export_1024,kt_rsa,  sign_rsa,   PR_TRUE, 1024, PR_FALSE, PR_TRUE},
++    {kea_dh_dss,         kt_dh,   sign_dsa,   PR_FALSE,   0, PR_FALSE, PR_FALSE},
++    {kea_dh_dss_export,  kt_dh,   sign_dsa,   PR_TRUE,  512, PR_FALSE, PR_FALSE},
++    {kea_dh_rsa,         kt_dh,   sign_rsa,   PR_FALSE,   0, PR_FALSE, PR_FALSE},
++    {kea_dh_rsa_export,  kt_dh,   sign_rsa,   PR_TRUE,  512, PR_FALSE, PR_FALSE},
++    {kea_dhe_dss,        kt_dh,   sign_dsa,   PR_FALSE,   0, PR_FALSE, PR_TRUE},
++    {kea_dhe_dss_export, kt_dh,   sign_dsa,   PR_TRUE,  512, PR_FALSE, PR_TRUE},
++    {kea_dhe_rsa,        kt_dh,   sign_rsa,   PR_FALSE,   0, PR_FALSE, PR_TRUE},
++    {kea_dhe_rsa_export, kt_dh,   sign_rsa,   PR_TRUE,  512, PR_FALSE, PR_TRUE},
++    {kea_dh_anon,        kt_dh,   sign_null,  PR_FALSE,   0, PR_FALSE, PR_TRUE},
++    {kea_dh_anon_export, kt_dh,   sign_null,  PR_TRUE,  512, PR_FALSE, PR_TRUE},
++    {kea_rsa_fips,       kt_rsa,  sign_rsa,   PR_FALSE,   0, PR_TRUE,  PR_FALSE},
+ #ifdef NSS_ENABLE_ECC
+-    {kea_ecdh_ecdsa,     kt_ecdh,     sign_ecdsa,  PR_FALSE, 0, PR_FALSE},
+-    {kea_ecdhe_ecdsa,    kt_ecdh,     sign_ecdsa,  PR_FALSE,   0, PR_FALSE},
+-    {kea_ecdh_rsa,       kt_ecdh,     sign_rsa,  PR_FALSE,   0, PR_FALSE},
+-    {kea_ecdhe_rsa,      kt_ecdh,     sign_rsa,  PR_FALSE,   0, PR_FALSE},
+-    {kea_ecdh_anon,      kt_ecdh,     sign_null,  PR_FALSE,   0, PR_FALSE},
++    {kea_ecdh_ecdsa,     kt_ecdh, sign_ecdsa, PR_FALSE,   0, PR_FALSE, PR_FALSE},
++    {kea_ecdhe_ecdsa,    kt_ecdh, sign_ecdsa, PR_FALSE,   0, PR_FALSE, PR_TRUE},
++    {kea_ecdh_rsa,       kt_ecdh, sign_rsa,   PR_FALSE,   0, PR_FALSE, PR_FALSE},
++    {kea_ecdhe_rsa,      kt_ecdh, sign_rsa,   PR_FALSE,   0, PR_FALSE, PR_TRUE},
++    {kea_ecdh_anon,      kt_ecdh, sign_null,  PR_FALSE,   0, PR_FALSE, PR_TRUE},
+ #endif /* NSS_ENABLE_ECC */
+ };
+ 
+@@ -5177,7 +5177,17 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+     PORT_Memcpy(sid->u.ssl3.sessionID, sidBytes.data, sidBytes.len);
+ 
+     ss->ssl3.hs.isResuming = PR_FALSE;
+-    ss->ssl3.hs.ws         = wait_server_cert;
++    if (ss->ssl3.hs.kea_def->signKeyType != sign_null) {
++        /* All current cipher suites other than those with sign_null (i.e.,
++         * DH_anon_* suites) require a certificate, so use that signal. */
++        ss->ssl3.hs.ws = wait_server_cert;
++    } else if (ss->ssl3.hs.kea_def->ephemeral) {
++        /* Only ephemeral cipher suites use ServerKeyExchange. */
++        ss->ssl3.hs.ws = wait_server_key;
++    } else {
++        ss->ssl3.hs.ws = wait_cert_request;
++    }
++
+     return SECSuccess;
+ 
+ alert_loser:
+@@ -5209,16 +5219,10 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ 
+-    if (ss->ssl3.hs.ws != wait_server_key &&
+-	ss->ssl3.hs.ws != wait_server_cert) {
+-	errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH;
+-	desc    = unexpected_message;
+-	goto alert_loser;
+-    }
+-    if (ss->sec.peerCert == NULL) {
+-	errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH;
+-	desc    = unexpected_message;
+-	goto alert_loser;
++    if (ss->ssl3.hs.ws != wait_server_key) {
++        errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH;
++        desc = unexpected_message;
++        goto alert_loser;
+     }
+ 
+     isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
+@@ -5452,11 +5456,10 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ 
+-    if (ss->ssl3.hs.ws != wait_cert_request &&
+-    	ss->ssl3.hs.ws != wait_server_key) {
+-	desc    = unexpected_message;
+-	errCode = SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST;
+-	goto alert_loser;
++    if (ss->ssl3.hs.ws != wait_cert_request) {
++        desc = unexpected_message;
++        errCode = SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST;
++        goto alert_loser;
+     }
+ 
+     /* clean up anything left from previous handshake. */
+@@ -5704,9 +5707,8 @@ ssl3_HandleServerHelloDone(sslSocket *ss)
+     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ 
++    /* Skipping CertificateRequest is always permitted. */
+     if (ws != wait_hello_done  &&
+-        ws != wait_server_cert &&
+-	ws != wait_server_key  &&
+ 	ws != wait_cert_request) {
+ 	SSL3_SendAlert(ss, alert_fatal, unexpected_message);
+ 	PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
+@@ -5928,14 +5930,11 @@ ssl3_SendServerHelloSequence(sslSocket *ss)
+ 	    return rv;
+ #endif
+ 	}
+-#ifdef NSS_ENABLE_ECC
+-    } else if ((kea_def->kea == kea_ecdhe_rsa) ||
+-	       (kea_def->kea == kea_ecdhe_ecdsa)) {
+-	rv = ssl3_SendServerKeyExchange(ss);
+-	if (rv != SECSuccess) {
+-	    return rv;	/* err code was set. */
+-	}
+-#endif /* NSS_ENABLE_ECC */
++    } else if (kea_def->ephemeral) {
++        rv = ssl3_SendServerKeyExchange(ss);
++        if (rv != SECSuccess) {
++            return rv;	/* err code was set. */
++        }
+     }
+ 
+     if (ss->opt.requestCertificate) {
+@@ -5984,6 +5983,22 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+ 
+     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
++    PORT_Assert( ss->ssl3.initialized );
++
++    if (!ss->sec.isServer ||
++        (ss->ssl3.hs.ws != wait_client_hello &&
++         ss->ssl3.hs.ws != idle_handshake)) {
++        desc = unexpected_message;
++        errCode = SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO;
++        goto alert_loser;
++    }
++    if (ss->ssl3.hs.ws == idle_handshake &&
++        ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
++        desc = no_renegotiation;
++        level = alert_warning;
++        errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
++        goto alert_loser;
++    }
+ 
+     /* Get peer name of client */
+     rv = ssl_GetPeerInfo(ss);
+@@ -6002,20 +6017,6 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+ 	return rv;		/* ssl3_InitState has set the error code. */
+     }
+ 
+-    if ((ss->ssl3.hs.ws != wait_client_hello) &&
+-	(ss->ssl3.hs.ws != idle_handshake)) {
+-	desc    = unexpected_message;
+-	errCode = SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO;
+-	goto alert_loser;
+-    }
+-    if (ss->ssl3.hs.ws == idle_handshake  &&
+-        ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
+-	desc    = no_renegotiation;
+-	level   = alert_warning;
+-	errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
+-	goto alert_loser;
+-    }
+-
+     tmp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
+     if (tmp < 0)
+ 	goto loser;		/* malformed, alert already sent */
+@@ -7165,7 +7166,7 @@ ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
+     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ 
+-    if (ss->ssl3.hs.ws != wait_cert_verify || ss->sec.peerCert == NULL) {
++    if (ss->ssl3.hs.ws != wait_cert_verify) {
+ 	desc    = unexpected_message;
+ 	errCode = SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY;
+ 	goto alert_loser;
+@@ -7785,11 +7786,11 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
+     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ 
+-    if ((ss->ssl3.hs.ws != wait_server_cert) &&
+-	(ss->ssl3.hs.ws != wait_client_cert)) {
+-	desc    = unexpected_message;
+-	errCode = SSL_ERROR_RX_UNEXPECTED_CERTIFICATE;
+-	goto alert_loser;
++    if ((isServer && ss->ssl3.hs.ws != wait_client_cert) ||
++        (!isServer && ss->ssl3.hs.ws != wait_server_cert)) {
++        desc = unexpected_message;
++        errCode = SSL_ERROR_RX_UNEXPECTED_CERTIFICATE;
++        goto alert_loser;
+     }
+ 
+     if (ss->sec.peerCert != NULL) {
+diff --git a/mozilla/security/nss/lib/ssl/sslimpl.h b/mozilla/security/nss/lib/ssl/sslimpl.h
+index 9af471d..55fa960 100644
+--- a/mozilla/security/nss/lib/ssl/sslimpl.h
++++ b/mozilla/security/nss/lib/ssl/sslimpl.h
+@@ -671,9 +671,15 @@ typedef struct {
+     SSL3KeyExchangeAlgorithm kea;
+     SSL3KEAType              exchKeyType;
+     SSL3SignType             signKeyType;
++    /* For export cipher suites:
++     * is_limited identifies a suite as having a limit on the key size.
++     * key_size_limit provides the corresponding limit. */
+     PRBool                   is_limited;
+     int                      key_size_limit;
+     PRBool                   tls_keygen;
++    /* True if the key exchange for the suite can be ephemeral.  Or to be more
++     * precise: true if the ServerKeyExchange message is required. */
++    PRBool                   ephemeral;
+ } ssl3KEADef;
+ 
+ typedef enum { kg_null, kg_strong, kg_export } SSL3KeyGenMode;
diff --git a/debian/patches/CVE-2015-2730.patch b/debian/patches/CVE-2015-2730.patch
new file mode 100644
index 0000000..24b3a48
--- /dev/null
+++ b/debian/patches/CVE-2015-2730.patch
@@ -0,0 +1,46 @@
+From: =?utf-8?q?Guido_G=C3=BCnther?= <agx@sigxcpu.org>
+Date: Sat, 25 Jul 2015 16:24:40 +0200
+Subject: CVE-2015-2730
+
+Based on upstream commit
+
+    https://hg.mozilla.org/projects/nss/rev/2c05e861ce07
+---
+ mozilla/security/nss/lib/freebl/ecl/ecp_jac.c | 17 ++++++++++++++++-
+ 1 file changed, 16 insertions(+), 1 deletion(-)
+
+diff --git a/mozilla/security/nss/lib/freebl/ecl/ecp_jac.c b/mozilla/security/nss/lib/freebl/ecl/ecp_jac.c
+index 2659dbb..fb2cf74 100644
+--- a/mozilla/security/nss/lib/freebl/ecl/ecp_jac.c
++++ b/mozilla/security/nss/lib/freebl/ecl/ecp_jac.c
+@@ -183,6 +183,20 @@ ec_GFp_pt_add_jac_aff(const mp_int *px, const mp_int *py, const mp_int *pz,
+ 	MP_CHECKOK(group->meth->field_sub(&A, px, &C, group->meth));
+ 	MP_CHECKOK(group->meth->field_sub(&B, py, &D, group->meth));
+ 
++	if (mp_cmp_z(&C) == 0) {
++		/* P == Q or P == -Q */
++		if (mp_cmp_z(&D) == 0) {
++			/* P == Q */
++			/* It is cheaper to double (qx, qy, 1) than (px, py, pz). */
++			MP_DIGIT(&D, 0) = 1; /* Set D to 1. */
++			MP_CHECKOK(ec_GFp_pt_dbl_jac(qx, qy, &D, rx, ry, rz, group));
++		} else {
++			/* P == -Q */
++			MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz));
++		}
++		goto CLEANUP;
++	}
++
+ 	/* C2 = C^2, C3 = C^3 */
+ 	MP_CHECKOK(group->meth->field_sqr(&C, &C2, group->meth));
+ 	MP_CHECKOK(group->meth->field_mul(&C, &C2, &C3, group->meth));
+@@ -244,7 +258,8 @@ ec_GFp_pt_dbl_jac(const mp_int *px, const mp_int *py, const mp_int *pz,
+ 	MP_CHECKOK(mp_init(&M));
+ 	MP_CHECKOK(mp_init(&S));
+ 
+-	if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
++	/* P == inf or P == -P */
++	if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES || mp_cmp_z(py) == 0) {
+ 		MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz));
+ 		goto CLEANUP;
+ 	}
diff --git a/debian/patches/series b/debian/patches/series
index f34638c..ccb5bf4 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -19,3 +19,5 @@ CVE-2011-3640
 CVE-2012-0441
 TURKTRUST.patch
 CVE-2013-5605.patch
+CVE-2015-2730.patch
+CVE-2015-2721.patch

Reply to: