Bug 1445731 - land NSS c1a4035420c3 UPGRADE_NSS_RELEASE, r=me
authorTim Taubert <ttaubert@mozilla.com>
Mon, 16 Apr 2018 10:09:12 +0200
changeset 413830 c6757ad801fedaff8606b6ae34a276ce08714ce8
parent 413827 ac685df07bfc81d80f81e40d7cac55cbf56d84c1
child 413831 3c1fdf8c83daf09d9bcf41ccd4c7bc0380f3d478
push id33852
push usershindli@mozilla.com
push dateMon, 16 Apr 2018 21:59:17 +0000
treeherdermozilla-central@0ceabd10aac2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs1445731
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1445731 - land NSS c1a4035420c3 UPGRADE_NSS_RELEASE, r=me
security/nss/TAG-INFO
security/nss/automation/taskcluster/graph/src/extend.js
security/nss/automation/taskcluster/graph/src/try_syntax.js
security/nss/coreconf/coreconf.dep
security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
security/nss/gtests/ssl_gtest/tls_agent.cc
security/nss/gtests/ssl_gtest/tls_agent.h
security/nss/gtests/ssl_gtest/tls_connect.cc
security/nss/gtests/ssl_gtest/tls_connect.h
security/nss/lib/pk11wrap/pk11merge.c
security/nss/lib/ssl/SSLerrs.h
security/nss/lib/ssl/ssl.h
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/ssl3ext.c
security/nss/lib/ssl/ssl3exthandle.c
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslsock.c
security/nss/lib/ssl/tls13con.c
security/nss/mach
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-2eefd697d661
+c1a4035420c3
--- a/security/nss/automation/taskcluster/graph/src/extend.js
+++ b/security/nss/automation/taskcluster/graph/src/extend.js
@@ -990,23 +990,23 @@ async function scheduleTools() {
     command: [
       "/bin/bash",
       "-c",
       "bin/checkout.sh && nss/automation/clang-format/run_clang_format.sh"
     ]
   }));
 
   queue.scheduleTask(merge(base, {
-    symbol: "scan-build-5.0",
-    name: "scan-build-5.0",
-    image: LINUX_IMAGE,
+    symbol: "scan-build",
+    name: "scan-build",
+    image: FUZZ_IMAGE,
     env: {
       USE_64: "1",
-      CC: "clang-5.0",
-      CCC: "clang++-5.0",
+      CC: "clang",
+      CCC: "clang++",
     },
     artifacts: {
       public: {
         expires: 24 * 7,
         type: "directory",
         path: "/home/worker/artifacts"
       }
     },
@@ -1087,10 +1087,22 @@ async function scheduleTools() {
     image: SAW_IMAGE,
     command: [
       "/bin/bash",
       "-c",
       "bin/checkout.sh && nss/automation/taskcluster/scripts/run_saw.sh poly1305"
     ]
   }));
 
+  queue.scheduleTask(merge(base, {
+    symbol: "Coverage",
+    name: "Coverage",
+    image: FUZZ_IMAGE,
+    features: ["allowPtrace"],
+    command: [
+      "/bin/bash",
+      "-c",
+      "bin/checkout.sh && nss/automation/taskcluster/scripts/gen_coverage_report.sh"
+    ]
+  }));
+
   return queue.submit();
 }
