diff -Nru nss-3.28.4/debian/changelog nss-3.28.4/debian/changelog --- nss-3.28.4/debian/changelog 2017-09-29 12:54:11.000000000 +0000 +++ nss-3.28.4/debian/changelog 2018-12-14 14:59:43.000000000 +0000 @@ -1,3 +1,26 @@ +nss (2:3.28.4-0ubuntu0.16.04.4) xenial-security; urgency=medium + + * SECURITY UPDATE: side-channel attack on ECDSA signatures + - debian/patches/CVE-2018-0495.patch: improve ecdsa and dsa in + nss/lib/freebl/dsa.c, nss/lib/freebl/ec.c. + - CVE-2018-0495 + * SECURITY UPDATE: ServerHello.random is all zero in v2 ClientHello + - debian/patches/CVE-2018-12384-1.patch: fix random logic in + nss/lib/ssl/ssl3con.c. + - debian/patches/CVE-2018-12384-2.patch: add tests to + nss/gtests/ssl_gtest/ssl_loopback_unittest.cc, + nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc. + - CVE-2018-12384 + * SECURITY UPDATE: cache side-channel variant of the Bleichenbacher attack + - debian/patches/CVE-2018-12404-1.patch: improve RSA key exchange + handling in nss/lib/ssl/ssl3con.c. + - debian/patches/CVE-2018-12404-3.patch: add constant time + mp_to_fixlen_octets in nss/gtests/freebl_gtest/mpi_unittest.cc, + nss/lib/freebl/mpi/mpi.c, nss/lib/freebl/mpi/mpi.h. + - CVE-2018-12404 + + -- Marc Deslauriers Fri, 14 Dec 2018 09:59:33 -0500 + nss (2:3.28.4-0ubuntu0.16.04.3) xenial-security; urgency=medium * SECURITY UPDATE: Use-after-free in TLS 1.2 generating handshake hashes diff -Nru nss-3.28.4/debian/patches/CVE-2018-0495.patch nss-3.28.4/debian/patches/CVE-2018-0495.patch --- nss-3.28.4/debian/patches/CVE-2018-0495.patch 1970-01-01 00:00:00.000000000 +0000 +++ nss-3.28.4/debian/patches/CVE-2018-0495.patch 2018-12-14 14:48:21.000000000 +0000 @@ -0,0 +1,185 @@ +Backport of: + +# HG changeset patch +# User Franziskus Kiefer +# Date 1527579529 -7200 +# Node ID ca18ca4ba00d97ac9683d92d3a16d9832342ba75 +# Parent db7f6facd8dfa0ec4f91612b62c563ecf3892063 +Bug 1464971 - improve ecdsa and dsa, r=mt + +Differential Revision: https://phabricator.services.mozilla.com/D1441 + +Index: nss-3.28.4/nss/lib/freebl/dsa.c +=================================================================== +--- nss-3.28.4.orig/nss/lib/freebl/dsa.c 2018-12-14 09:16:21.558298874 -0500 ++++ nss-3.28.4/nss/lib/freebl/dsa.c 2018-12-14 09:16:21.558298874 -0500 +@@ -16,14 +16,11 @@ + #include "blapi.h" + #include "nssilock.h" + #include "secitem.h" +-#include "blapi.h" ++#include "blapit.h" + #include "mpi.h" + #include "secmpi.h" + #include "pqg.h" + +-/* XXX to be replaced by define in blapit.h */ +-#define NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE 2048 +- + /* + * FIPS 186-2 requires result from random output to be reduced mod q when + * generating random numbers for DSA. +@@ -168,7 +165,7 @@ dsa_NewKeyExtended(const PQGParams *para + return SECFailure; + } + /* Initialize an arena for the DSA key. */ +- arena = PORT_NewArena(NSS_FREEBL_DSA_DEFAULT_CHUNKSIZE); ++ arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE); + if (!arena) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; +@@ -213,8 +210,9 @@ cleanup: + mp_clear(&g); + mp_clear(&x); + mp_clear(&y); +- if (key) ++ if (key) { + PORT_FreeArena(key->params.arena, PR_TRUE); ++ } + if (err) { + translate_mpi_error(err); + return SECFailure; +@@ -321,6 +319,7 @@ dsa_SignDigest(DSAPrivateKey *key, SECIt + mp_int x, k; /* private key & pseudo-random integer */ + mp_int r, s; /* tuple (r, s) is signature) */ + mp_int t; /* holding tmp values */ ++ mp_int ar; /* holding blinding values */ + mp_err err = MP_OKAY; + SECStatus rv = SECSuccess; + unsigned int dsa_subprime_len, dsa_signature_len, offset; +@@ -364,6 +363,7 @@ dsa_SignDigest(DSAPrivateKey *key, SECIt + MP_DIGITS(&r) = 0; + MP_DIGITS(&s) = 0; + MP_DIGITS(&t) = 0; ++ MP_DIGITS(&ar) = 0; + CHECK_MPI_OK(mp_init(&p)); + CHECK_MPI_OK(mp_init(&q)); + CHECK_MPI_OK(mp_init(&g)); +@@ -372,6 +372,7 @@ dsa_SignDigest(DSAPrivateKey *key, SECIt + CHECK_MPI_OK(mp_init(&r)); + CHECK_MPI_OK(mp_init(&s)); + CHECK_MPI_OK(mp_init(&t)); ++ CHECK_MPI_OK(mp_init(&ar)); + /* + ** Convert stored PQG and private key into MPI integers. + */ +@@ -397,14 +398,28 @@ dsa_SignDigest(DSAPrivateKey *key, SECIt + rv = SECFailure; + goto cleanup; + } +- SECITEM_TO_MPINT(t2, &t); /* t <-$ Zq */ ++ SECITEM_TO_MPINT(t2, &t); /* t <-$ Zq */ ++ SECITEM_FreeItem(&t2, PR_FALSE); ++ if (DSA_NewRandom(NULL, &key->params.subPrime, &t2) != SECSuccess) { ++ PORT_SetError(SEC_ERROR_NEED_RANDOM); ++ rv = SECFailure; ++ goto cleanup; ++ } ++ SECITEM_TO_MPINT(t2, &ar); /* ar <-$ Zq */ ++ SECITEM_FreeItem(&t2, PR_FALSE); ++ ++ /* Using mp_invmod on k directly would leak bits from k. */ ++ CHECK_MPI_OK(mp_mul(&k, &ar, &k)); /* k = k * ar */ + CHECK_MPI_OK(mp_mulmod(&k, &t, &q, &k)); /* k = k * t mod q */ + CHECK_MPI_OK(mp_invmod(&k, &q, &k)); /* k = k**-1 mod q */ + CHECK_MPI_OK(mp_mulmod(&k, &t, &q, &k)); /* k = k * t mod q */ + SECITEM_TO_MPINT(localDigest, &s); /* s = HASH(M) */ +- CHECK_MPI_OK(mp_mulmod(&x, &r, &q, &x)); /* x = x * r mod q */ +- CHECK_MPI_OK(mp_addmod(&s, &x, &q, &s)); /* s = s + x mod q */ +- CHECK_MPI_OK(mp_mulmod(&s, &k, &q, &s)); /* s = s * k mod q */ ++ /* To avoid leaking secret bits here the addition is blinded. */ ++ CHECK_MPI_OK(mp_mul(&x, &ar, &x)); /* x = x * ar */ ++ CHECK_MPI_OK(mp_mulmod(&x, &r, &q, &x)); /* x = x * r mod q */ ++ CHECK_MPI_OK(mp_mulmod(&s, &ar, &q, &t)); /* t = s * ar mod q */ ++ CHECK_MPI_OK(mp_add(&t, &x, &s)); /* s = t + x */ ++ CHECK_MPI_OK(mp_mulmod(&s, &k, &q, &s)); /* s = s * k mod q */ + /* + ** verify r != 0 and s != 0 + ** mentioned as optional in FIPS 186-1. +@@ -438,7 +453,7 @@ cleanup: + mp_clear(&r); + mp_clear(&s); + mp_clear(&t); +- SECITEM_FreeItem(&t2, PR_FALSE); ++ mp_clear(&ar); + if (err) { + translate_mpi_error(err); + rv = SECFailure; +Index: nss-3.28.4/nss/lib/freebl/ec.c +=================================================================== +--- nss-3.28.4.orig/nss/lib/freebl/ec.c 2018-12-14 09:16:21.558298874 -0500 ++++ nss-3.28.4/nss/lib/freebl/ec.c 2018-12-14 09:16:41.818302456 -0500 +@@ -671,6 +671,7 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *k + mp_int r, s; /* tuple (r, s) is the signature */ + mp_int t; /* holding tmp values */ + mp_int n; ++ mp_int ar; /* blinding value */ + mp_err err = MP_OKAY; + ECParams *ecParams = NULL; + SECItem kGpoint = { siBuffer, NULL, 0 }; +@@ -692,6 +693,7 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *k + MP_DIGITS(&s) = 0; + MP_DIGITS(&n) = 0; + MP_DIGITS(&t) = 0; ++ MP_DIGITS(&ar) = 0; + + /* Check args */ + if (!key || !signature || !digest || !kb || (kblen < 0)) { +@@ -718,6 +720,7 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *k + CHECK_MPI_OK(mp_init(&s)); + CHECK_MPI_OK(mp_init(&n)); + CHECK_MPI_OK(mp_init(&t)); ++ CHECK_MPI_OK(mp_init(&ar)); + + SECITEM_TO_MPINT(ecParams->order, &n); + SECITEM_TO_MPINT(key->privateValue, &d); +@@ -833,12 +836,25 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *k + goto cleanup; + } + CHECK_MPI_OK(mp_read_unsigned_octets(&t, t2, 2 * ecParams->order.len)); /* t <-$ Zn */ +- CHECK_MPI_OK(mp_mulmod(&k, &t, &n, &k)); /* k = k * t mod n */ +- CHECK_MPI_OK(mp_invmod(&k, &n, &k)); /* k = k**-1 mod n */ +- CHECK_MPI_OK(mp_mulmod(&k, &t, &n, &k)); /* k = k * t mod n */ +- CHECK_MPI_OK(mp_mulmod(&d, &r, &n, &d)); /* d = d * r mod n */ +- CHECK_MPI_OK(mp_addmod(&s, &d, &n, &s)); /* s = s + d mod n */ +- CHECK_MPI_OK(mp_mulmod(&s, &k, &n, &s)); /* s = s * k mod n */ ++ PORT_Memset(t2, 0, 2 * ecParams->order.len); ++ if (RNG_GenerateGlobalRandomBytes(t2, 2 * ecParams->order.len) != SECSuccess) { ++ PORT_SetError(SEC_ERROR_NEED_RANDOM); ++ rv = SECFailure; ++ goto cleanup; ++ } ++ CHECK_MPI_OK(mp_read_unsigned_octets(&ar, t2, 2 * ecParams->order.len)); /* ar <-$ Zn */ ++ ++ /* Using mp_invmod on k directly would leak bits from k. */ ++ CHECK_MPI_OK(mp_mul(&k, &ar, &k)); /* k = k * ar */ ++ CHECK_MPI_OK(mp_mulmod(&k, &t, &n, &k)); /* k = k * t mod n */ ++ CHECK_MPI_OK(mp_invmod(&k, &n, &k)); /* k = k**-1 mod n */ ++ CHECK_MPI_OK(mp_mulmod(&k, &t, &n, &k)); /* k = k * t mod n */ ++ /* To avoid leaking secret bits here the addition is blinded. */ ++ CHECK_MPI_OK(mp_mul(&d, &ar, &t)); /* t = d * ar */ ++ CHECK_MPI_OK(mp_mulmod(&t, &r, &n, &d)); /* d = t * r mod n */ ++ CHECK_MPI_OK(mp_mulmod(&s, &ar, &n, &t)); /* t = s * ar mod n */ ++ CHECK_MPI_OK(mp_add(&t, &d, &s)); /* s = t + d */ ++ CHECK_MPI_OK(mp_mulmod(&s, &k, &n, &s)); /* s = s * k mod n */ + + #if EC_DEBUG + mp_todecimal(&s, mpstr); +@@ -876,6 +892,7 @@ cleanup: + mp_clear(&s); + mp_clear(&n); + mp_clear(&t); ++ mp_clear(&ar); + + if (t2) { + PORT_Free(t2); diff -Nru nss-3.28.4/debian/patches/CVE-2018-12384-1.patch nss-3.28.4/debian/patches/CVE-2018-12384-1.patch --- nss-3.28.4/debian/patches/CVE-2018-12384-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ nss-3.28.4/debian/patches/CVE-2018-12384-1.patch 2018-12-14 15:06:53.000000000 +0000 @@ -0,0 +1,41 @@ +Backport of: + +# HG changeset patch +# User Martin Thomson +# Date 1535720767 -7200 +# Node ID 46f9a1f40c3dd53cf4627e007429530fe989f592 +# Parent 93108979390d163ae97d73db5a2df883d2bf8c62 +Bug 1483128, backported fix for CVE-2018-12384 to the NSS_3_36_BRANCH + +Index: nss-3.28.4/nss/lib/ssl/ssl3con.c +=================================================================== +--- nss-3.28.4.orig/nss/lib/ssl/ssl3con.c 2018-12-14 09:48:09.000000000 -0500 ++++ nss-3.28.4/nss/lib/ssl/ssl3con.c 2018-12-14 09:48:58.192430935 -0500 +@@ -8421,14 +8421,6 @@ ssl3_HandleClientHello(sslSocket *ss, SS + goto alert_loser; + } + +- /* Generate the Server Random now so it is available +- * when we process the ClientKeyShare in TLS 1.3 */ +- rv = ssl3_GetNewRandom(&ss->ssl3.hs.server_random); +- if (rv != SECSuccess) { +- errCode = SSL_ERROR_GENERATE_RANDOM_FAILURE; +- goto loser; +- } +- + #ifndef TLS_1_3_DRAFT_VERSION + /* + * [draft-ietf-tls-tls13-11 Section 6.3.1.1]. +@@ -9323,7 +9315,11 @@ ssl3_SendServerHello(sslSocket *ss) + if (rv != SECSuccess) { + return rv; /* err set by AppendHandshake. */ + } +- /* Random already generated in ssl3_HandleClientHello */ ++ ++ rv = ssl3_GetNewRandom(&ss->ssl3.hs.server_random); ++ if (rv != SECSuccess) { ++ return SECFailure; ++ } + rv = ssl3_AppendHandshake( + ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH); + if (rv != SECSuccess) { diff -Nru nss-3.28.4/debian/patches/CVE-2018-12384-2.patch nss-3.28.4/debian/patches/CVE-2018-12384-2.patch --- nss-3.28.4/debian/patches/CVE-2018-12384-2.patch 1970-01-01 00:00:00.000000000 +0000 +++ nss-3.28.4/debian/patches/CVE-2018-12384-2.patch 2018-12-14 14:50:54.000000000 +0000 @@ -0,0 +1,107 @@ +Backport of: + +# HG changeset patch +# User Martin Thomson +# Date 1535421480 -36000 +# Node ID f182a11fbe532b1b9edb76a57a0d4609d9d8ab75 +# Parent a4de0e81d1ccdb153817fbeda86d2182eec6f726 +Bug 1483128 - Test that randoms aren't fixed, r=ekr + +We can't easily test that ClientHello.random and ServerHello.random are truly +random in these tests, but we can catch mistakes the likes of which produced +this bug. This just runs a few handshakes and tests that none of the random +values are equal to any other, or they are equal to zero. + +Index: nss-3.28.4/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc +=================================================================== +--- nss-3.28.4.orig/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc 2018-12-14 09:49:41.076490347 -0500 ++++ nss-3.28.4/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc 2018-12-14 09:50:40.948573444 -0500 +@@ -229,6 +229,51 @@ TEST_F(TlsConnectStreamTls13, Tls13Faile + client_->CheckErrorCode(SSL_ERROR_SOCKET_WRITE_FAILURE); + } + ++// We can't test for randomness easily here, but we can test that we don't ++// produce a zero value, or produce the same value twice. There are 5 values ++// here: two ClientHello.random, two ServerHello.random, and one zero value. ++// Matrix them and fail if any are the same. ++TEST_P(TlsConnectGeneric, CheckRandoms) { ++ ConfigureSessionCache(RESUME_NONE, RESUME_NONE); ++ ++ static const size_t random_len = 32; ++ uint8_t crandom1[random_len], srandom1[random_len]; ++ uint8_t z[random_len] = {0}; ++ ++ auto ch = std::make_shared(ssl_hs_client_hello); ++ client_->SetTlsRecordFilter(ch); ++ auto sh = std::make_shared(ssl_hs_server_hello); ++ server_->SetTlsRecordFilter(sh); ++ Connect(); ++ ASSERT_TRUE(ch->buffer().len() > (random_len + 2)); ++ ASSERT_TRUE(sh->buffer().len() > (random_len + 2)); ++ memcpy(crandom1, ch->buffer().data() + 2, random_len); ++ memcpy(srandom1, sh->buffer().data() + 2, random_len); ++ EXPECT_NE(0, memcmp(crandom1, srandom1, random_len)); ++ EXPECT_NE(0, memcmp(crandom1, z, random_len)); ++ EXPECT_NE(0, memcmp(srandom1, z, random_len)); ++ ++ Reset(); ++ ch = std::make_shared(ssl_hs_client_hello); ++ client_->SetTlsRecordFilter(ch); ++ sh = std::make_shared(ssl_hs_server_hello); ++ server_->SetTlsRecordFilter(sh); ++ Connect(); ++ ASSERT_TRUE(ch->buffer().len() > (random_len + 2)); ++ ASSERT_TRUE(sh->buffer().len() > (random_len + 2)); ++ const uint8_t* crandom2 = ch->buffer().data() + 2; ++ const uint8_t* srandom2 = sh->buffer().data() + 2; ++ ++ EXPECT_NE(0, memcmp(crandom2, srandom2, random_len)); ++ EXPECT_NE(0, memcmp(crandom2, z, random_len)); ++ EXPECT_NE(0, memcmp(srandom2, z, random_len)); ++ ++ EXPECT_NE(0, memcmp(crandom1, crandom2, random_len)); ++ EXPECT_NE(0, memcmp(crandom1, srandom2, random_len)); ++ EXPECT_NE(0, memcmp(srandom1, crandom2, random_len)); ++ EXPECT_NE(0, memcmp(srandom1, srandom2, random_len)); ++} ++ + INSTANTIATE_TEST_CASE_P(GenericStream, TlsConnectGeneric, + ::testing::Combine(TlsConnectTestBase::kTlsModesStream, + TlsConnectTestBase::kTlsVAll)); +Index: nss-3.28.4/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc +=================================================================== +--- nss-3.28.4.orig/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc 2018-12-14 09:49:41.076490347 -0500 ++++ nss-3.28.4/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc 2018-12-14 09:49:41.072490341 -0500 +@@ -333,6 +333,32 @@ TEST_P(SSLv2ClientHelloTest, RequireSafe + Connect(); + } + ++TEST_P(SSLv2ClientHelloTest, CheckServerRandom) { ++ ConfigureSessionCache(RESUME_NONE, RESUME_NONE); ++ SetAvailableCipherSuite(TLS_DHE_RSA_WITH_AES_128_CBC_SHA); ++ ++ static const size_t random_len = 32; ++ uint8_t srandom1[random_len]; ++ uint8_t z[random_len] = {0}; ++ ++ auto sh = std::make_shared(ssl_hs_server_hello); ++ server_->SetTlsRecordFilter(sh); ++ Connect(); ++ ASSERT_TRUE(sh->buffer().len() > (random_len + 2)); ++ memcpy(srandom1, sh->buffer().data() + 2, random_len); ++ EXPECT_NE(0, memcmp(srandom1, z, random_len)); ++ ++ Reset(); ++ sh = std::make_shared(ssl_hs_server_hello); ++ server_->SetTlsRecordFilter(sh); ++ Connect(); ++ ASSERT_TRUE(sh->buffer().len() > (random_len + 2)); ++ const uint8_t* srandom2 = sh->buffer().data() + 2; ++ ++ EXPECT_NE(0, memcmp(srandom2, z, random_len)); ++ EXPECT_NE(0, memcmp(srandom1, srandom2, random_len)); ++} ++ + // Connect to the server with TLS 1.1, signalling that this is a fallback from + // a higher version. As the server doesn't support anything higher than TLS 1.1 + // it must accept the connection. diff -Nru nss-3.28.4/debian/patches/CVE-2018-12404-1.patch nss-3.28.4/debian/patches/CVE-2018-12404-1.patch --- nss-3.28.4/debian/patches/CVE-2018-12404-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ nss-3.28.4/debian/patches/CVE-2018-12404-1.patch 2018-12-14 15:14:26.000000000 +0000 @@ -0,0 +1,116 @@ +Backport of: + +# HG changeset patch +# User Franziskus Kiefer +# Date 1540551022 -7200 +# Node ID 93b536c98e60fe27e4cbf859e746c0929905ec23 +# Parent e00f455d90e5ed34038a1b74c2d53093ba19233f +Bug 1485864 - improve RSA key exchange handling, r=mt + +Differential Revision: https://phabricator.services.mozilla.com//D9914 + +Index: nss-3.28.4/nss/lib/ssl/ssl3con.c +=================================================================== +--- nss-3.28.4.orig/nss/lib/ssl/ssl3con.c 2018-12-14 09:51:24.392633839 -0500 ++++ nss-3.28.4/nss/lib/ssl/ssl3con.c 2018-12-14 09:52:53.468757903 -0500 +@@ -9892,6 +9892,23 @@ ssl3_GenerateRSAPMS(sslSocket *ss, ssl3C + return pms; + } + ++static void ++ssl3_CSwapPK11SymKey(PK11SymKey **x, PK11SymKey **y, PRBool c) ++{ ++ uintptr_t mask = (uintptr_t)c; ++ unsigned int i; ++ for (i = 1; i < sizeof(uintptr_t) * 8; i <<= 1) { ++ mask |= mask << i; ++ } ++ uintptr_t x_ptr = (uintptr_t)*x; ++ uintptr_t y_ptr = (uintptr_t)*y; ++ uintptr_t tmp = (x_ptr ^ y_ptr) & mask; ++ x_ptr = x_ptr ^ tmp; ++ y_ptr = y_ptr ^ tmp; ++ *x = (PK11SymKey *)x_ptr; ++ *y = (PK11SymKey *)y_ptr; ++} ++ + /* Note: The Bleichenbacher attack on PKCS#1 necessitates that we NEVER + * return any indication of failure of the Client Key Exchange message, + * where that failure is caused by the content of the client's message. +@@ -9912,9 +9929,9 @@ ssl3_HandleRSAClientKeyExchange(sslSocke + { + SECStatus rv; + SECItem enc_pms; +- PK11SymKey *tmpPms[2] = { NULL, NULL }; +- PK11SlotInfo *slot; +- int useFauxPms = 0; ++ PK11SymKey *pms = NULL; ++ PK11SymKey *fauxPms = NULL; ++ PK11SlotInfo *slot = NULL; + + PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); + PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); +@@ -9935,11 +9952,6 @@ ssl3_HandleRSAClientKeyExchange(sslSocke + } + } + +-#define currentPms tmpPms[!useFauxPms] +-#define unusedPms tmpPms[useFauxPms] +-#define realPms tmpPms[1] +-#define fauxPms tmpPms[0] +- + /* + * Get as close to algorithm 2 from RFC 5246; Section 7.4.7.1 + * as we can within the constraints of the PKCS#11 interface. +@@ -9994,40 +10006,33 @@ ssl3_HandleRSAClientKeyExchange(sslSocke + * the unwrap. Rather, it is the mechanism with which the + * unwrapped pms will be used. + */ +- realPms = PK11_PubUnwrapSymKey(serverKeyPair->privKey, &enc_pms, +- CKM_SSL3_MASTER_KEY_DERIVE, CKA_DERIVE, 0); ++ pms = PK11_PubUnwrapSymKey(serverKeyPair->privKey, &enc_pms, ++ CKM_SSL3_MASTER_KEY_DERIVE, CKA_DERIVE, 0); + /* Temporarily use the PMS if unwrapping the real PMS fails. */ +- useFauxPms |= (realPms == NULL); ++ ssl3_CSwapPK11SymKey(&pms, &fauxPms, pms == NULL); + + /* Attempt to derive the MS from the PMS. This is the only way to + * check the version field in the RSA PMS. If this fails, we + * then use the faux PMS in place of the PMS. Note that this + * operation should never fail if we are using the faux PMS + * since it is correctly formatted. */ +- rv = ssl3_ComputeMasterSecret(ss, currentPms, NULL); ++ rv = ssl3_ComputeMasterSecret(ss, pms, NULL); + +- /* If we succeeded, then select the true PMS and discard the +- * FPMS. Else, select the FPMS and select the true PMS */ +- useFauxPms |= (rv != SECSuccess); +- +- if (unusedPms) { +- PK11_FreeSymKey(unusedPms); +- } ++ /* If we succeeded, then select the true PMS, else select the FPMS. */ ++ ssl3_CSwapPK11SymKey(&pms, &fauxPms, (rv != SECSuccess) & (fauxPms != NULL)); + + /* This step will derive the MS from the PMS, among other things. */ +- rv = ssl3_InitPendingCipherSpec(ss, currentPms); +- PK11_FreeSymKey(currentPms); ++ rv = ssl3_InitPendingCipherSpec(ss, pms); ++ ++ /* Clear both PMS. */ ++ PK11_FreeSymKey(pms); ++ PK11_FreeSymKey(fauxPms); + + if (rv != SECSuccess) { + (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure); + return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */ + } + +-#undef currentPms +-#undef unusedPms +-#undef realPms +-#undef fauxPms +- + return SECSuccess; + } + diff -Nru nss-3.28.4/debian/patches/CVE-2018-12404-3.patch nss-3.28.4/debian/patches/CVE-2018-12404-3.patch --- nss-3.28.4/debian/patches/CVE-2018-12404-3.patch 1970-01-01 00:00:00.000000000 +0000 +++ nss-3.28.4/debian/patches/CVE-2018-12404-3.patch 2018-12-14 14:59:16.000000000 +0000 @@ -0,0 +1,209 @@ +Backport of: + +# HG changeset patch +# User Martin Thomson +# Date 1543594048 -3600 +# Node ID f550aef6074c43642bdecb0ce21c511c3fbf81eb +# Parent 2ac9939c87ccd681fab7bdbe20eaf092eb26e8ed +Bug 1485864 - Constant time mp_to_fixlen_octets, r=franziskus + +Differential Revision: https://phabricator.services.mozilla.com/D11722 + +Index: nss-3.28.4/nss/gtests/freebl_gtest/mpi_unittest.cc +=================================================================== +--- nss-3.28.4.orig/nss/gtests/freebl_gtest/mpi_unittest.cc 2018-12-14 09:57:04.005108161 -0500 ++++ nss-3.28.4/nss/gtests/freebl_gtest/mpi_unittest.cc 2018-12-14 09:58:52.373260110 -0500 +@@ -20,7 +20,7 @@ + #include "mpi.h" + namespace nss_test { + +-void gettime(struct timespec *tp) { ++void gettime(struct timespec* tp) { + #ifdef __MACH__ + clock_serv_t cclock; + mach_timespec_t mts; +@@ -51,6 +51,39 @@ class MPITest : public ::testing::Test { + mp_read_radix(&b, b_string.c_str(), 16); + EXPECT_EQ(result, mp_cmp(&a, &b)); + } ++ ++ void dump(const std::string& prefix, const uint8_t* buf, size_t len) { ++ auto flags = std::cerr.flags(); ++ std::cerr << prefix << ": [" << std::dec << len << "] "; ++ for (size_t i = 0; i < len; ++i) { ++ std::cerr << std::hex << std::setw(2) << std::setfill('0') ++ << static_cast(buf[i]); ++ } ++ std::cerr << std::endl << std::resetiosflags(flags); ++ } ++ ++ void TestToFixedOctets(const std::vector& ref, size_t len) { ++ mp_int a; ++ ASSERT_EQ(MP_OKAY, mp_init(&a)); ++ ASSERT_EQ(MP_OKAY, mp_read_unsigned_octets(&a, ref.data(), ref.size())); ++ uint8_t buf[len]; ++ ASSERT_EQ(MP_OKAY, mp_to_fixlen_octets(&a, buf, len)); ++ size_t compare; ++ if (len > ref.size()) { ++ for (size_t i = 0; i < len - ref.size(); ++i) { ++ ASSERT_EQ(0U, buf[i]) << "index " << i << " should be zero"; ++ } ++ compare = ref.size(); ++ } else { ++ compare = len; ++ } ++ dump("value", ref.data(), ref.size()); ++ dump("output", buf, len); ++ ASSERT_EQ(0, memcmp(buf + len - compare, ref.data() + ref.size() - compare, ++ compare)) ++ << "comparing " << compare << " octets"; ++ mp_clear(&a); ++ } + }; + + TEST_F(MPITest, MpiCmp01Test) { TestCmp("0", "1", -1); } +@@ -115,4 +148,45 @@ TEST_F(MPITest, MpiCmpConstTest) { + printf("time c: %u\n", time_c / runs); + } + ++TEST_F(MPITest, MpiFixlenOctetsZero) { ++ std::vector zero = {0}; ++ TestToFixedOctets(zero, 1); ++ TestToFixedOctets(zero, 2); ++ TestToFixedOctets(zero, sizeof(mp_digit)); ++ TestToFixedOctets(zero, sizeof(mp_digit) + 1); ++} ++ ++TEST_F(MPITest, MpiFixlenOctetsVarlen) { ++ std::vector packed; ++ for (size_t i = 0; i < sizeof(mp_digit) * 2; ++i) { ++ packed.push_back(0xa4); // Any non-zero value will do. ++ TestToFixedOctets(packed, packed.size()); ++ TestToFixedOctets(packed, packed.size() + 1); ++ TestToFixedOctets(packed, packed.size() + sizeof(mp_digit)); ++ } ++} ++ ++TEST_F(MPITest, MpiFixlenOctetsTooSmall) { ++ uint8_t buf[sizeof(mp_digit) * 3]; ++ std::vector ref; ++ for (size_t i = 0; i < sizeof(mp_digit) * 2; i++) { ++ ref.push_back(3); // Any non-zero value will do. ++ dump("ref", ref.data(), ref.size()); ++ ++ mp_int a; ++ ASSERT_EQ(MP_OKAY, mp_init(&a)); ++ ASSERT_EQ(MP_OKAY, mp_read_unsigned_octets(&a, ref.data(), ref.size())); ++#ifdef DEBUG ++ // ARGCHK maps to assert() in a debug build. ++ EXPECT_DEATH(mp_to_fixlen_octets(&a, buf, ref.size() - 1), ""); ++#else ++ EXPECT_EQ(MP_BADARG, mp_to_fixlen_octets(&a, buf, ref.size() - 1)); ++#endif ++ ASSERT_EQ(MP_OKAY, mp_to_fixlen_octets(&a, buf, ref.size())); ++ ASSERT_EQ(0, memcmp(buf, ref.data(), ref.size())); ++ ++ mp_clear(&a); ++ } ++} ++ + } // nss_test +Index: nss-3.28.4/nss/lib/freebl/mpi/mpi.c +=================================================================== +--- nss-3.28.4.orig/nss/lib/freebl/mpi/mpi.c 2018-12-14 09:57:04.005108161 -0500 ++++ nss-3.28.4/nss/lib/freebl/mpi/mpi.c 2018-12-14 09:57:04.005108161 -0500 +@@ -4799,38 +4799,61 @@ mp_to_signed_octets(const mp_int *mp, un + /* }}} */ + + /* {{{ mp_to_fixlen_octets(mp, str) */ +-/* output a buffer of big endian octets exactly as long as requested. */ ++/* output a buffer of big endian octets exactly as long as requested. ++ constant time on the value of mp. */ + mp_err + mp_to_fixlen_octets(const mp_int *mp, unsigned char *str, mp_size length) + { +- int ix, pos = 0; ++ int ix, jx; + unsigned int bytes; + +- ARGCHK(mp != NULL && str != NULL && !SIGN(mp), MP_BADARG); +- +- bytes = mp_unsigned_octet_size(mp); +- ARGCHK(bytes <= length, MP_BADARG); ++ ARGCHK(mp != NULL, MP_BADARG); ++ ARGCHK(str != NULL, MP_BADARG); ++ ARGCHK(!SIGN(mp), MP_BADARG); ++ ARGCHK(length > 0, MP_BADARG); ++ ++ /* Constant time on the value of mp. Don't use mp_unsigned_octet_size. */ ++ bytes = USED(mp) * MP_DIGIT_SIZE; ++ ++ /* If the output is shorter than the native size of mp, then check that any ++ * bytes not written have zero values. This check isn't constant time on ++ * the assumption that timing-sensitive callers can guarantee that mp fits ++ * in the allocated space. */ ++ ix = USED(mp) - 1; ++ if (bytes > length) { ++ unsigned int zeros = bytes - length; ++ ++ while (zeros >= MP_DIGIT_SIZE) { ++ ARGCHK(DIGIT(mp, ix) == 0, MP_BADARG); ++ zeros -= MP_DIGIT_SIZE; ++ ix--; ++ } + +- /* place any needed leading zeros */ +- for (; length > bytes; --length) { +- *str++ = 0; ++ if (zeros > 0) { ++ mp_digit d = DIGIT(mp, ix); ++ mp_digit m = ~0ULL << ((MP_DIGIT_SIZE - zeros) * CHAR_BIT); ++ ARGCHK((d & m) == 0, MP_BADARG); ++ for (jx = MP_DIGIT_SIZE - zeros - 1; jx >= 0; jx--) { ++ *str++ = d >> (jx * CHAR_BIT); ++ } ++ ix--; ++ } ++ } else if (bytes < length) { ++ /* Place any needed leading zeros. */ ++ unsigned int zeros = length - bytes; ++ memset(str, 0, zeros); ++ str += zeros; + } + +- /* Iterate over each digit... */ +- for (ix = USED(mp) - 1; ix >= 0; ix--) { ++ /* Iterate over each whole digit... */ ++ for (; ix >= 0; ix--) { + mp_digit d = DIGIT(mp, ix); +- int jx; + + /* Unpack digit bytes, high order first */ +- for (jx = sizeof(mp_digit) - 1; jx >= 0; jx--) { +- unsigned char x = (unsigned char)(d >> (jx * CHAR_BIT)); +- if (!pos && !x) /* suppress leading zeros */ +- continue; +- str[pos++] = x; ++ for (jx = MP_DIGIT_SIZE - 1; jx >= 0; jx--) { ++ *str++ = d >> (jx * CHAR_BIT); + } + } +- if (!pos) +- str[pos++] = 0; + return MP_OKAY; + } /* end mp_to_fixlen_octets() */ + /* }}} */ +Index: nss-3.28.4/nss/lib/freebl/mpi/mpi.h +=================================================================== +--- nss-3.28.4.orig/nss/lib/freebl/mpi/mpi.h 2018-12-14 09:57:04.005108161 -0500 ++++ nss-3.28.4/nss/lib/freebl/mpi/mpi.h 2018-12-14 09:57:04.005108161 -0500 +@@ -128,7 +128,8 @@ typedef int mp_sword; + #define MP_WORD_MAX UINT_MAX + #endif + +-#define MP_DIGIT_BIT (CHAR_BIT * sizeof(mp_digit)) ++#define MP_DIGIT_SIZE sizeof(mp_digit) ++#define MP_DIGIT_BIT (CHAR_BIT * MP_DIGIT_SIZE) + #define MP_WORD_BIT (CHAR_BIT * sizeof(mp_word)) + #define MP_RADIX (1 + (mp_word)MP_DIGIT_MAX) + diff -Nru nss-3.28.4/debian/patches/series nss-3.28.4/debian/patches/series --- nss-3.28.4/debian/patches/series 2017-09-29 12:54:07.000000000 +0000 +++ nss-3.28.4/debian/patches/series 2018-12-14 14:56:57.000000000 +0000 @@ -4,3 +4,8 @@ 85_security_load.patch CVE-2017-7502.patch CVE-2017-7805.patch +CVE-2018-0495.patch +CVE-2018-12384-1.patch +CVE-2018-12384-2.patch +CVE-2018-12404-1.patch +CVE-2018-12404-3.patch