Bug#862958: NMU for nss fixing CVE-2017-5461, CVE-2017-5462 and CVE-2017-7502
Salvatore Bonaccorso
carnil at debian.org
Fri Jun 2 16:08:25 UTC 2017
Control: tags 862958 + patch
Control: tags 863839 + patch
Hi
prepared a NMU for src:nss fixing CVE-2017-5461, CVE-2017-5462 and
CVE-2017-7502. But I still want to double check the patches with the
ones done by Moritz Muehlenhoff in the last DSA. will afterwards
upload to a delayed queue to make it in time for stretch if that's
fine with you.
Regards,
Salvatore
-------------- next part --------------
diff -Nru nss-3.26.2/debian/changelog nss-3.26.2/debian/changelog
--- nss-3.26.2/debian/changelog 2016-10-30 00:20:34.000000000 +0200
+++ nss-3.26.2/debian/changelog 2017-06-01 06:57:51.000000000 +0200
@@ -1,3 +1,13 @@
+nss (2:3.26.2-1.1) unstable; urgency=medium
+
+ * Non-maintainer upload.
+ * CVE-2017-5461: Out-of-bounds write in Base64 encoding (Closes: #862958)
+ * CVE-2017-5462: DRBG flaw (Closes: #862958)
+ * CVE-2017-7502: Null pointer dereference when handling empty SSLv2 messages
+ (Closes: #863839)
+
+ -- Salvatore Bonaccorso <carnil at debian.org> Thu, 01 Jun 2017 06:57:51 +0200
+
nss (2:3.26.2-1) unstable; urgency=medium
* New upstream release.
diff -Nru nss-3.26.2/debian/patches/CVE-2017-5461.patch nss-3.26.2/debian/patches/CVE-2017-5461.patch
--- nss-3.26.2/debian/patches/CVE-2017-5461.patch 1970-01-01 01:00:00.000000000 +0100
+++ nss-3.26.2/debian/patches/CVE-2017-5461.patch 2017-06-01 06:57:51.000000000 +0200
@@ -0,0 +1,183 @@
+
+# HG changeset patch
+# User Franziskus Kiefer <franziskuskiefer at gmail.com>
+# Date 1489748381 -3600
+# Node ID 77a5bb81dbaac5b03266a64ff981c156b61c8931
+# Parent da15c12097edbe876620ed5da8378ee3269caea8
+Bug 1344380 - gtests for b64 bug and some fixes, r=ttaubert
+
+Differential Revision: https://nss-review.dev.mozaws.net/D256#inline-2146
+
+--- a/nss/external_tests/util_gtest/manifest.mn
++++ b/nss/external_tests/util_gtest/manifest.mn
+@@ -8,6 +8,7 @@ MODULE = nss
+
+ CPPSRCS = \
+ util_utf8_unittest.cc \
++ util_b64_unittest.cc \
+ $(NULL)
+
+ INCLUDES += \
+--- /dev/null
++++ b/nss/external_tests/util_gtest/util_b64_unittest.cc
+@@ -0,0 +1,79 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
++/* vim: set ts=2 et sw=2 tw=80: */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
++ * You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#include <climits>
++#include <memory>
++#include "nssb64.h"
++
++#include "gtest/gtest.h"
++#include "scoped_ptrs.h"
++
++namespace nss_test {
++
++class B64EncodeDecodeTest : public ::testing::Test {
++ public:
++ void TestDecodeStr(const std::string &str) {
++ ScopedSECItem tmp(
++ NSSBase64_DecodeBuffer(nullptr, nullptr, str.c_str(), str.size()));
++ ASSERT_TRUE(tmp);
++ char *out = NSSBase64_EncodeItem(nullptr, nullptr, 0, tmp.get());
++ ASSERT_TRUE(out);
++ ASSERT_EQ(std::string(out), str);
++ PORT_Free(out);
++ }
++ bool TestEncodeItem(SECItem *item) {
++ bool rv = true;
++ char *out = NSSBase64_EncodeItem(nullptr, nullptr, 0, item);
++ rv = !!out;
++ if (out) {
++ ScopedSECItem tmp(
++ NSSBase64_DecodeBuffer(nullptr, nullptr, out, strlen(out)));
++ EXPECT_TRUE(tmp);
++ EXPECT_EQ(SECEqual, SECITEM_CompareItem(item, tmp.get()));
++ PORT_Free(out);
++ }
++ return rv;
++ }
++ bool TestFakeDecode(size_t str_len) {
++ std::string str(str_len, 'A');
++ ScopedSECItem tmp(
++ NSSBase64_DecodeBuffer(nullptr, nullptr, str.c_str(), str.size()));
++ return !!tmp;
++ }
++ bool TestFakeEncode(size_t len) {
++ std::vector<uint8_t> data(len, 0x30);
++ SECItem tmp = {siBuffer, data.data(),
++ static_cast<unsigned int>(data.size())};
++ return TestEncodeItem(&tmp);
++ }
++
++ protected:
++};
++
++TEST_F(B64EncodeDecodeTest, DecEncTest) { TestDecodeStr("VGhpcyBpcyBOU1Mh"); }
++
++TEST_F(B64EncodeDecodeTest, EncDecTest) {
++ uint8_t data[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
++ SECItem tmp = {siBuffer, data, sizeof(data)};
++ TestEncodeItem(&tmp);
++}
++
++TEST_F(B64EncodeDecodeTest, FakeDecTest) { EXPECT_TRUE(TestFakeDecode(100)); }
++
++TEST_F(B64EncodeDecodeTest, FakeEncDecTest) {
++ EXPECT_TRUE(TestFakeEncode(100));
++}
++
++// These takes a while ...
++TEST_F(B64EncodeDecodeTest, LongFakeDecTest1) {
++ EXPECT_TRUE(TestFakeDecode(0x66666666));
++}
++TEST_F(B64EncodeDecodeTest, LongFakeEncDecTest1) { TestFakeEncode(0x3fffffff); }
++TEST_F(B64EncodeDecodeTest, LongFakeEncDecTest2) {
++ EXPECT_FALSE(TestFakeEncode(0x40000000));
++}
++
++} // namespace nss_test
+--- a/nss/lib/util/nssb64d.c
++++ b/nss/lib/util/nssb64d.c
+@@ -373,7 +373,7 @@ pl_base64_decode_flush (PLBase64Decoder
+ static PRUint32
+ PL_Base64MaxDecodedLength (PRUint32 size)
+ {
+- return ((size * 3) / 4);
++ return size * 0.75;
+ }
+
+
+--- a/nss/lib/util/nssb64e.c
++++ b/nss/lib/util/nssb64e.c
+@@ -284,21 +284,29 @@ static PRUint32
+ PL_Base64MaxEncodedLength (PRUint32 size, PRUint32 line_length)
+ {
+ PRUint32 tokens, tokens_per_line, full_lines, line_break_chars, remainder;
++ /* This is the maximum length we support. */
++ if (size > 0x3fffffff) {
++ return 0;
++ }
+
+ tokens = (size + 2) / 3;
+
+- if (line_length == 0)
+- return tokens * 4;
++ if (line_length == 0) {
++ return tokens * 4;
++ }
+
+- if (line_length < 4) /* too small! */
+- line_length = 4;
++
++ if (line_length < 4) { /* too small! */
++ line_length = 4;
++ }
+
+ tokens_per_line = line_length / 4;
+ full_lines = tokens / tokens_per_line;
+ remainder = (tokens - (full_lines * tokens_per_line)) * 4;
+ line_break_chars = full_lines * 2;
+- if (remainder == 0)
+- line_break_chars -= 2;
++ if (remainder == 0) {
++ line_break_chars -= 2;
++ }
+
+ return (full_lines * tokens_per_line * 4) + line_break_chars + remainder;
+ }
+@@ -454,13 +462,18 @@ PL_Base64EncodeBuffer (const unsigned ch
+ PRStatus status;
+
+ PR_ASSERT(srclen > 0);
+- if (srclen == 0)
+- return dest;
++ if (srclen == 0) {
++ return dest;
++ }
+
+ /*
+ * How much space could we possibly need for encoding this input?
+ */
+ need_length = PL_Base64MaxEncodedLength (srclen, line_length);
++ if (need_length == 0) {
++ PORT_SetError(SEC_ERROR_INVALID_ARGS);
++ return NULL;
++ }
+
+ /*
+ * Make sure we have at least that much, if output buffer provided.
+@@ -643,6 +656,10 @@ NSSBase64_EncodeItem (PLArenaPool *arena
+ }
+
+ max_out_len = PL_Base64MaxEncodedLength (inItem->len, 64);
++ if (max_out_len == 0) {
++ PORT_SetError(SEC_ERROR_INVALID_ARGS);
++ return NULL;
++ }
+
+ if (arenaOpt != NULL)
+ mark = PORT_ArenaMark (arenaOpt);
diff -Nru nss-3.26.2/debian/patches/CVE-2017-5462.patch nss-3.26.2/debian/patches/CVE-2017-5462.patch
--- nss-3.26.2/debian/patches/CVE-2017-5462.patch 1970-01-01 01:00:00.000000000 +0100
+++ nss-3.26.2/debian/patches/CVE-2017-5462.patch 2017-06-01 06:57:51.000000000 +0200
@@ -0,0 +1,94 @@
+
+# HG changeset patch
+# User Franziskus Kiefer <franziskuskiefer at gmail.com>
+# Date 1491394302 -7200
+# Node ID 7248d38b76e569d2f89b20598fcdca595c3a2e6a
+# Parent 6eb39ead39e0b3f6269fd9660a4426187f5302a8
+Bug 1345089 - add prng kat tests, r=ttaubert
+
+--- a/nss/lib/freebl/blapi.h
++++ b/nss/lib/freebl/blapi.h
+@@ -1473,6 +1473,12 @@ FIPS186Change_ReduceModQForDSA(const uns
+ const unsigned char *q,
+ unsigned char *xj);
+
++/* To allow NIST KAT tests */
++extern SECStatus
++PRNGTEST_Instantiate_Kat(const PRUint8 *entropy, unsigned int entropy_len,
++ const PRUint8 *nonce, unsigned int nonce_len,
++ const PRUint8 *personal_string, unsigned int ps_len);
++
+ /*
+ * The following functions are for FIPS poweron self test and FIPS algorithm
+ * testing.
+--- a/nss/lib/freebl/drbg.c
++++ b/nss/lib/freebl/drbg.c
+@@ -96,7 +96,8 @@ struct RNGContextStr {
+ * RNG_RandomUpdate. */
+ PRUint8 additionalDataCache[PRNG_ADDITONAL_DATA_CACHE_SIZE];
+ PRUint32 additionalAvail;
+- PRBool isValid; /* false if RNG reaches an invalid state */
++ PRBool isValid; /* false if RNG reaches an invalid state */
++ PRBool isKatTest; /* true if running NIST PRNG KAT tests */
+ };
+
+ typedef struct RNGContextStr RNGContext;
+@@ -149,7 +150,7 @@ prng_Hash_df(PRUint8 *requested_bytes, u
+
+
+ /*
+- * Hash_DRBG Instantiate NIST SP 800-80 10.1.1.2
++ * Hash_DRBG Instantiate NIST SP 800-90 10.1.1.2
+ *
+ * NOTE: bytes & len are entropy || nonce || personalization_string. In
+ * normal operation, NSS calculates them all together in a single call.
+@@ -157,9 +158,11 @@ prng_Hash_df(PRUint8 *requested_bytes, u
+ static SECStatus
+ prng_instantiate(RNGContext *rng, const PRUint8 *bytes, unsigned int len)
+ {
+- if (len < PRNG_SEEDLEN) {
+- /* if the seedlen is to small, it's probably because we failed to get
+- * enough random data */
++ if (!rng->isKatTest && len < PRNG_SEEDLEN) {
++ /* If the seedlen is too small, it's probably because we failed to get
++ * enough random data.
++ * This is stricter than NIST SP800-90A requires. Don't enforce it for
++ * tests. */
+ PORT_SetError(SEC_ERROR_NEED_RANDOM);
+ return SECFailure;
+ }
+@@ -272,7 +275,7 @@ prng_reseed_test(RNGContext *rng, const
+
+ #define PRNG_ADD_BITS_AND_CARRY(dest, dest_len, add, len, carry) \
+ PRNG_ADD_BITS(dest, dest_len, add, len, carry) \
+- PRNG_ADD_CARRY_ONLY(dest, dest_len - len, carry)
++ PRNG_ADD_CARRY_ONLY(dest, dest_len - len - 1, carry)
+
+ /*
+ * This function expands the internal state of the prng to fulfill any number
+@@ -440,6 +443,7 @@ static PRStatus rng_init(void)
+ }
+ /* the RNG is in a valid state */
+ globalrng->isValid = PR_TRUE;
++ globalrng->isKatTest = PR_FALSE;
+
+ /* fetch one random value so that we can populate rng->oldV for our
+ * continous random number test. */
+@@ -684,6 +688,17 @@ RNG_RNGShutdown(void)
+ * entropy we may have previously collected. */
+ RNGContext testContext;
+
++SECStatus
++PRNGTEST_Instantiate_Kat(const PRUint8 *entropy, unsigned int entropy_len,
++ const PRUint8 *nonce, unsigned int nonce_len,
++ const PRUint8 *personal_string, unsigned int ps_len)
++{
++ testContext.isKatTest = PR_TRUE;
++ return PRNGTEST_Instantiate(entropy, entropy_len,
++ nonce, nonce_len,
++ personal_string, ps_len);
++}
++
+ /*
+ * Test vector API. Use NIST SP 800-90 general interface so one of the
+ * other NIST SP 800-90 algorithms may be used in the future.
diff -Nru nss-3.26.2/debian/patches/CVE-2017-7502.patch nss-3.26.2/debian/patches/CVE-2017-7502.patch
--- nss-3.26.2/debian/patches/CVE-2017-7502.patch 1970-01-01 01:00:00.000000000 +0100
+++ nss-3.26.2/debian/patches/CVE-2017-7502.patch 2017-06-01 06:57:51.000000000 +0200
@@ -0,0 +1,108 @@
+
+# HG changeset patch
+# User Tim Taubert <ttaubert at mozilla.com>
+# Date 1483435195 -3600
+# Node ID 55ea60effd0d7c427f9b57a0bd43fb0fcbdae0e9
+# Parent 316fcf7c1ca35a1d1bb8e12605cca6f9af933bde
+Bug 1328122 - Fix various ssl3_GatherData() issues r=mt,franziskus
+
+Differential Revision: https://nss-review.dev.mozaws.net/D135
+
+--- a/nss/lib/ssl/ssl3gthr.c
++++ b/nss/lib/ssl/ssl3gthr.c
+@@ -32,6 +32,7 @@ ssl3_InitGather(sslGather *gs)
+ gs->readOffset = 0;
+ gs->dtlsPacketOffset = 0;
+ gs->dtlsPacket.len = 0;
++ gs->rejectV2Records = PR_FALSE;
+ status = sslBuffer_Grow(&gs->buf, 4096);
+ return status;
+ }
+@@ -147,8 +148,11 @@ ssl3_GatherData(sslSocket *ss, sslGather
+ switch (gs->state) {
+ case GS_HEADER:
+ /* Check for SSLv2 handshakes. Always assume SSLv3 on clients,
+- * support SSLv2 handshakes only when ssl2gs != NULL. */
+- if (!ssl2gs || ssl3_isLikelyV3Hello(gs->hdr)) {
++ * support SSLv2 handshakes only when ssl2gs != NULL.
++ * Always assume v3 after we received the first record. */
++ if (!ssl2gs ||
++ ss->gs.rejectV2Records ||
++ ssl3_isLikelyV3Hello(gs->hdr)) {
+ /* Should have an SSLv3 record header in gs->hdr. Extract
+ * the length of the following encrypted data, and then
+ * read in the rest of the SSL3 record into gs->inbuf. */
+@@ -171,7 +175,7 @@ ssl3_GatherData(sslSocket *ss, sslGather
+ /* This is the max length for an encrypted SSLv3+ fragment. */
+ if (!v2HdrLength &&
+ gs->remainder > (MAX_FRAGMENT_LENGTH + 2048)) {
+- SSL3_SendAlert(ss, alert_fatal, unexpected_message);
++ SSL3_SendAlert(ss, alert_fatal, record_overflow);
+ gs->state = GS_INIT;
+ PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
+ return SECFailure;
+@@ -193,13 +197,28 @@ ssl3_GatherData(sslSocket *ss, sslGather
+ * many into the gs->hdr[] buffer. Copy them over into inbuf so
+ * that we can properly process the hello record later. */
+ if (v2HdrLength) {
++ /* Reject v2 records that don't even carry enough data to
++ * resemble a valid ClientHello header. */
++ if (gs->remainder < SSL_HL_CLIENT_HELLO_HBYTES) {
++ SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
++ PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
++ return SECFailure;
++ }
++
++ PORT_Assert(lbp);
+ gs->inbuf.len = 5 - v2HdrLength;
+ PORT_Memcpy(lbp, gs->hdr + v2HdrLength, gs->inbuf.len);
+ gs->remainder -= gs->inbuf.len;
+ lbp += gs->inbuf.len;
+ }
+
+- break; /* End this case. Continue around the loop. */
++ if (gs->remainder > 0) {
++ break; /* End this case. Continue around the loop. */
++ }
++
++ /* FALL THROUGH if (gs->remainder == 0) as we just received
++ * an empty record and there's really no point in calling
++ * ssl_DefRecv() with buf=NULL and len=0. */
+
+ case GS_DATA:
+ /*
+@@ -207,6 +226,10 @@ ssl3_GatherData(sslSocket *ss, sslGather
+ */
+ SSL_TRC(10, ("%d: SSL[%d]: got record of %d bytes",
+ SSL_GETPID(), ss->fd, gs->inbuf.len));
++
++ /* reject any v2 records from now on */
++ ss->gs.rejectV2Records = PR_TRUE;
++
+ gs->state = GS_INIT;
+ return 1;
+ }
+--- a/nss/lib/ssl/ssldef.c
++++ b/nss/lib/ssl/ssldef.c
+@@ -66,6 +66,8 @@ ssl_DefRecv(sslSocket *ss, unsigned char
+ PRFileDesc *lower = ss->fd->lower;
+ int rv;
+
++ PORT_Assert(buf && len > 0);
++
+ rv = lower->methods->recv(lower, (void *)buf, len, flags, ss->rTimeout);
+ if (rv < 0) {
+ DEFINE_ERROR
+--- a/nss/lib/ssl/sslimpl.h
++++ b/nss/lib/ssl/sslimpl.h
+@@ -451,6 +451,10 @@ struct sslGatherStr {
+
+ /* the start of the buffered DTLS record in dtlsPacket */
+ unsigned int dtlsPacketOffset;
++
++ /* tracks whether we've seen a v3-type record before and must reject
++ * any further v2-type records. */
++ PRBool rejectV2Records;
+ };
+
+ /* sslGather.state */
diff -Nru nss-3.26.2/debian/patches/series nss-3.26.2/debian/patches/series
--- nss-3.26.2/debian/patches/series 2016-03-09 01:48:28.000000000 +0100
+++ nss-3.26.2/debian/patches/series 2017-06-01 06:57:51.000000000 +0200
@@ -3,3 +3,6 @@
80_security_tools.patch
85_security_load.patch
38_hppa.patch
+CVE-2017-5461.patch
+CVE-2017-5462.patch
+CVE-2017-7502.patch
More information about the pkg-mozilla-maintainers
mailing list