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