--- a/security/nss/automation/taskcluster/graph/src/try_syntax.js
+++ b/security/nss/automation/taskcluster/graph/src/try_syntax.js
@@ -46,17 +46,17 @@ function parseOptions(opts) {
   // If it's nonsense then don't run any tests.
   if (opts.unittests == "all") {
     unittests = allUnitTests;
   } else if (unittests.length == 0) {
     unittests = [];
   }
 
   // Parse tools.
-  let allTools = ["clang-format", "scan-build", "hacl", "saw", "abi"];
+  let allTools = ["clang-format", "scan-build", "hacl", "saw", "abi", "coverage"];
   let tools = intersect(opts.tools.split(/\s*,\s*/), allTools);
 
   // If the given value is "all" run all tools.
   // If it's nonsense then don't run any tools.
   if (opts.tools == "all") {
     tools = allTools;
   } else if (tools.length == 0) {
     tools = [];
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_0rtt_unittest.cc
@@ -340,18 +340,18 @@ TEST_P(TlsConnectTls13, TestTls13ZeroRtt
   }
   client_->CheckErrorCode(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
 }
 
 // Remove the old ALPN value and so the client will not offer early data.
 TEST_P(TlsConnectTls13, TestTls13ZeroRttAlpnChangeBoth) {
   EnableAlpn();
   SetupForZeroRtt();
-  static const uint8_t alpn[] = {0x01, 0x62};  // "b"
-  EnableAlpn(alpn, sizeof(alpn));
+  static const std::vector<uint8_t> alpn({0x01, 0x62});  // "b"
+  EnableAlpn(alpn);
   client_->Set0RttEnabled(true);
   server_->Set0RttEnabled(true);
   ExpectResumption(RESUME_TICKET);
   ZeroRttSendReceive(true, false, [this]() {
     client_->CheckAlpn(SSL_NEXT_PROTO_NO_SUPPORT);
     return false;
   });
   Handshake();
--- a/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
@@ -554,16 +554,77 @@ TEST_P(TlsConnectGenericPre13, ConnectEC
 }
 
 TEST_P(TlsConnectGenericPre13, ConnectECDHEmptyClientPoint) {
   MakeTlsFilter<ECCClientKEXFilter>(client_);
   ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
   server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH);
 }
 
+// Damage ECParams/ECPoint of a SKE.
+class ECCServerKEXDamager : public TlsHandshakeFilter {
+ public:
+  ECCServerKEXDamager(const std::shared_ptr<TlsAgent> &server, ECType ec_type,
+                      SSLNamedGroup named_curve)
+      : TlsHandshakeFilter(server, {kTlsHandshakeServerKeyExchange}),
+        ec_type_(ec_type),
+        named_curve_(named_curve) {}
+
+ protected:
+  virtual PacketFilter::Action FilterHandshake(const HandshakeHeader &header,
+                                               const DataBuffer &input,
+                                               DataBuffer *output) {
+    size_t offset = 0;
+    output->Allocate(5);
+    offset = output->Write(offset, ec_type_, 1);
+    offset = output->Write(offset, named_curve_, 2);
+    // Write a point with fmt != EC_POINT_FORM_UNCOMPRESSED.
+    offset = output->Write(offset, 1U, 1);
+    (void)output->Write(offset, 0x02, 1);  // EC_POINT_FORM_COMPRESSED_Y0
+    return CHANGE;
+  }
+
+ private:
+  ECType ec_type_;
+  SSLNamedGroup named_curve_;
+};
+
+TEST_P(TlsConnectGenericPre13, ConnectUnsupportedCurveType) {
+  EnsureTlsSetup();
+  client_->DisableAllCiphers();
+  client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
+
+  MakeTlsFilter<ECCServerKEXDamager>(server_, ec_type_explicitPrime,
+                                     ssl_grp_none);
+  ConnectExpectAlert(client_, kTlsAlertHandshakeFailure);
+  client_->CheckErrorCode(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+}
+
+TEST_P(TlsConnectGenericPre13, ConnectUnsupportedCurve) {
+  EnsureTlsSetup();
+  client_->DisableAllCiphers();
+  client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
+
+  MakeTlsFilter<ECCServerKEXDamager>(server_, ec_type_named,
+                                     ssl_grp_ffdhe_2048);
+  ConnectExpectAlert(client_, kTlsAlertHandshakeFailure);
+  client_->CheckErrorCode(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
+}
+
+TEST_P(TlsConnectGenericPre13, ConnectUnsupportedPointFormat) {
+  EnsureTlsSetup();
+  client_->DisableAllCiphers();
+  client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
+
+  MakeTlsFilter<ECCServerKEXDamager>(server_, ec_type_named,
+                                     ssl_grp_ec_secp256r1);
+  ConnectExpectAlert(client_, kTlsAlertHandshakeFailure);
+  client_->CheckErrorCode(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
+}
+
 INSTANTIATE_TEST_CASE_P(KeyExchangeTest, TlsKeyExchangeTest,
                         ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
                                            TlsConnectTestBase::kTlsV11Plus));
 
 #ifndef NSS_DISABLE_TLS_1_3
 INSTANTIATE_TEST_CASE_P(KeyExchangeTest, TlsKeyExchangeTest13,
                         ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
                                            TlsConnectTestBase::kTlsV13));
--- a/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
@@ -144,24 +144,72 @@ TEST_P(TlsConnectGenericPre13, ConnectFa
 }
 
 TEST_P(TlsConnectGeneric, ConnectAlpn) {
   EnableAlpn();
   Connect();
   CheckAlpn("a");
 }
 
+TEST_P(TlsConnectGeneric, ConnectAlpnPriorityA) {
+  // "alpn" "npn"
+  // alpn is the fallback here. npn has the highest priority and should be
+  // picked.
+  const std::vector<uint8_t> alpn = {0x04, 0x61, 0x6c, 0x70, 0x6e,
+                                     0x03, 0x6e, 0x70, 0x6e};
+  EnableAlpn(alpn);
+  Connect();
+  CheckAlpn("npn");
+}
+
+TEST_P(TlsConnectGeneric, ConnectAlpnPriorityB) {
+  // "alpn" "npn" "http"
+  // npn has the highest priority and should be picked.
+  const std::vector<uint8_t> alpn = {0x04, 0x61, 0x6c, 0x70, 0x6e, 0x03, 0x6e,
+                                     0x70, 0x6e, 0x04, 0x68, 0x74, 0x74, 0x70};
+  EnableAlpn(alpn);
+  Connect();
+  CheckAlpn("npn");
+}
+
 TEST_P(TlsConnectGeneric, ConnectAlpnClone) {
   EnsureModelSockets();
   client_model_->EnableAlpn(alpn_dummy_val_, sizeof(alpn_dummy_val_));
   server_model_->EnableAlpn(alpn_dummy_val_, sizeof(alpn_dummy_val_));
   Connect();
   CheckAlpn("a");
 }
 
+TEST_P(TlsConnectGeneric, ConnectAlpnWithCustomCallbackA) {
+  // "ab" "alpn"
+  const std::vector<uint8_t> client_alpn = {0x02, 0x61, 0x62, 0x04,
+                                            0x61, 0x6c, 0x70, 0x6e};
+  EnableAlpnWithCallback(client_alpn, "alpn");
+  Connect();
+  CheckAlpn("alpn");
+}
+
+TEST_P(TlsConnectGeneric, ConnectAlpnWithCustomCallbackB) {
+  // "ab" "alpn"
+  const std::vector<uint8_t> client_alpn = {0x02, 0x61, 0x62, 0x04,
+                                            0x61, 0x6c, 0x70, 0x6e};
+  EnableAlpnWithCallback(client_alpn, "ab");
+  Connect();
+  CheckAlpn("ab");
+}
+
+TEST_P(TlsConnectGeneric, ConnectAlpnWithCustomCallbackC) {
+  // "cd" "npn" "alpn"
+  const std::vector<uint8_t> client_alpn = {0x02, 0x63, 0x64, 0x03, 0x6e, 0x70,
+                                            0x6e, 0x04, 0x61, 0x6c, 0x70, 0x6e};
+  EnableAlpnWithCallback(client_alpn, "npn");
+  Connect();
+  CheckAlpn("npn");
+}
+
 TEST_P(TlsConnectDatagram, ConnectSrtp) {
   EnableSrtp();
   Connect();
   CheckSrtp();
   SendReceive();
 }
 
 TEST_P(TlsConnectGeneric, ConnectSendReceive) {
--- a/security/nss/gtests/ssl_gtest/tls_agent.cc
+++ b/security/nss/gtests/ssl_gtest/tls_agent.cc
@@ -594,32 +594,30 @@ void TlsAgent::EnableFalseStart() {
                             ssl_fd(), CanFalseStartCallback, this));
   SetOption(SSL_ENABLE_FALSE_START, PR_TRUE);
 }
 
 void TlsAgent::ExpectResumption() { expect_resumption_ = true; }
 
 void TlsAgent::EnableAlpn(const uint8_t* val, size_t len) {
   EXPECT_TRUE(EnsureTlsSetup());
-
-  SetOption(SSL_ENABLE_ALPN, PR_TRUE);
   EXPECT_EQ(SECSuccess, SSL_SetNextProtoNego(ssl_fd(), val, len));
 }
 
 void TlsAgent::CheckAlpn(SSLNextProtoState expected_state,
                          const std::string& expected) const {
-  SSLNextProtoState npn_state;
+  SSLNextProtoState alpn_state;
   char chosen[10];
   unsigned int chosen_len;
-  SECStatus rv = SSL_GetNextProto(ssl_fd(), &npn_state,
+  SECStatus rv = SSL_GetNextProto(ssl_fd(), &alpn_state,
                                   reinterpret_cast<unsigned char*>(chosen),
                                   &chosen_len, sizeof(chosen));
   EXPECT_EQ(SECSuccess, rv);
-  EXPECT_EQ(expected_state, npn_state);
-  if (npn_state == SSL_NEXT_PROTO_NO_SUPPORT) {
+  EXPECT_EQ(expected_state, alpn_state);
+  if (alpn_state == SSL_NEXT_PROTO_NO_SUPPORT) {
     EXPECT_EQ("", expected);
   } else {
     EXPECT_NE("", expected);
     EXPECT_EQ(expected, std::string(chosen, chosen_len));
   }
 }
 
 void TlsAgent::EnableSrtp() {
--- a/security/nss/gtests/ssl_gtest/tls_agent.h
+++ b/security/nss/gtests/ssl_gtest/tls_agent.h
@@ -263,16 +263,18 @@ class TlsAgent : public PollTarget {
 
   void SetSniCallback(SniCallbackFunction sni_callback) {
     sni_callback_ = sni_callback;
   }
 
   void ExpectReceiveAlert(uint8_t alert, uint8_t level = 0);
   void ExpectSendAlert(uint8_t alert, uint8_t level = 0);
 
+  std::string alpn_value_to_use_ = "";
+
  private:
   const static char* states[];
 
   void SetState(State state);
   void ValidateCipherSpecs();
 
   // Dummy auth certificate hook.
   static SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd,
--- a/security/nss/gtests/ssl_gtest/tls_connect.cc
+++ b/security/nss/gtests/ssl_gtest/tls_connect.cc
@@ -566,24 +566,67 @@ void TlsConnectTestBase::CheckResumption
                 session_ids_[session_ids_.size() - 2]);
     } else {
       // TLS 1.3 only uses tickets.
       EXPECT_TRUE(expected & RESUME_TICKET);
     }
   }
 }
 
+static SECStatus NextProtoCallbackServer(void* arg, PRFileDesc* fd,
+                                         const unsigned char* protos,
+                                         unsigned int protos_len,
+                                         unsigned char* protoOut,
+                                         unsigned int* protoOutLen,
+                                         unsigned int protoMaxLen) {
+  EXPECT_EQ(protoMaxLen, 255U);
+  TlsAgent* agent = reinterpret_cast<TlsAgent*>(arg);
+  // Check that agent->alpn_value_to_use_ is in protos.
+  if (protos_len < 1) {
+    return SECFailure;
+  }
+  for (size_t i = 0; i < protos_len;) {
+    size_t l = protos[i];
+    EXPECT_LT(i + l, protos_len);
+    if (i + l >= protos_len) {
+      return SECFailure;
+    }
+    std::string protos_s(reinterpret_cast<const char*>(protos + i + 1), l);
+    if (protos_s == agent->alpn_value_to_use_) {
+      size_t s_len = agent->alpn_value_to_use_.size();
+      EXPECT_LE(s_len, 255U);
+      memcpy(protoOut, &agent->alpn_value_to_use_[0], s_len);
+      *protoOutLen = s_len;
+      return SECSuccess;
+    }
+    i += l + 1;
+  }
+  return SECFailure;
+}
+
 void TlsConnectTestBase::EnableAlpn() {
   client_->EnableAlpn(alpn_dummy_val_, sizeof(alpn_dummy_val_));
   server_->EnableAlpn(alpn_dummy_val_, sizeof(alpn_dummy_val_));
 }
 
-void TlsConnectTestBase::EnableAlpn(const uint8_t* val, size_t len) {
-  client_->EnableAlpn(val, len);
-  server_->EnableAlpn(val, len);
+void TlsConnectTestBase::EnableAlpnWithCallback(
+    const std::vector<uint8_t>& client_vals, std::string server_choice) {
+  EnsureTlsSetup();
+  server_->alpn_value_to_use_ = server_choice;
+  EXPECT_EQ(SECSuccess,
+            SSL_SetNextProtoNego(client_->ssl_fd(), client_vals.data(),
+                                 client_vals.size()));
+  SECStatus rv = SSL_SetNextProtoCallback(
+      server_->ssl_fd(), NextProtoCallbackServer, server_.get());
+  EXPECT_EQ(SECSuccess, rv);
+}
+
+void TlsConnectTestBase::EnableAlpn(const std::vector<uint8_t>& vals) {
+  client_->EnableAlpn(vals.data(), vals.size());
+  server_->EnableAlpn(vals.data(), vals.size());
 }
 
 void TlsConnectTestBase::EnsureModelSockets() {
   // Make sure models agents are available.
   if (!client_model_) {
     ASSERT_EQ(server_model_, nullptr);
     client_model_.reset(
         new TlsAgent(TlsAgent::kClient, TlsAgent::CLIENT, variant_));
--- a/security/nss/gtests/ssl_gtest/tls_connect.h
+++ b/security/nss/gtests/ssl_gtest/tls_connect.h
@@ -105,17 +105,19 @@ class TlsConnectTestBase : public ::test
   void EnableOnlyStaticRsaCiphers();
   void EnableOnlyDheCiphers();
   void EnableSomeEcdhCiphers();
   void EnableExtendedMasterSecret();
   void ConfigureSelfEncrypt();
   void ConfigureSessionCache(SessionResumptionMode client,
                              SessionResumptionMode server);
   void EnableAlpn();
-  void EnableAlpn(const uint8_t* val, size_t len);
+  void EnableAlpnWithCallback(const std::vector<uint8_t>& client,
+                              std::string server_choice);
+  void EnableAlpn(const std::vector<uint8_t>& vals);
   void EnsureModelSockets();
   void CheckAlpn(const std::string& val);
   void EnableSrtp();
   void CheckSrtp() const;
   void SendReceive(size_t total = 50);
   void SetupForZeroRtt();
   void SetupForResume();
   void ZeroRttSendReceive(
--- a/security/nss/lib/pk11wrap/pk11merge.c
+++ b/security/nss/lib/pk11wrap/pk11merge.c
@@ -69,43 +69,44 @@ pk11_copyAttributes(PLArenaPool *arena,
     /* if we have missing attributes, just skip them and create the object */
     if (crv == CKR_ATTRIBUTE_TYPE_INVALID) {
         CK_ULONG i, j;
         newTemplate = PORT_NewArray(CK_ATTRIBUTE, copyTemplateCount);
         if (!newTemplate) {
             return SECFailure;
         }
         /* remove the unknown attributes. If we don't have enough attributes
-	 * PK11_CreateNewObject() will fail */
+         * PK11_CreateNewObject() will fail */
         for (i = 0, j = 0; i < copyTemplateCount; i++) {
             if (copyTemplate[i].ulValueLen != -1) {
                 newTemplate[j] = copyTemplate[i];
                 j++;
             }
         }
         copyTemplate = newTemplate;
         copyTemplateCount = j;
         crv = PK11_GetAttributes(arena, sourceSlot, sourceID,
                                  copyTemplate, copyTemplateCount);
     }
     if (crv != CKR_OK) {
         PORT_SetError(PK11_MapError(crv));
+        PORT_Free(newTemplate);
         return SECFailure;
     }
     if (targetID == CK_INVALID_HANDLE) {
         /* we need to create the object */
         rv = PK11_CreateNewObject(targetSlot, CK_INVALID_SESSION,
                                   copyTemplate, copyTemplateCount, PR_TRUE, &targetID);
     } else {
         /* update the existing object with the new attributes */
         rv = pk11_setAttributes(targetSlot, targetID,
                                 copyTemplate, copyTemplateCount);
     }
     if (newTemplate) {
-        free(newTemplate);
+        PORT_Free(newTemplate);
     }
     return rv;
 }
 
 /*
  * look for a matching object across tokens.
  */
 static SECStatus
--- a/security/nss/lib/ssl/SSLerrs.h
+++ b/security/nss/lib/ssl/SSLerrs.h
@@ -369,17 +369,17 @@ ER3(SSL_ERROR_UNSAFE_NEGOTIATION, (SSL_E
 
 ER3(SSL_ERROR_RX_UNEXPECTED_UNCOMPRESSED_RECORD, (SSL_ERROR_BASE + 114),
     "SSL received an unexpected uncompressed record.")
 
 ER3(SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY, (SSL_ERROR_BASE + 115),
     "SSL received a weak ephemeral Diffie-Hellman key in Server Key Exchange handshake message.")
 
 ER3(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID, (SSL_ERROR_BASE + 116),
-    "SSL received invalid NPN extension data.")
+    "SSL received invalid ALPN extension data.")
 
 ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2, (SSL_ERROR_BASE + 117),
     "SSL feature not supported for SSL 2.0 connections.")
 
 ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS, (SSL_ERROR_BASE + 118),
     "SSL feature not supported for servers.")
 
 ER3(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_CLIENTS, (SSL_ERROR_BASE + 119),
--- a/security/nss/lib/ssl/ssl.h
+++ b/security/nss/lib/ssl/ssl.h
@@ -153,33 +153,28 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRF
  * application_data records. Also, we only split application_data records and
  * not other types of records, because some implementations will not accept
  * fragmented records of some other types (e.g. some versions of NSS do not
  * accept fragmented alerts).
  */
 #define SSL_CBC_RANDOM_IV 23
 #define SSL_ENABLE_OCSP_STAPLING 24 /* Request OCSP stapling (client) */
 
-/* SSL_ENABLE_NPN controls whether the NPN extension is enabled for the initial
- * handshake when application layer protocol negotiation is used.
- * SSL_SetNextProtoCallback or SSL_SetNextProtoNego must be used to control the
- * application layer protocol negotiation; otherwise, the NPN extension will
- * not be negotiated. SSL_ENABLE_NPN is currently enabled by default but this
- * may change in future versions.
- */
+/* SSL_ENABLE_NPN is defunct and defaults to false.
+ * Using this option will not have any effect but won't produce an error. */
 #define SSL_ENABLE_NPN 25
 
 /* SSL_ENABLE_ALPN controls whether the ALPN extension is enabled for the
  * initial handshake when application layer protocol negotiation is used.
- * SSL_SetNextProtoNego (not SSL_SetNextProtoCallback) must be used to control
- * the application layer protocol negotiation; otherwise, the ALPN extension
- * will not be negotiated. ALPN is not negotiated for renegotiation handshakes,
- * even though the ALPN specification defines a way to use ALPN during
- * renegotiations. SSL_ENABLE_ALPN is currently disabled by default, but this
- * may change in future versions.
+ * SSL_SetNextProtoNego or SSL_SetNextProtoCallback can be used to control
+ * the application layer protocol negotiation;
+ * ALPN is not negotiated for renegotiation handshakes, even though the ALPN
+ * specification defines a way to use ALPN during renegotiations.
+ * SSL_ENABLE_ALPN is currently enabled by default, but this may change in
+ * future versions.
  */
 #define SSL_ENABLE_ALPN 26
 
 /* SSL_REUSE_SERVER_ECDHE_KEY controls whether the ECDHE server key is
  * reused for multiple handshakes or generated each time.
  * SSL_REUSE_SERVER_ECDHE_KEY is currently enabled by default.
  * This socket option is for ECDHE, only. It is unrelated to DHE.
  */
@@ -278,56 +273,53 @@ SSL_IMPORT SECStatus SSL_EnableDefault(i
  * options will explain if other values are permitted.
  */
 SSL_IMPORT SECStatus SSL_OptionSet(PRFileDesc *fd, PRInt32 option, PRIntn val);
 SSL_IMPORT SECStatus SSL_OptionGet(PRFileDesc *fd, PRInt32 option, PRIntn *val);
 SSL_IMPORT SECStatus SSL_OptionSetDefault(PRInt32 option, PRIntn val);
 SSL_IMPORT SECStatus SSL_OptionGetDefault(PRInt32 option, PRIntn *val);
 SSL_IMPORT SECStatus SSL_CertDBHandleSet(PRFileDesc *fd, CERTCertDBHandle *dbHandle);
 
-/* SSLNextProtoCallback is called during the handshake for the client, when a
- * Next Protocol Negotiation (NPN) extension has been received from the server.
- * |protos| and |protosLen| define a buffer which contains the server's
- * advertisement. This data is guaranteed to be well formed per the NPN spec.
+/* SSLNextProtoCallback is called during the handshake for the server, when an
+ * Application-Layer Protocol Negotiation (ALPN) extension has been received
+ * from the client. |protos| and |protosLen| define a buffer which contains the
+ * client's advertisement.
  * |protoOut| is a buffer provided by the caller, of length 255 (the maximum
  * allowed by the protocol). On successful return, the protocol to be announced
  * to the server will be in |protoOut| and its length in |*protoOutLen|.
  *
  * The callback must return SECFailure or SECSuccess (not SECWouldBlock).
  */
 typedef SECStatus(PR_CALLBACK *SSLNextProtoCallback)(
     void *arg,
     PRFileDesc *fd,
     const unsigned char *protos,
     unsigned int protosLen,
     unsigned char *protoOut,
     unsigned int *protoOutLen,
     unsigned int protoMaxOut);
 
-/* SSL_SetNextProtoCallback sets a callback function to handle Next Protocol
- * Negotiation. It causes a client to advertise NPN. */
+/* SSL_SetNextProtoCallback sets a callback function to handle ALPN Negotiation.
+ * It causes a client to advertise ALPN. */
 SSL_IMPORT SECStatus SSL_SetNextProtoCallback(PRFileDesc *fd,
                                               SSLNextProtoCallback callback,
                                               void *arg);
 
 /* SSL_SetNextProtoNego can be used as an alternative to
- * SSL_SetNextProtoCallback. It also causes a client to advertise NPN and
- * installs a default callback function which selects the first supported
- * protocol in server-preference order. If no matching protocol is found it
- * selects the first supported protocol.
+ * SSL_SetNextProtoCallback.
  *
- * Using this function also allows the client to transparently support ALPN.
+ * Using this function allows client and server to transparently support ALPN.
  * The same set of protocols will be advertised via ALPN and, if the server
  * uses ALPN to select a protocol, SSL_GetNextProto will return
  * SSL_NEXT_PROTO_SELECTED as the state.
  *
- * Since NPN uses the first protocol as the fallback protocol, when sending an
- * ALPN extension, the first protocol is moved to the end of the list. This
- * indicates that the fallback protocol is the least preferred. The other
- * protocols should be in preference order.
+ * Because the predecessor to ALPN, NPN, used the first protocol as the fallback
+ * protocol, when sending an ALPN extension, the first protocol is moved to the
+ * end of the list. This indicates that the fallback protocol is the least
+ * preferred. The other protocols should be in preference order.
  *
  * The supported protocols are specified in |data| in wire-format (8-bit
  * length-prefixed). For example: "\010http/1.1\006spdy/2". */
 SSL_IMPORT SECStatus SSL_SetNextProtoNego(PRFileDesc *fd,
                                           const unsigned char *data,
                                           unsigned int length);
 
 typedef enum SSLNextProtoState {
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -7316,20 +7316,16 @@ ssl3_SendClientSecondRound(sslSocket *ss
                      ss->ssl3.clientCertChain != NULL &&
                      ss->ssl3.clientPrivateKey != NULL;
 
     /* We must wait for the server's certificate to be authenticated before
      * sending the client certificate in order to disclosing the client
      * certificate to an attacker that does not have a valid cert for the
      * domain we are connecting to.
      *
-     * XXX: We should do the same for the NPN extension, but for that we
-     * need an option to give the application the ability to leak the NPN
-     * information to get better performance.
-     *
      * During the initial handshake on a connection, we never send/receive
      * application data until we have authenticated the server's certificate;
      * i.e. we have fully authenticated the handshake before using the cipher
      * specs agreed upon for that handshake. During a renegotiation, we may
      * continue sending and receiving application data during the handshake
      * interleaved with the handshake records. If we were to send the client's
      * second round for a renegotiation before the server's certificate was
      * authenticated, then the application data sent/received after this point
@@ -7393,24 +7389,16 @@ ssl3_SendClientSecondRound(sslSocket *ss
      * ssl3_SendChangeCipherSpecs because SSL_GetChannelInfo uses information
      * from cwSpec. This must be done before we call ssl3_CheckFalseStart
      * because the false start callback (if any) may need the information from
      * the functions that depend on this being set.
      */
     ss->enoughFirstHsDone = PR_TRUE;
 
     if (!ss->firstHsDone) {
-        /* XXX: If the server's certificate hasn't been authenticated by this
-         * point, then we may be leaking this NPN message to an attacker.
-         */
-        rv = ssl3_SendNextProto(ss);
-        if (rv != SECSuccess) {
-            goto loser; /* err code was set. */
-        }
-
         if (ss->opt.enableFalseStart) {
             if (!ss->ssl3.hs.authCertificatePending) {
                 /* When we fix bug 589047, we will need to know whether we are
                  * false starting before we try to flush the client second
                  * round to the network. With that in mind, we purposefully
                  * call ssl3_CheckFalseStart before calling ssl3_SendFinished,
                  * which includes a call to ssl3_FlushHandshake, so that
                  * no application develops a reliance on such flushing being
--- a/security/nss/lib/ssl/ssl3ext.c
+++ b/security/nss/lib/ssl/ssl3ext.c
@@ -34,17 +34,16 @@ typedef struct {
  */
 /* This table is used by the server, to handle client hello extensions. */
 static const ssl3ExtensionHandler clientHelloHandlers[] = {
     { ssl_server_name_xtn, &ssl3_HandleServerNameXtn },
     { ssl_supported_groups_xtn, &ssl_HandleSupportedGroupsXtn },
     { ssl_ec_point_formats_xtn, &ssl3_HandleSupportedPointFormatsXtn },
     { ssl_session_ticket_xtn, &ssl3_ServerHandleSessionTicketXtn },
     { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
-    { ssl_next_proto_nego_xtn, &ssl3_ServerHandleNextProtoNegoXtn },
     { ssl_app_layer_protocol_xtn, &ssl3_ServerHandleAppProtoXtn },
     { ssl_use_srtp_xtn, &ssl3_ServerHandleUseSRTPXtn },
     { ssl_cert_status_xtn, &ssl3_ServerHandleStatusRequestXtn },
     { ssl_signature_algorithms_xtn, &ssl3_HandleSigAlgsXtn },
     { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
     { ssl_signed_cert_timestamp_xtn, &ssl3_ServerHandleSignedCertTimestampXtn },
     { ssl_tls13_key_share_xtn, &tls13_ServerHandleKeyShareXtn },
     { ssl_tls13_pre_shared_key_xtn, &tls13_ServerHandlePreSharedKeyXtn },
@@ -56,17 +55,16 @@ static const ssl3ExtensionHandler client
 
 /* These two tables are used by the client, to handle server hello
  * extensions. */
 static const ssl3ExtensionHandler serverHelloHandlersTLS[] = {
     { ssl_server_name_xtn, &ssl3_HandleServerNameXtn },
     /* TODO: add a handler for ssl_ec_point_formats_xtn */
     { ssl_session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn },
     { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
-    { ssl_next_proto_nego_xtn, &ssl3_ClientHandleNextProtoNegoXtn },
     { ssl_app_layer_protocol_xtn, &ssl3_ClientHandleAppProtoXtn },
     { ssl_use_srtp_xtn, &ssl3_ClientHandleUseSRTPXtn },
     { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn },
     { ssl_extended_master_secret_xtn, &ssl3_HandleExtendedMasterSecretXtn },
     { ssl_signed_cert_timestamp_xtn, &ssl3_ClientHandleSignedCertTimestampXtn },
     { ssl_tls13_key_share_xtn, &tls13_ClientHandleKeyShareXtn },
     { ssl_tls13_pre_shared_key_xtn, &tls13_ClientHandlePreSharedKeyXtn },
     { ssl_tls13_early_data_xtn, &tls13_ClientHandleEarlyDataXtn },
@@ -117,17 +115,16 @@ static const ssl3ExtensionHandler certif
 static const sslExtensionBuilder clientHelloSendersTLS[] =
     {
       { ssl_server_name_xtn, &ssl3_ClientSendServerNameXtn },
       { ssl_extended_master_secret_xtn, &ssl3_SendExtendedMasterSecretXtn },
       { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn },
       { ssl_supported_groups_xtn, &ssl_SendSupportedGroupsXtn },
       { ssl_ec_point_formats_xtn, &ssl3_SendSupportedPointFormatsXtn },
       { ssl_session_ticket_xtn, &ssl3_ClientSendSessionTicketXtn },
-      { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn },
       { ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn },
       { ssl_use_srtp_xtn, &ssl3_ClientSendUseSRTPXtn },
       { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn },
       { ssl_signed_cert_timestamp_xtn, &ssl3_ClientSendSignedCertTimestampXtn },
       { ssl_tls13_key_share_xtn, &tls13_ClientSendKeyShareXtn },
       { ssl_tls13_early_data_xtn, &tls13_ClientSendEarlyDataXtn },
       /* Some servers (e.g. WebSphere Application Server 7.0 and Tomcat) will
        * time out or terminate the connection if the last extension in the
@@ -178,17 +175,16 @@ static const struct {
     { ssl_tls13_key_share_xtn, ssl_ext_native_only },
     { ssl_tls13_pre_shared_key_xtn, ssl_ext_native_only },
     { ssl_tls13_early_data_xtn, ssl_ext_native_only },
     { ssl_tls13_supported_versions_xtn, ssl_ext_native_only },
     { ssl_tls13_cookie_xtn, ssl_ext_native_only },
     { ssl_tls13_psk_key_exchange_modes_xtn, ssl_ext_native_only },
     { ssl_tls13_ticket_early_data_info_xtn, ssl_ext_native_only },
     { ssl_tls13_certificate_authorities_xtn, ssl_ext_native },
-    { ssl_next_proto_nego_xtn, ssl_ext_none },
     { ssl_renegotiation_info_xtn, ssl_ext_native }
 };
 
 static SSLExtensionSupport
 ssl_GetExtensionSupport(PRUint16 type)
 {
     unsigned int i;
     for (i = 0; i < PR_ARRAY_SIZE(ssl_supported_extensions); ++i) {
--- a/security/nss/lib/ssl/ssl3exthandle.c
+++ b/security/nss/lib/ssl/ssl3exthandle.c
@@ -237,43 +237,21 @@ ssl_AlpnTagAllowed(const sslSocket *ss, 
             !PORT_Memcmp(data + offset + 1, tag->data, tag->len))
             return PR_TRUE;
         offset += 1 + taglen;
     }
 
     return PR_FALSE;
 }
 
-/* handle an incoming Next Protocol Negotiation extension. */
-SECStatus
-ssl3_ServerHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                  SECItem *data)
-{
-    PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
-
-    if (ss->firstHsDone || data->len != 0) {
-        /* Clients MUST send an empty NPN extension, if any. */
-        PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
-        return SECFailure;
-    }
-
-    xtnData->negotiated[xtnData->numNegotiated++] = ssl_next_proto_nego_xtn;
-
-    /* TODO: server side NPN support would require calling
-     * ssl3_RegisterServerHelloExtensionSender here in order to echo the
-     * extension back to the client. */
-
-    return SECSuccess;
-}
-
-/* ssl3_ValidateNextProtoNego checks that the given block of data is valid: none
+/* ssl3_ValidateAppProtocol checks that the given block of data is valid: none
  * of the lengths may be 0 and the sum of the lengths must equal the length of
  * the block. */
 SECStatus
-ssl3_ValidateNextProtoNego(const unsigned char *data, unsigned int length)
+ssl3_ValidateAppProtocol(const unsigned char *data, unsigned int length)
 {
     unsigned int offset = 0;
 
     while (offset < length) {
         unsigned int newOffset = offset + 1 + (unsigned int)data[offset];
         /* Reject embedded nulls to protect against buggy applications that
          * store protocol identifiers in null-terminated strings.
          */
@@ -281,65 +259,66 @@ ssl3_ValidateNextProtoNego(const unsigne
             return SECFailure;
         }
         offset = newOffset;
     }
 
     return SECSuccess;
 }
 
-/* protocol selection handler for ALPN (server side) and NPN (client side) */
+/* Protocol selection handler for ALPN. */
 static SECStatus
 ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData,
                        PRUint16 extension, SECItem *data)
 {
     SECStatus rv;
     unsigned char resultBuffer[255];
     SECItem result = { siBuffer, resultBuffer, 0 };
 
-    rv = ssl3_ValidateNextProtoNego(data->data, data->len);
+    rv = ssl3_ValidateAppProtocol(data->data, data->len);
     if (rv != SECSuccess) {
         ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
         return rv;
     }
 
     PORT_Assert(ss->nextProtoCallback);
-    /* For ALPN, the cipher suite isn't selected yet.  Note that extensions
+    /* The cipher suite isn't selected yet.  Note that extensions
      * sometimes affect what cipher suite is selected, e.g., for ECC. */
     PORT_Assert((ss->ssl3.hs.preliminaryInfo &
                  ssl_preinfo_all & ~ssl_preinfo_cipher_suite) ==
                 (ssl_preinfo_all & ~ssl_preinfo_cipher_suite));
+    /* The callback has to make sure that either rv != SECSuccess or that result
+     * is not set if there is no common protocol. */
     rv = ss->nextProtoCallback(ss->nextProtoArg, ss->fd, data->data, data->len,
                                result.data, &result.len, sizeof(resultBuffer));
     if (rv != SECSuccess) {
         /* Expect callback to call PORT_SetError() */
         ssl3_ExtSendAlert(ss, alert_fatal, internal_error);
         return SECFailure;
     }
 
     /* If the callback wrote more than allowed to |result| it has corrupted our
      * stack. */
     if (result.len > sizeof(resultBuffer)) {
         PORT_SetError(SEC_ERROR_OUTPUT_LEN);
-        /* TODO: crash */
+        PORT_Assert(PR_FALSE);
         return SECFailure;
     }
 
     SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE);
 
-    if (extension == ssl_app_layer_protocol_xtn &&
-        xtnData->nextProtoState != SSL_NEXT_PROTO_NEGOTIATED) {
-        /* The callback might say OK, but then it picks a default value - one
-         * that was not listed.  That's OK for NPN, but not ALPN. */
+    if (result.len < 1 || !result.data) {
+        /* Check that we actually got a result. */
         ssl3_ExtSendAlert(ss, alert_fatal, no_application_protocol);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL);
         return SECFailure;
     }
 
+    xtnData->nextProtoState = SSL_NEXT_PROTO_NEGOTIATED;
     xtnData->negotiated[xtnData->numNegotiated++] = extension;
     return SECITEM_CopyItem(NULL, &xtnData->nextProto, &result);
 }
 
 /* handle an incoming ALPN extension at the server */
 SECStatus
 ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                              SECItem *data)
@@ -351,17 +330,17 @@ ssl3_ServerHandleAppProtoXtn(const sslSo
      * despite it being permitted by the spec. */
     if (ss->firstHsDone || data->len == 0) {
         /* Clients MUST send a non-empty ALPN extension. */
         ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
         return SECFailure;
     }
 
-    /* Unlike NPN, ALPN has extra redundant length information so that
+    /* ALPN has extra redundant length information so that
      * the extension is the same in both ClientHello and ServerHello. */
     rv = ssl3_ExtConsumeHandshakeNumber(ss, &count, 2, &data->data, &data->len);
     if (rv != SECSuccess || count != data->len) {
         ssl3_ExtDecodeError(ss);
         return SECFailure;
     }
 
     if (!ss->nextProtoCallback) {
@@ -384,49 +363,16 @@ ssl3_ServerHandleAppProtoXtn(const sslSo
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             return rv;
         }
     }
     return SECSuccess;
 }
 
 SECStatus
-ssl3_ClientHandleNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                  SECItem *data)
-{
-    PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
-    PORT_Assert(!ss->firstHsDone);
-
-    if (ssl3_ExtensionNegotiated(ss, ssl_app_layer_protocol_xtn)) {
-        /* If the server negotiated ALPN then it has already told us what
-         * protocol to use, so it doesn't make sense for us to try to negotiate
-         * a different one by sending the NPN handshake message. However, if
-         * we've negotiated NPN then we're required to send the NPN handshake
-         * message. Thus, these two extensions cannot both be negotiated on the
-         * same connection. */
-        ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
-        PORT_SetError(SSL_ERROR_BAD_SERVER);
-        return SECFailure;
-    }
-
-    /* We should only get this call if we sent the extension, so
-     * ss->nextProtoCallback needs to be non-NULL.  However, it is possible
-     * that an application erroneously cleared the callback between the time
-     * we sent the ClientHello and now. */
-    if (!ss->nextProtoCallback) {
-        PORT_Assert(0);
-        ssl3_ExtSendAlert(ss, alert_fatal, internal_error);
-        PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_CALLBACK);
-        return SECFailure;
-    }
-
-    return ssl3_SelectAppProtocol(ss, xtnData, ssl_next_proto_nego_xtn, data);
-}
-
-SECStatus
 ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                              SECItem *data)
 {
     SECStatus rv;
     PRUint32 list_len;
     SECItem protocol_name;
 
     if (ssl3_ExtensionNegotiated(ss, ssl_next_proto_nego_xtn)) {
@@ -470,69 +416,36 @@ ssl3_ClientHandleAppProtoXtn(const sslSo
 
     SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE);
     xtnData->nextProtoState = SSL_NEXT_PROTO_SELECTED;
     xtnData->negotiated[xtnData->numNegotiated++] = ssl_app_layer_protocol_xtn;
     return SECITEM_CopyItem(NULL, &xtnData->nextProto, &protocol_name);
 }
 
 SECStatus
-ssl3_ClientSendNextProtoNegoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
-                                sslBuffer *buf, PRBool *added)
-{
-    /* Renegotiations do not send this extension. */
-    if (!ss->opt.enableNPN || !ss->nextProtoCallback || ss->firstHsDone) {
-        return SECSuccess;
-    }
-
-    *added = PR_TRUE;
-    return SECSuccess;
-}
-
-SECStatus
 ssl3_ClientSendAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                            sslBuffer *buf, PRBool *added)
 {
     SECStatus rv;
     const unsigned int len = ss->opt.nextProtoNego.len;
 
     /* Renegotiations do not send this extension. */
     if (!ss->opt.enableALPN || !ss->opt.nextProtoNego.data || ss->firstHsDone) {
         return SECSuccess;
     }
 
-    /* NPN requires that the client's fallback protocol is first in the
-     * list. However, ALPN sends protocols in preference order. So move the
-     * first protocol to the end of the list. */
-
     if (len > 0) {
         /* Each protocol string is prefixed with a single byte length. */
-        unsigned int i;
-
         rv = sslBuffer_AppendNumber(buf, len, 2);
         if (rv != SECSuccess) {
             return SECFailure;
         }
-
-        i = ss->opt.nextProtoNego.data[0] + 1;
-        if (i <= len) {
-            rv = sslBuffer_Append(buf, &ss->opt.nextProtoNego.data[i], len - i);
-            if (rv != SECSuccess) {
-                return SECFailure;
-            }
-            rv = sslBuffer_Append(buf, ss->opt.nextProtoNego.data, i);
-            if (rv != SECSuccess) {
-                return SECFailure;
-            }
-        } else {
-            /* This seems to be invalid data so we'll send as-is. */
-            rv = sslBuffer_Append(buf, ss->opt.nextProtoNego.data, len);
-            if (rv != SECSuccess) {
-                return SECFailure;
-            }
+        rv = sslBuffer_Append(buf, ss->opt.nextProtoNego.data, len);
+        if (rv != SECSuccess) {
+            return SECFailure;
         }
     }
 
     *added = PR_TRUE;
     return SECSuccess;
 }
 
 SECStatus
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -246,17 +246,16 @@ typedef struct sslOptionsStr {
     unsigned int noLocks : 1;
     unsigned int enableSessionTickets : 1;
     unsigned int enableDeflate : 1; /* Deprecated. */
     unsigned int enableRenegotiation : 2;
     unsigned int requireSafeNegotiation : 1;
     unsigned int enableFalseStart : 1;
     unsigned int cbcRandomIV : 1;
     unsigned int enableOCSPStapling : 1;
-    unsigned int enableNPN : 1;
     unsigned int enableALPN : 1;
     unsigned int reuseServerECDHEKey : 1;
     unsigned int enableFallbackSCSV : 1;
     unsigned int enableServerDhe : 1;
     unsigned int enableExtendedMS : 1;
     unsigned int enableSignedCertTimestamps : 1;
     unsigned int requireDHENamedGroups : 1;
     unsigned int enable0RttData : 1;
@@ -438,17 +437,17 @@ struct sslSessionIDStr {
 
             SECItem srvName;
 
             /* Signed certificate timestamps received in a TLS extension.
             ** (used only in client).
             */
             SECItem signedCertTimestamps;
 
-            /* The NPN/ALPN value negotiated in the original connection.
+            /* The ALPN value negotiated in the original connection.
              * Used for TLS 1.3. */
             SECItem alpnSelection;
 
             /* This lock is lazily initialized by CacheSID when a sid is first
              * cached. Before then, there is no need to lock anything because
              * the sid isn't being shared by anything.
              */
             PRRWLock *lock;
@@ -1542,18 +1541,18 @@ SECStatus ssl3_EncodeSessionTicket(sslSo
 SECStatus SSLExp_SendSessionTicket(PRFileDesc *fd, const PRUint8 *token,
                                    unsigned int tokenLen);
 
 SECStatus ssl_MaybeSetSelfEncryptKeyPair(const sslKeyPair *keyPair);
 SECStatus ssl_GetSelfEncryptKeys(sslSocket *ss, unsigned char *keyName,
                                  PK11SymKey **encKey, PK11SymKey **macKey);
 void ssl_ResetSelfEncryptKeys();
 
-extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char *data,
-                                            unsigned int length);
+extern SECStatus ssl3_ValidateAppProtocol(const unsigned char *data,
+                                          unsigned int length);
 
 /* Construct a new NSPR socket for the app to use */
 extern PRFileDesc *ssl_NewPRSocket(sslSocket *ss, PRFileDesc *fd);
 extern void ssl_FreePRSocket(PRFileDesc *fd);
 
 /* Internal config function so SSL3 can initialize the present state of
  * various ciphers */
 extern unsigned int ssl3_config_match_init(sslSocket *);
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -67,17 +67,16 @@ static sslOptions ssl_defaults = {
     .noLocks = PR_FALSE,
     .enableSessionTickets = PR_FALSE,
     .enableDeflate = PR_FALSE,
     .enableRenegotiation = SSL_RENEGOTIATE_REQUIRES_XTN,
     .requireSafeNegotiation = PR_FALSE,
     .enableFalseStart = PR_FALSE,
     .cbcRandomIV = PR_TRUE,
     .enableOCSPStapling = PR_FALSE,
-    .enableNPN = PR_FALSE,
     .enableALPN = PR_TRUE,
     .reuseServerECDHEKey = PR_TRUE,
     .enableFallbackSCSV = PR_FALSE,
     .enableServerDhe = PR_TRUE,
     .enableExtendedMS = PR_FALSE,
     .enableSignedCertTimestamps = PR_FALSE,
     .requireDHENamedGroups = PR_FALSE,
     .enable0RttData = PR_FALSE,
@@ -914,17 +913,17 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 wh
             break;
         case SSL_CBC_RANDOM_IV:
             val = ss->opt.cbcRandomIV;
             break;
         case SSL_ENABLE_OCSP_STAPLING:
             val = ss->opt.enableOCSPStapling;
             break;
         case SSL_ENABLE_NPN:
-            val = ss->opt.enableNPN;
+            val = PR_FALSE;
             break;
         case SSL_ENABLE_ALPN:
             val = ss->opt.enableALPN;
             break;
         case SSL_REUSE_SERVER_ECDHE_KEY:
             val = ss->opt.reuseServerECDHEKey;
             break;
         case SSL_ENABLE_FALLBACK_SCSV:
@@ -1040,17 +1039,17 @@ SSL_OptionGetDefault(PRInt32 which, PRIn
             break;
         case SSL_CBC_RANDOM_IV:
             val = ssl_defaults.cbcRandomIV;
             break;
         case SSL_ENABLE_OCSP_STAPLING:
             val = ssl_defaults.enableOCSPStapling;
             break;
         case SSL_ENABLE_NPN:
-            val = ssl_defaults.enableNPN;
+            val = PR_FALSE;
             break;
         case SSL_ENABLE_ALPN:
             val = ssl_defaults.enableALPN;
             break;
         case SSL_REUSE_SERVER_ECDHE_KEY:
             val = ssl_defaults.reuseServerECDHEKey;
             break;
         case SSL_ENABLE_FALLBACK_SCSV:
@@ -1905,20 +1904,17 @@ SSL_ImportFD(PRFileDesc *model, PRFileDe
 
 PRFileDesc *
 DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd)
 {
     return ssl_ImportFD(model, fd, ssl_variant_datagram);
 }
 
 /* SSL_SetNextProtoCallback is used to select an application protocol
- * for ALPN and NPN.  For ALPN, this runs on the server; for NPN it
- * runs on the client. */
-/* Note: The ALPN version doesn't allow for the use of a default, setting a
- * status of SSL_NEXT_PROTO_NO_OVERLAP is treated as a failure. */
+ * for ALPN. */
 SECStatus
 SSL_SetNextProtoCallback(PRFileDesc *fd, SSLNextProtoCallback callback,
                          void *arg)
 {
     sslSocket *ss = ssl_FindSocket(fd);
 
     if (!ss) {
         SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetNextProtoCallback", SSL_GETPID(),
@@ -1929,94 +1925,88 @@ SSL_SetNextProtoCallback(PRFileDesc *fd,
     ssl_GetSSL3HandshakeLock(ss);
     ss->nextProtoCallback = callback;
     ss->nextProtoArg = arg;
     ssl_ReleaseSSL3HandshakeLock(ss);
 
     return SECSuccess;
 }
 
-/* ssl_NextProtoNegoCallback is set as an ALPN/NPN callback when
+/* ssl_NextProtoNegoCallback is set as an ALPN callback when
  * SSL_SetNextProtoNego is used.
  */
 static SECStatus
 ssl_NextProtoNegoCallback(void *arg, PRFileDesc *fd,
                           const unsigned char *protos, unsigned int protos_len,
                           unsigned char *protoOut, unsigned int *protoOutLen,
                           unsigned int protoMaxLen)
 {
     unsigned int i, j;
-    const unsigned char *result;
     sslSocket *ss = ssl_FindSocket(fd);
 
     if (!ss) {
         SSL_DBG(("%d: SSL[%d]: bad socket in ssl_NextProtoNegoCallback",
                  SSL_GETPID(), fd));
         return SECFailure;
     }
-
-    /* For each protocol in server preference, see if we support it. */
-    for (i = 0; i < protos_len;) {
-        for (j = 0; j < ss->opt.nextProtoNego.len;) {
+    PORT_Assert(protoMaxLen <= 255);
+    if (protoMaxLen > 255) {
+        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+        return SECFailure;
+    }
+
+    /* For each protocol in client preference, see if we support it. */
+    for (j = 0; j < ss->opt.nextProtoNego.len;) {
+        for (i = 0; i < protos_len;) {
             if (protos[i] == ss->opt.nextProtoNego.data[j] &&
                 PORT_Memcmp(&protos[i + 1], &ss->opt.nextProtoNego.data[j + 1],
                             protos[i]) == 0) {
                 /* We found a match. */
-                ss->xtnData.nextProtoState = SSL_NEXT_PROTO_NEGOTIATED;
-                result = &protos[i];
-                goto found;
+                const unsigned char *result = &protos[i];
+                memcpy(protoOut, result + 1, result[0]);
+                *protoOutLen = result[0];
+                return SECSuccess;
             }
-            j += 1 + (unsigned int)ss->opt.nextProtoNego.data[j];
+            i += 1 + (unsigned int)protos[i];
         }
-        i += 1 + (unsigned int)protos[i];
+        j += 1 + (unsigned int)ss->opt.nextProtoNego.data[j];
     }
 
-    /* The other side supports the extension, and either doesn't have any
-     * protocols configured, or none of its options match ours. In this case we
-     * request our favoured protocol. */
-    /* This will be treated as a failure for ALPN. */
-    ss->xtnData.nextProtoState = SSL_NEXT_PROTO_NO_OVERLAP;
-    result = ss->opt.nextProtoNego.data;
-
-found:
-    if (protoMaxLen < result[0]) {
-        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
-        return SECFailure;
-    }
-    memcpy(protoOut, result + 1, result[0]);
-    *protoOutLen = result[0];
     return SECSuccess;
 }
 
 SECStatus
 SSL_SetNextProtoNego(PRFileDesc *fd, const unsigned char *data,
                      unsigned int length)
 {
     sslSocket *ss;
-    SECStatus rv;
-    SECItem dataItem = { siBuffer, (unsigned char *)data, length };
 
     ss = ssl_FindSocket(fd);
     if (!ss) {
         SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetNextProtoNego",
                  SSL_GETPID(), fd));
         return SECFailure;
     }
 
-    if (ssl3_ValidateNextProtoNego(data, length) != SECSuccess)
+    if (ssl3_ValidateAppProtocol(data, length) != SECSuccess) {
         return SECFailure;
-
+    }
+
+    /* NPN required that the client's fallback protocol is first in the
+     * list. However, ALPN sends protocols in preference order. So move the
+     * first protocol to the end of the list. */
     ssl_GetSSL3HandshakeLock(ss);
     SECITEM_FreeItem(&ss->opt.nextProtoNego, PR_FALSE);
-    rv = SECITEM_CopyItem(NULL, &ss->opt.nextProtoNego, &dataItem);
+    SECITEM_AllocItem(NULL, &ss->opt.nextProtoNego, length);
+    size_t firstLen = data[0] + 1;
+    /* firstLen <= length is ensured by ssl3_ValidateAppProtocol. */
+    PORT_Memcpy(ss->opt.nextProtoNego.data + (length - firstLen), data, firstLen);
+    PORT_Memcpy(ss->opt.nextProtoNego.data, data + firstLen, length - firstLen);
     ssl_ReleaseSSL3HandshakeLock(ss);
 
-    if (rv != SECSuccess)
-        return rv;
-
     return SSL_SetNextProtoCallback(fd, ssl_NextProtoNegoCallback, NULL);
 }
 
 SECStatus
 SSL_GetNextProto(PRFileDesc *fd, SSLNextProtoState *state, unsigned char *buf,
                  unsigned int *bufLen, unsigned int bufLenMax)
 {
     sslSocket *ss = ssl_FindSocket(fd);
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -3579,17 +3579,17 @@ tls13_ChaCha20Poly1305(ssl3KeyMaterial *
                       (unsigned char *)&aeadParams, sizeof(aeadParams));
 }
 
 static SECStatus
 tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length)
 {
     SECStatus rv;
     PRUint32 innerLength;
-    SECItem oldNpn = { siBuffer, NULL, 0 };
+    SECItem oldAlpn = { siBuffer, NULL, 0 };
 
     PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
     PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
 
     SSL_TRC(3, ("%d: TLS13[%d]: handle encrypted extensions",
                 SSL_GETPID(), ss->fd));
 
     rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_ENCRYPTED_EXTENSIONS,
@@ -3603,21 +3603,21 @@ tls13_HandleEncryptedExtensions(sslSocke
         return SECFailure; /* Alert already sent. */
     }
     if (innerLength != length) {
         FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS,
                     illegal_parameter);
         return SECFailure;
     }
 
-    /* If we are doing 0-RTT, then we already have an NPN value. Stash
+    /* If we are doing 0-RTT, then we already have an ALPN value. Stash
      * it for comparison. */
     if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent &&
         ss->xtnData.nextProtoState == SSL_NEXT_PROTO_EARLY_VALUE) {
-        oldNpn = ss->xtnData.nextProto;
+        oldAlpn = ss->xtnData.nextProto;
         ss->xtnData.nextProto.data = NULL;
         ss->xtnData.nextProtoState = SSL_NEXT_PROTO_NO_SUPPORT;
     }
     rv = ssl3_HandleExtensions(ss, &b, &length, ssl_hs_encrypted_extensions);
     if (rv != SECSuccess) {
         return SECFailure; /* Error code set below */
     }
 
@@ -3627,18 +3627,18 @@ tls13_HandleEncryptedExtensions(sslSocke
         if (!ss->statelessResume) {
             /* Illegal to accept 0-RTT without also accepting PSK. */
             FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS,
                         illegal_parameter);
         }
         ss->ssl3.hs.zeroRttState = ssl_0rtt_accepted;
 
         /* Check that the server negotiated the same ALPN (if any). */
-        if (SECITEM_CompareItem(&oldNpn, &ss->xtnData.nextProto)) {
-            SECITEM_FreeItem(&oldNpn, PR_FALSE);
+        if (SECITEM_CompareItem(&oldAlpn, &ss->xtnData.nextProto)) {
+            SECITEM_FreeItem(&oldAlpn, PR_FALSE);
             FATAL_ERROR(ss, SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID,
                         illegal_parameter);
             return SECFailure;
         }
         /* Check that the server negotiated the same cipher suite. */
         if (ss->ssl3.hs.cipher_suite != ss->ssl3.hs.zeroRttSuite) {
             FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ENCRYPTED_EXTENSIONS,
                         illegal_parameter);
@@ -3650,17 +3650,17 @@ tls13_HandleEncryptedExtensions(sslSocke
         ss->ssl3.hs.zeroRttState = ssl_0rtt_ignored;
         ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_trial;
     } else {
         PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_none ||
                     (ss->ssl3.hs.helloRetry &&
                      ss->ssl3.hs.zeroRttState == ssl_0rtt_ignored));
     }
 
-    SECITEM_FreeItem(&oldNpn, PR_FALSE);
+    SECITEM_FreeItem(&oldAlpn, PR_FALSE);
     if (ss->ssl3.hs.kea_def->authKeyType == ssl_auth_psk) {
         TLS13_SET_HS_STATE(ss, wait_finished);
     } else {
         TLS13_SET_HS_STATE(ss, wait_cert_request);
     }
 
     return SECSuccess;
 }
--- a/security/nss/mach
+++ b/security/nss/mach
@@ -5,23 +5,42 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 ##########################################################################
 #
 # This is a collection of helper tools to get stuff done in NSS.
 #
 
 import sys
 import argparse
+import fnmatch
 import subprocess
 import os
 import platform
+import tempfile
+
 from hashlib import sha256
 
+DEVNULL = open(os.devnull, 'wb')
 cwd = os.path.dirname(os.path.abspath(__file__))
 
+def run_tests(test, cycles="standard", env={}, silent=False):
+    domsuf = os.getenv('DOMSUF', "localdomain")
+    host = os.getenv('HOST', "localhost")
+    env = env.copy()
+    env.update({
+        "NSS_TESTS": test,
+        "NSS_CYCLES": cycles,
+        "DOMSUF": domsuf,
+        "HOST": host
+    })
+    os_env = os.environ
+    os_env.update(env)
+    command = cwd + "/tests/all.sh"
+    stdout = stderr = DEVNULL if silent else None
+    subprocess.check_call(command, env=os_env, stdout=stdout, stderr=stderr)
 
 class cfAction(argparse.Action):
     docker_command = ["docker"]
     restorecon = None
 
     def __call__(self, parser, args, values, option_string=None):
         if not args.noroot:
             self.setDockerCommand()
@@ -122,39 +141,73 @@ class cfAction(argparse.Action):
         def isFormatted(x):
             return x[-2:] == '.c' or x[-3:] == '.cc' or x[-2:] == '.h'
         return [x for x in files if isFormatted(x)]
 
 
 class buildAction(argparse.Action):
 
     def __call__(self, parser, args, values, option_string=None):
-        cwd = os.path.dirname(os.path.abspath(__file__))
         subprocess.check_call([cwd + "/build.sh"] + values)
 
 
 class testAction(argparse.Action):
 
-    def runTest(self, test, cycles="standard"):
-        cwd = os.path.dirname(os.path.abspath(__file__))
-        domsuf = os.getenv('DOMSUF', "localdomain")
-        host = os.getenv('HOST', "localhost")
+    def __call__(self, parser, args, values, option_string=None):
+        run_tests(values)
+
+
+class covAction(argparse.Action):
+
+    def runSslGtests(self, outdir):
         env = {
-            "NSS_TESTS": test,
-            "NSS_CYCLES": cycles,
-            "DOMSUF": domsuf,
-            "HOST": host
+            "GTESTFILTER": "*", # Prevent parallel test runs.
+            "ASAN_OPTIONS": "coverage=1:coverage_dir=" + outdir
         }
-        os_env = os.environ
-        os_env.update(env)
-        command = cwd + "/tests/all.sh"
-        subprocess.check_call(command, env=os_env)
+
+        run_tests("ssl_gtests", env=env, silent=True)
+
+    def findSanCovFile(self, outdir):
+        for file in os.listdir(outdir):
+            if fnmatch.fnmatch(file, 'ssl_gtest.*.sancov'):
+                return os.path.join(outdir, file)
+
+        return None
 
     def __call__(self, parser, args, values, option_string=None):
-        self.runTest(values)
+        outdir = args.outdir
+        print("Output directory: " + outdir)
+
+        print("\nBuild with coverage sanitizers...\n")
+        sancov_args = "edge,no-prune,trace-pc-guard,trace-cmp"
+        subprocess.check_call([
+            os.path.join(cwd, "build.sh"), "-c", "--clang", "--asan",
+            "--sancov=" + sancov_args
+        ])
+
+        print("\nRun ssl_gtests to get a coverage report...")
+        self.runSslGtests(outdir)
+        print("Done.")
+
+        sancov_file = self.findSanCovFile(outdir)
+        if not sancov_file:
+            print("Couldn't find .sancov file.")
+            sys.exit(1)
+
+        symcov_file = os.path.join(outdir, "ssl_gtest.symcov")
+        out = open(symcov_file, 'wb')
+        subprocess.check_call([
+            "sancov",
+            "-blacklist=" + os.path.join(cwd, ".sancov-blacklist"),
+            "-symbolize", sancov_file,
+            os.path.join(cwd, "../dist/Debug/bin/ssl_gtest")
+        ], stdout=out)
+        out.close()
+
+        print("\nCoverage report: " + symcov_file)
 
 
 class commandsAction(argparse.Action):
     commands = []
 
     def __call__(self, parser, args, values, option_string=None):
         for c in commandsAction.commands:
             print(c)
@@ -194,16 +247,26 @@ def parse_arguments():
     tests = [
         "cipher", "lowhash", "chains", "cert", "dbtests", "tools", "fips",
         "sdr", "crmf", "smime", "ssl", "ocsp", "merge", "pkits", "ec",
         "gtests", "ssl_gtests", "bogo"
     ]
     parser_test.add_argument(
         'test', choices=tests, help="Available tests", action=testAction)
 
+    parser_cov = subparsers.add_parser(
+        'coverage', help='Generate coverage report')
+    cov_modules = ["ssl_gtests"]
+    parser_cov.add_argument(
+        '--outdir', help='Output directory for coverage report data.',
+        default=tempfile.mkdtemp())
+    parser_cov.add_argument(
+        'module', choices=cov_modules, help="Available coverage modules",
+        action=covAction)
+
     parser_commands = subparsers.add_parser(
         'mach-commands',
         help="list commands")
     parser_commands.add_argument(
         'mach-commands',
         nargs='*',
         action=commandsAction)