Bug 1166031 - Update NSS to NSS_3_19_1_RTM. a=lizzard
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 28 May 2015 15:14:54 -0400
changeset 260472 b68c2aa2ba17
parent 260471 0b2496be7da1
child 260473 e4122cc66111
push id44
push userryanvm@gmail.com
push dateThu, 28 May 2015 23:11:22 +0000
treeherdermozilla-esr38@104927365946 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslizzard
bugs1166031
milestone38.0.1esrpre
Bug 1166031 - Update NSS to NSS_3_19_1_RTM. a=lizzard
CLOBBER
configure.in
security/nss/TAG-INFO
security/nss/cmd/certutil/certext.c
security/nss/cmd/certutil/certutil.c
security/nss/cmd/checkcert/checkcert.c
security/nss/cmd/modutil/install.c
security/nss/cmd/platlibs.mk
security/nss/coreconf/coreconf.dep
security/nss/coreconf/location.mk
security/nss/external_tests/README
security/nss/external_tests/ssl_gtest/manifest.mn
security/nss/external_tests/ssl_gtest/ssl_extension_unittest.cc
security/nss/external_tests/ssl_gtest/ssl_loopback_unittest.cc
security/nss/external_tests/ssl_gtest/ssl_skip_unittest.cc
security/nss/external_tests/ssl_gtest/test_io.cc
security/nss/external_tests/ssl_gtest/test_io.h
security/nss/external_tests/ssl_gtest/tls_agent.cc
security/nss/external_tests/ssl_gtest/tls_agent.h
security/nss/external_tests/ssl_gtest/tls_connect.cc
security/nss/external_tests/ssl_gtest/tls_connect.h
security/nss/external_tests/ssl_gtest/tls_filter.cc
security/nss/external_tests/ssl_gtest/tls_filter.h
security/nss/external_tests/ssl_gtest/tls_parser.h
security/nss/lib/certdb/cert.h
security/nss/lib/certdb/certt.h
security/nss/lib/certdb/genname.c
security/nss/lib/ckfw/builtins/config.mk
security/nss/lib/ckfw/capi/config.mk
security/nss/lib/cryptohi/keyhi.h
security/nss/lib/cryptohi/seckey.c
security/nss/lib/freebl/blapit.h
security/nss/lib/freebl/ecl/ecp_jac.c
security/nss/lib/freebl/ecl/ecp_jm.c
security/nss/lib/freebl/mpi/mpmontg.c
security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c
security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.c
security/nss/lib/nss/nss.def
security/nss/lib/nss/nss.h
security/nss/lib/smime/cmsmessage.c
security/nss/lib/softoken/config.mk
security/nss/lib/softoken/sftkpwd.c
security/nss/lib/softoken/softkver.h
security/nss/lib/ssl/SSLerrs.h
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/ssl3ecc.c
security/nss/lib/ssl/ssl3ext.c
security/nss/lib/ssl/sslerr.h
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslsock.c
security/nss/lib/util/nssutil.h
security/nss/tests/all.sh
security/nss/tests/cert/cert.sh
security/nss/tests/chains/scenarios/realcerts.cfg
security/nss/tests/libpkix/certs/PayPalEE.cert
security/nss/tests/libpkix/certs/PayPalICA.cert
security/nss/tests/libpkix/certs/PayPalRootCA.cert
security/nss/tests/libpkix/vfychain_test.lst
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Merge day clobber
\ No newline at end of file
+Bug 1166031 - NSS update hit needs-clobber bustage.
--- a/configure.in
+++ b/configure.in
@@ -3622,17 +3622,17 @@ dnl = If NSS was not detected in the sys
 dnl = use the one in the source tree (mozilla/security/nss)
 dnl ========================================================
 
 MOZ_ARG_WITH_BOOL(system-nss,
 [  --with-system-nss       Use system installed NSS],
     _USE_SYSTEM_NSS=1 )
 
 if test -n "$_USE_SYSTEM_NSS"; then
-    AM_PATH_NSS(3.18.1, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
+    AM_PATH_NSS(3.19.1, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
 fi
 
 if test -n "$MOZ_NATIVE_NSS"; then
    NSS_LIBS="$NSS_LIBS -lcrmf"
 else
    NSS_CFLAGS='-I$(LIBXUL_DIST)/include/nss'
 
    if test -z "$GNU_CC" -a "$OS_ARCH" = "WINNT"; then
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_18_1_RTM
+NSS_3_19_1_RTM
--- a/security/nss/cmd/certutil/certext.c
+++ b/security/nss/cmd/certutil/certext.c
@@ -982,20 +982,23 @@ AddNameConstraints(void *extHandle)
         }
 
         (void) SEC_ASN1EncodeInteger(arena, &current->min, 0);
 
         if (!GetGeneralName(arena, &current->name, PR_TRUE)) {
             GEN_BREAK(SECFailure);
         }
 
-        PrintChoicesAndGetAnswer("Type of Name Constraint?\n"
+        if (PrintChoicesAndGetAnswer("Type of Name Constraint?\n"
             "\t1 - permitted\n\t2 - excluded\n\tAny"
             "other number to finish\n\tChoice",
-            buffer, sizeof(buffer));
+            buffer, sizeof(buffer)) != SECSuccess) {
+            GEN_BREAK(SECFailure);
+        }
+
         intValue = PORT_Atoi(buffer);
         switch (intValue) {
         case 1:
             if (constraints->permited == NULL) {
                 constraints->permited = last_permited = current;
             }
             last_permited->l.next = &(current->l);
             current->l.prev = &(last_permited->l);
@@ -1821,21 +1824,23 @@ AddInfoAccess(void *extHandle, PRBool ad
                     "Subject Information Access extension:\n");
                 intValue = caRepository;
             } else {
                 puts("Adding \"Time Stamping Services\" access method type for "
                     "Subject Information Access extension:\n");
                 intValue = timeStamping;
             }
         } else {
-            PrintChoicesAndGetAnswer("Enter access method type "
+            if (PrintChoicesAndGetAnswer("Enter access method type "
                 "for Authority Information Access extension:\n"
                 "\t1 - CA Issuers\n\t2 - OCSP\n\tAny"
                 "other number to finish\n\tChoice",
-                buffer, sizeof(buffer));
+                buffer, sizeof(buffer)) != SECSuccess) {
+                GEN_BREAK (SECFailure);
+            }
             intValue = PORT_Atoi(buffer);
         }
         if (addSIAExt) {
             switch (intValue) {
               case caRepository:
                   oid = SECOID_FindOIDByTag(SEC_OID_PKIX_CA_REPOSITORY);
                   break;
                   
--- a/security/nss/cmd/certutil/certutil.c
+++ b/security/nss/cmd/certutil/certutil.c
@@ -175,17 +175,17 @@ AddCert(PK11SlotInfo *slot, CERTCertDBHa
     CERT_DestroyCertificate (cert);
     PORT_Free(trust);
 
     return rv;
 }
 
 static SECStatus
 CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
-        SECOidTag hashAlgTag, CERTName *subject, char *phone, int ascii, 
+        SECOidTag hashAlgTag, CERTName *subject, const char *phone, int ascii,
 	const char *emailAddrs, const char *dnsNames,
         certutilExtnList extnList, const char *extGeneric,
         /*out*/ SECItem *result)
 {
     CERTSubjectPublicKeyInfo *spki;
     CERTCertificateRequest *cr;
     SECItem *encoding;
     SECOidTag signAlgTag;
@@ -265,17 +265,17 @@ CertReq(SECKEYPrivateKey *privk, SECKEYP
 	}
 
 	name = CERT_GetCommonName(subject);
 	if (!name) {
 	    name = PORT_Strdup("(not specified)");
 	}
 
 	if (!phone)
-	    phone = strdup("(not specified)");
+	    phone = "(not specified)";
 
 	email = CERT_GetCertEmailAddress(subject);
 	if (!email)
 	    email = PORT_Strdup("(not specified)");
 
 	org = CERT_GetOrgName(subject);
 	if (!org)
 	    org = PORT_Strdup("(not specified)");
@@ -318,16 +318,17 @@ CertReq(SECKEYPrivateKey *privk, SECKEYP
 		    PORT_Memcpy(result->data + headerLen, obuf, obufLen);
 		    PORT_Memcpy(result->data + headerLen + obufLen,
 				trailer, trailerLen);
 		}
 		PR_smprintf_free(trailer);
 	    }
 	    PR_smprintf_free(header);
 	}
+	PORT_Free(obuf);
     } else {
 	(void) SECITEM_CopyItem(NULL, result, &signedReq);
     }
 
     if (!result->data) {
 oom:    SECU_PrintError(progName, "out of memory");
 	PORT_SetError(SEC_ERROR_NO_MEMORY);
 	rv = SECFailure;
--- a/security/nss/cmd/checkcert/checkcert.c
+++ b/security/nss/cmd/checkcert/checkcert.c
@@ -215,40 +215,39 @@ CERTCertificate *createEmptyCertificate(
     if (c) {
 	c->referenceCount = 1;
 	c->arena = arena;
     } else {
 	PORT_FreeArena(arena,PR_TRUE);
     }
 
     return c;
-}    
-
-
+}
 
 
 int main(int argc, char **argv)
 {
-    int rv, verbose=0, force=0;
+    int verbose=0, force=0;
     int ascii=0, issuerAscii=0;
     char *progName=0;
     PRFileDesc *inFile=0, *issuerCertFile=0;
     SECItem derCert, derIssuerCert;
     PLArenaPool *arena=0;
     CERTSignedData *signedData=0;
     CERTCertificate *cert=0, *issuerCert=0;
     SECKEYPublicKey *rsapubkey=0;
     SECAlgorithmID md5WithRSAEncryption, md2WithRSAEncryption;
     SECAlgorithmID sha1WithRSAEncryption, rsaEncryption;
     SECItem spk;
     int selfSigned=0;
     int invalid=0;
     char *inFileName = NULL, *issuerCertFileName = NULL;
     PLOptState *optstate;
     PLOptStatus status;
+    SECStatus rv;
 
     PORT_Memset(&md5WithRSAEncryption, 0, sizeof(md5WithRSAEncryption));
     PORT_Memset(&md2WithRSAEncryption, 0, sizeof(md2WithRSAEncryption));
     PORT_Memset(&sha1WithRSAEncryption, 0, sizeof(sha1WithRSAEncryption));
     PORT_Memset(&rsaEncryption, 0, sizeof(rsaEncryption));
 
     progName = strrchr(argv[0], '/');
     progName = progName ? progName+1 : argv[0];
@@ -400,27 +399,47 @@ int main(int argc, char **argv)
     }
 
 
     /* Do various checks on the cert */
 
     printf("\n");
 
     /* Check algorithms */
-    SECOID_SetAlgorithmID(arena, &md5WithRSAEncryption,
+    rv = SECOID_SetAlgorithmID(arena, &md5WithRSAEncryption,
 		       SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, NULL);
+    if (rv) {
+	fprintf(stderr, "%s: failed to set algorithm ID for SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION.\n",
+                progName);
+	exit(1);
+    }
 
-    SECOID_SetAlgorithmID(arena, &md2WithRSAEncryption,
+    rv = SECOID_SetAlgorithmID(arena, &md2WithRSAEncryption,
 		       SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION, NULL);
+    if (rv) {
+	fprintf(stderr, "%s: failed to set algorithm ID for SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION.\n",
+                progName);
+	exit(1);
+    }
 
-    SECOID_SetAlgorithmID(arena, &sha1WithRSAEncryption,
+    rv = SECOID_SetAlgorithmID(arena, &sha1WithRSAEncryption,
 		       SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION, NULL);
+    if (rv) {
+	fprintf(stderr, "%s: failed to set algorithm ID for SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION.\n",
+                progName);
+	exit(1);
+    }
 
-    SECOID_SetAlgorithmID(arena, &rsaEncryption,
+    rv = SECOID_SetAlgorithmID(arena, &rsaEncryption,
 		       SEC_OID_PKCS1_RSA_ENCRYPTION, NULL);
+    if (rv) {
+	fprintf(stderr, "%s: failed to set algorithm ID for SEC_OID_PKCS1_RSA_ENCRYPTION.\n",
+                progName);
+	exit(1);
+    }
 
     {
 	int isMD5RSA = (SECOID_CompareAlgorithmID(&cert->signature,
 					       &md5WithRSAEncryption) == 0);
 	int isMD2RSA = (SECOID_CompareAlgorithmID(&cert->signature,
 					       &md2WithRSAEncryption) == 0);
 	int isSHA1RSA = (SECOID_CompareAlgorithmID(&cert->signature,
 					       &sha1WithRSAEncryption) == 0);
--- a/security/nss/cmd/modutil/install.c
+++ b/security/nss/cmd/modutil/install.c
@@ -115,19 +115,20 @@ static char *msgStrings[] = {
 typedef struct StringNode_str {
     char *str;
     struct StringNode_str* next;
 } StringNode;
 
 StringNode* StringNode_new()
 {
 	StringNode* new_this;
-	new_this = (StringNode*)malloc(sizeof(StringNode));
-  new_this->str=NULL;
-  new_this->next=NULL;
+	new_this = (StringNode*)PR_Malloc(sizeof(StringNode));
+	PORT_Assert(new_this != NULL);
+	new_this->str = NULL;
+	new_this->next = NULL;
 	return new_this;
 }
 
 void StringNode_delete(StringNode* s) 
 {
 	if(s->str) {
 		PR_Free(s->str);
 		s->str=NULL;
--- a/security/nss/cmd/platlibs.mk
+++ b/security/nss/cmd/platlibs.mk
@@ -82,18 +82,18 @@ EXTRA_LIBS += \
 	$(DIST)/lib/$(LIB_PREFIX)certdb.$(LIB_SUFFIX) \
 	$(SOFTOKENLIB) \
 	$(CRYPTOLIB) \
 	$(DIST)/lib/$(LIB_PREFIX)nsspki.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)nssdev.$(LIB_SUFFIX) \
 	$(DIST)/lib/$(LIB_PREFIX)nssb.$(LIB_SUFFIX) \
 	$(PKIXLIB) \
 	$(DBMLIB) \
-	$(DIST)/lib/$(LIB_PREFIX)$(SQLITE_LIB_NAME).$(LIB_SUFFIX) \
-	$(DIST)/lib/$(LIB_PREFIX)nssutil3.$(LIB_SUFFIX) \
+	$(SQLITE_LIB_DIR)/$(LIB_PREFIX)$(SQLITE_LIB_NAME).$(LIB_SUFFIX) \
+	$(NSSUTIL_LIB_DIR)/$(LIB_PREFIX)nssutil3.$(LIB_SUFFIX) \
 	$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plc4.$(LIB_SUFFIX) \
 	$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plds4.$(LIB_SUFFIX) \
 	$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)nspr4.$(LIB_SUFFIX) \
 	$(NULL)
 
 # $(PROGRAM) has NO explicit dependencies on $(OS_LIBS)
 #OS_LIBS += \
 	wsock32.lib \
@@ -130,17 +130,17 @@ EXTRA_LIBS += \
 
 ifeq ($(OS_ARCH), AIX) 
 EXTRA_SHARED_LIBS += -brtl 
 endif
 
 # $(PROGRAM) has NO explicit dependencies on $(EXTRA_SHARED_LIBS)
 # $(EXTRA_SHARED_LIBS) come before $(OS_LIBS), except on AIX.
 EXTRA_SHARED_LIBS += \
-	-L$(DIST)/lib \
+	-L$(SQLITE_LIB_DIR) \
 	-l$(SQLITE_LIB_NAME) \
 	-L$(NSSUTIL_LIB_DIR) \
 	-lnssutil3 \
 	-L$(NSPR_LIB_DIR) \
 	-lplc4 \
 	-lplds4 \
 	-lnspr4 \
 	$(NULL)
@@ -148,17 +148,17 @@ endif
 
 else # USE_STATIC_LIBS
 # can't do this in manifest.mn because OS_ARCH isn't defined there.
 ifeq ($(OS_ARCH), WINNT)
 
 # $(PROGRAM) has explicit dependencies on $(EXTRA_LIBS)
 EXTRA_LIBS += \
 	$(DIST)/lib/$(LIB_PREFIX)sectool.$(LIB_SUFFIX) \
-	$(DIST)/lib/$(IMPORT_LIB_PREFIX)nssutil3$(IMPORT_LIB_SUFFIX) \
+	$(NSSUTIL_LIB_DIR)/$(IMPORT_LIB_PREFIX)nssutil3$(IMPORT_LIB_SUFFIX) \
 	$(DIST)/lib/$(IMPORT_LIB_PREFIX)smime3$(IMPORT_LIB_SUFFIX) \
 	$(DIST)/lib/$(IMPORT_LIB_PREFIX)ssl3$(IMPORT_LIB_SUFFIX) \
 	$(DIST)/lib/$(IMPORT_LIB_PREFIX)nss3$(IMPORT_LIB_SUFFIX) \
 	$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plc4$(IMPORT_LIB_SUFFIX) \
 	$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plds4$(IMPORT_LIB_SUFFIX) \
 	$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)nspr4$(IMPORT_LIB_SUFFIX) \
 	$(NULL)
 
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * 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/coreconf/location.mk
+++ b/security/nss/coreconf/location.mk
@@ -62,13 +62,17 @@ endif
 ifdef SOFTOKEN_INCLUDE_DIR
     INCLUDES += -I$(SOFTOKEN_INCLUDE_DIR)
 endif
 
 ifndef SOFTOKEN_LIB_DIR
     SOFTOKEN_LIB_DIR = $(DIST)/lib
 endif
 
+ifndef SQLITE_LIB_DIR
+    SQLITE_LIB_DIR = $(DIST)/lib
+endif
+
 ifndef SQLITE_LIB_NAME
     SQLITE_LIB_NAME = sqlite3
 endif
 
 MK_LOCATION = included
--- a/security/nss/external_tests/README
+++ b/security/nss/external_tests/README
@@ -16,16 +16,16 @@ work do:
 
 This will run the certutil tests (generating a test db) and
 will finalize with a call to the ssl_gtest
 
 You should be able to run the unit tests manually as:
 
   ssl_gtest -d ${SSLGTESTDIR}
 
-Where $SSLGTESTDIR the directory created by ./all.sh or a manually
-created directory with a database containing a certificate called
-server (with its private keys)
+Where $SSLGTESTDIR is a directory with a database containing:
+ - an RSA certificate called server (with its private key)
+ - an ECDSA certificate called ecdsa (with its private key)
 
+A directory like this is created by ./all.sh and can be found
+in a directory named something like
 
-There is a very trivial set of tests that demonstrate some
-of the features.
-
+  tests_results/security/${hostname}.${NUMBER}/ssl_gtests
--- a/security/nss/external_tests/ssl_gtest/manifest.mn
+++ b/security/nss/external_tests/ssl_gtest/manifest.mn
@@ -3,16 +3,18 @@
 # 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/.
 CORE_DEPTH = ../..
 DEPTH      = ../..
 MODULE = nss
 
 CPPSRCS = \
       ssl_loopback_unittest.cc \
+      ssl_extension_unittest.cc \
+      ssl_skip_unittest.cc \
       ssl_gtest.cc \
       test_io.cc \
       tls_agent.cc \
       tls_connect.cc \
       tls_filter.cc \
       tls_parser.cc \
       $(NULL)
 
new file mode 100644
--- /dev/null
+++ b/security/nss/external_tests/ssl_gtest/ssl_extension_unittest.cc
@@ -0,0 +1,578 @@
+/* -*- 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 "ssl.h"
+#include "sslproto.h"
+
+#include <memory>
+
+#include "tls_parser.h"
+#include "tls_filter.h"
+#include "tls_connect.h"
+
+namespace nss_test {
+
+class TlsExtensionFilter : public TlsHandshakeFilter {
+ protected:
+  virtual bool FilterHandshake(uint16_t version, uint8_t handshake_type,
+                               const DataBuffer& input, DataBuffer* output) {
+    if (handshake_type == kTlsHandshakeClientHello) {
+      TlsParser parser(input);
+      if (!FindClientHelloExtensions(parser, version)) {
+        return false;
+      }
+      return FilterExtensions(parser, input, output);
+    }
+    if (handshake_type == kTlsHandshakeServerHello) {
+      TlsParser parser(input);
+      if (!FindServerHelloExtensions(parser, version)) {
+        return false;
+      }
+      return FilterExtensions(parser, input, output);
+    }
+    return false;
+  }
+
+  virtual bool FilterExtension(uint16_t extension_type,
+                               const DataBuffer& input, DataBuffer* output) = 0;
+
+ public:
+  static bool FindClientHelloExtensions(TlsParser& parser, uint16_t version) {
+    if (!parser.Skip(2 + 32)) { // version + random
+      return false;
+    }
+    if (!parser.SkipVariable(1)) { // session ID
+      return false;
+    }
+    if (IsDtls(version) && !parser.SkipVariable(1)) { // DTLS cookie
+      return false;
+    }
+    if (!parser.SkipVariable(2)) { // cipher suites
+      return false;
+    }
+    if (!parser.SkipVariable(1)) { // compression methods
+      return false;
+    }
+    return true;
+  }
+
+  static bool FindServerHelloExtensions(TlsParser& parser, uint16_t version) {
+    if (!parser.Skip(2 + 32)) { // version + random
+      return false;
+    }
+    if (!parser.SkipVariable(1)) { // session ID
+      return false;
+    }
+    if (!parser.Skip(2)) { // cipher suite
+      return false;
+    }
+    if (NormalizeTlsVersion(version) <= SSL_LIBRARY_VERSION_TLS_1_2) {
+      if (!parser.Skip(1)) { // compression method
+        return false;
+      }
+    }
+    return true;
+  }
+
+ private:
+  bool FilterExtensions(TlsParser& parser,
+                        const DataBuffer& input, DataBuffer* output) {
+    size_t length_offset = parser.consumed();
+    uint32_t all_extensions;
+    if (!parser.Read(&all_extensions, 2)) {
+      return false; // no extensions, odd but OK
+    }
+    if (all_extensions != parser.remaining()) {
+      return false; // malformed
+    }
+
+    bool changed = false;
+
+    // Write out the start of the message.
+    output->Allocate(input.len());
+    output->Write(0, input.data(), parser.consumed());
+    size_t output_offset = parser.consumed();
+
+    while (parser.remaining()) {
+      uint32_t extension_type;
+      if (!parser.Read(&extension_type, 2)) {
+        return false; // malformed
+      }
+
+      // Copy extension type.
+      output->Write(output_offset, extension_type, 2);
+
+      DataBuffer extension;
+      if (!parser.ReadVariable(&extension, 2)) {
+        return false; // malformed
+      }
+      output_offset = ApplyFilter(static_cast<uint16_t>(extension_type), extension,
+                                  output, output_offset + 2, &changed);
+    }
+    output->Truncate(output_offset);
+
+    if (changed) {
+      size_t newlen = output->len() - length_offset - 2;
+      if (newlen >= 0x10000) {
+        return false; // bad: size increased too much
+      }
+      output->Write(length_offset, newlen, 2);
+    }
+    return changed;
+  }
+
+  size_t ApplyFilter(uint16_t extension_type, const DataBuffer& extension,
+                     DataBuffer* output, size_t offset, bool* changed) {
+    const DataBuffer* source = &extension;
+    DataBuffer filtered;
+    if (FilterExtension(extension_type, extension, &filtered) &&
+        filtered.len() < 0x10000) {
+      *changed = true;
+      std::cerr << "extension old: " << extension << std::endl;
+      std::cerr << "extension new: " << filtered << std::endl;
+      source = &filtered;
+    }
+
+    output->Write(offset, source->len(), 2);
+    output->Write(offset + 2, *source);
+    return offset + 2 + source->len();
+  }
+};
+
+class TlsExtensionTruncator : public TlsExtensionFilter {
+ public:
+  TlsExtensionTruncator(uint16_t extension, size_t length)
+      : extension_(extension), length_(length) {}
+  virtual bool FilterExtension(uint16_t extension_type,
+                               const DataBuffer& input, DataBuffer* output) {
+    if (extension_type != extension_) {
+      return false;
+    }
+    if (input.len() <= length_) {
+      return false;
+    }
+
+    output->Assign(input.data(), length_);
+    return true;
+  }
+ private:
+    uint16_t extension_;
+    size_t length_;
+};
+
+class TlsExtensionDamager : public TlsExtensionFilter {
+ public:
+  TlsExtensionDamager(uint16_t extension, size_t index)
+      : extension_(extension), index_(index) {}
+  virtual bool FilterExtension(uint16_t extension_type,
+                               const DataBuffer& input, DataBuffer* output) {
+    if (extension_type != extension_) {
+      return false;
+    }
+
+    *output = input;
+    output->data()[index_] += 73; // Increment selected for maximum damage
+    return true;
+  }
+ private:
+  uint16_t extension_;
+  size_t index_;
+};
+
+class TlsExtensionReplacer : public TlsExtensionFilter {
+ public:
+  TlsExtensionReplacer(uint16_t extension, const DataBuffer& data)
+      : extension_(extension), data_(data) {}
+  virtual bool FilterExtension(uint16_t extension_type,
+                               const DataBuffer& input, DataBuffer* output) {
+    if (extension_type != extension_) {
+      return false;
+    }
+
+    *output = data_;
+    return true;
+  }
+ private:
+  uint16_t extension_;
+  DataBuffer data_;
+};
+
+class TlsExtensionInjector : public TlsHandshakeFilter {
+ public:
+  TlsExtensionInjector(uint16_t ext, DataBuffer& data)
+      : extension_(ext), data_(data) {}
+
+  virtual bool FilterHandshake(uint16_t version, uint8_t handshake_type,
+                               const DataBuffer& input, DataBuffer* output) {
+    size_t offset;
+    if (handshake_type == kTlsHandshakeClientHello) {
+      TlsParser parser(input);
+      if (!TlsExtensionFilter::FindClientHelloExtensions(parser, version)) {
+        return false;
+      }
+      offset = parser.consumed();
+    } else if (handshake_type == kTlsHandshakeServerHello) {
+      TlsParser parser(input);
+      if (!TlsExtensionFilter::FindServerHelloExtensions(parser, version)) {
+        return false;
+      }
+      offset = parser.consumed();
+    } else {
+      return false;
+    }
+
+    *output = input;
+
+    std::cerr << "Pre:" << input << std::endl;
+    std::cerr << "Lof:" << offset << std::endl;
+
+    // Increase the size of the extensions.
+    uint16_t* len_addr = reinterpret_cast<uint16_t*>(output->data() + offset);
+    std::cerr << "L-p:" << ntohs(*len_addr) << std::endl;
+    *len_addr = htons(ntohs(*len_addr) + data_.len() + 4);
+    std::cerr << "L-i:" << ntohs(*len_addr) << std::endl;
+
+
+    // Insert the extension type and length.
+    DataBuffer type_length;
+    type_length.Allocate(4);
+    type_length.Write(0, extension_, 2);
+    type_length.Write(2, data_.len(), 2);
+    output->Splice(type_length, offset + 2);
+
+    // Insert the payload.
+    output->Splice(data_, offset + 6);
+
+    std::cerr << "Aft:" << *output << std::endl;
+    return true;
+  }
+
+ private:
+  uint16_t extension_;
+  DataBuffer data_;
+};
+
+class TlsExtensionTestBase : public TlsConnectTestBase {
+ protected:
+  TlsExtensionTestBase(Mode mode, uint16_t version)
+    : TlsConnectTestBase(mode, version) {}
+
+  void ClientHelloErrorTest(PacketFilter* filter,
+                            uint8_t alert = kTlsAlertDecodeError) {
+    auto alert_recorder = new TlsAlertRecorder();
+    server_->SetPacketFilter(alert_recorder);
+    if (filter) {
+      client_->SetPacketFilter(filter);
+    }
+    ConnectExpectFail();
+    EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
+    EXPECT_EQ(alert, alert_recorder->description());
+  }
+
+  void ServerHelloErrorTest(PacketFilter* filter,
+                            uint8_t alert = kTlsAlertDecodeError) {
+    auto alert_recorder = new TlsAlertRecorder();
+    client_->SetPacketFilter(alert_recorder);
+    if (filter) {
+      server_->SetPacketFilter(filter);
+    }
+    ConnectExpectFail();
+    EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
+    EXPECT_EQ(alert, alert_recorder->description());
+  }
+
+  static void InitSimpleSni(DataBuffer* extension) {
+    const char* name = "host.name";
+    const size_t namelen = PL_strlen(name);
+    extension->Allocate(namelen + 5);
+    extension->Write(0, namelen + 3, 2);
+    extension->Write(2, static_cast<uint32_t>(0), 1); // 0 == hostname
+    extension->Write(3, namelen, 2);
+    extension->Write(5, reinterpret_cast<const uint8_t*>(name), namelen);
+  }
+};
+
+class TlsExtensionTestDtls
+  : public TlsExtensionTestBase,
+    public ::testing::WithParamInterface<uint16_t> {
+ public:
+  TlsExtensionTestDtls() : TlsExtensionTestBase(DGRAM, GetParam()) {}
+};
+
+class TlsExtensionTest12Plus
+  : public TlsExtensionTestBase,
+    public ::testing::WithParamInterface<std::string> {
+ public:
+  TlsExtensionTest12Plus()
+    : TlsExtensionTestBase(TlsConnectTestBase::ToMode(GetParam()),
+                           SSL_LIBRARY_VERSION_TLS_1_2) {}
+};
+
+class TlsExtensionTestGeneric
+  : public TlsExtensionTestBase,
+    public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
+ public:
+  TlsExtensionTestGeneric()
+    : TlsExtensionTestBase(TlsConnectTestBase::ToMode((std::get<0>(GetParam()))),
+                           std::get<1>(GetParam())) {}
+};
+
+TEST_P(TlsExtensionTestGeneric, DamageSniLength) {
+  ClientHelloErrorTest(new TlsExtensionDamager(ssl_server_name_xtn, 1));
+}
+
+TEST_P(TlsExtensionTestGeneric, DamageSniHostLength) {
+  ClientHelloErrorTest(new TlsExtensionDamager(ssl_server_name_xtn, 4));
+}
+
+TEST_P(TlsExtensionTestGeneric, TruncateSni) {
+  ClientHelloErrorTest(new TlsExtensionTruncator(ssl_server_name_xtn, 7));
+}
+
+// A valid extension that appears twice will be reported as unsupported.
+TEST_P(TlsExtensionTestGeneric, RepeatSni) {
+  DataBuffer extension;
+  InitSimpleSni(&extension);
+  ClientHelloErrorTest(new TlsExtensionInjector(ssl_server_name_xtn, extension),
+                       kTlsAlertIllegalParameter);
+}
+
+// An SNI entry with zero length is considered invalid (strangely, not if it is
+// the last entry, which is probably a bug).
+TEST_P(TlsExtensionTestGeneric, BadSni) {
+  DataBuffer simple;
+  InitSimpleSni(&simple);
+  DataBuffer extension;
+  extension.Allocate(simple.len() + 3);
+  extension.Write(0, static_cast<uint32_t>(0), 3);
+  extension.Write(3, simple);
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_server_name_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, EmptyAlpnExtension) {
+  EnableAlpn();
+  DataBuffer extension;
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension),
+                       kTlsAlertIllegalParameter);
+}
+
+// An empty ALPN isn't considered bad, though it does lead to there being no
+// protocol for the server to select.
+TEST_P(TlsExtensionTestGeneric, EmptyAlpnList) {
+  EnableAlpn();
+  const uint8_t val[] = { 0x00, 0x00 };
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension),
+                       kTlsAlertNoApplicationProtocol);
+}
+
+TEST_P(TlsExtensionTestGeneric, OneByteAlpn) {
+  EnableAlpn();
+  ClientHelloErrorTest(new TlsExtensionTruncator(ssl_app_layer_protocol_xtn, 1));
+}
+
+TEST_P(TlsExtensionTestGeneric, AlpnMissingValue) {
+  EnableAlpn();
+  // This will leave the length of the second entry, but no value.
+  ClientHelloErrorTest(new TlsExtensionTruncator(ssl_app_layer_protocol_xtn, 5));
+}
+
+TEST_P(TlsExtensionTestGeneric, AlpnZeroLength) {
+  EnableAlpn();
+  const uint8_t val[] = { 0x01, 0x61, 0x00 };
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, AlpnMismatch) {
+  const uint8_t client_alpn[] = { 0x01, 0x61 };
+  client_->EnableAlpn(client_alpn, sizeof(client_alpn));
+  const uint8_t server_alpn[] = { 0x02, 0x61, 0x62 };
+  server_->EnableAlpn(server_alpn, sizeof(server_alpn));
+
+  ClientHelloErrorTest(nullptr, kTlsAlertNoApplicationProtocol);
+}
+
+TEST_P(TlsExtensionTestGeneric, AlpnReturnedEmptyList) {
+  EnableAlpn();
+  const uint8_t val[] = { 0x00, 0x00 };
+  DataBuffer extension(val, sizeof(val));
+  ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, AlpnReturnedEmptyName) {
+  EnableAlpn();
+  const uint8_t val[] = { 0x00, 0x01, 0x00 };
+  DataBuffer extension(val, sizeof(val));
+  ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, AlpnReturnedListTrailingData) {
+  EnableAlpn();
+  const uint8_t val[] = { 0x00, 0x02, 0x01, 0x61, 0x00 };
+  DataBuffer extension(val, sizeof(val));
+  ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, AlpnReturnedExtraEntry) {
+  EnableAlpn();
+  const uint8_t val[] = { 0x00, 0x04, 0x01, 0x61, 0x01, 0x62 };
+  DataBuffer extension(val, sizeof(val));
+  ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, AlpnReturnedBadListLength) {
+  EnableAlpn();
+  const uint8_t val[] = { 0x00, 0x99, 0x01, 0x61, 0x00 };
+  DataBuffer extension(val, sizeof(val));
+  ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, AlpnReturnedBadNameLength) {
+  EnableAlpn();
+  const uint8_t val[] = { 0x00, 0x02, 0x99, 0x61 };
+  DataBuffer extension(val, sizeof(val));
+  ServerHelloErrorTest(new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+}
+
+TEST_P(TlsExtensionTestDtls, SrtpShort) {
+  EnableSrtp();
+  ClientHelloErrorTest(new TlsExtensionTruncator(ssl_use_srtp_xtn, 3));
+}
+
+TEST_P(TlsExtensionTestDtls, SrtpOdd) {
+  EnableSrtp();
+  const uint8_t val[] = { 0x00, 0x01, 0xff, 0x00 };
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_use_srtp_xtn, extension));
+}
+
+TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsBadLength) {
+  const uint8_t val[] = { 0x00 };
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_signature_algorithms_xtn,
+                                                extension));
+}
+
+TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsTrailingData) {
+  const uint8_t val[] = { 0x00, 0x02, 0x04, 0x01, 0x00 }; // sha-256, rsa
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_signature_algorithms_xtn,
+                                                extension));
+}
+
+TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsEmpty) {
+  const uint8_t val[] = { 0x00, 0x00 };
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_signature_algorithms_xtn,
+                                                extension));
+}
+
+TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsOddLength) {
+  const uint8_t val[] = { 0x00, 0x01, 0x04 };
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_signature_algorithms_xtn,
+                                                extension));
+}
+
+// The extension handling ignores unsupported hashes, so breaking that has no
+// effect on success rates.  However, ssl3_SendServerKeyExchange catches an
+// unsupported signature algorithm.
+
+// This actually fails with a decryption error (fatal alert 51).  That's a bad
+// to fail, since any tampering with the handshake will trigger that alert when
+// verifying the Finished message.  Thus, this test is disabled until this error
+// is turned into an alert.
+TEST_P(TlsExtensionTest12Plus, DISABLED_SignatureAlgorithmsSigUnsupported) {
+  const uint8_t val[] = { 0x00, 0x02, 0x04, 0x99 };
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_signature_algorithms_xtn,
+                                                extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, SupportedCurvesShort) {
+  EnableSomeEcdheCiphers();
+  const uint8_t val[] = { 0x00, 0x01, 0x00 };
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_elliptic_curves_xtn,
+                                                extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, SupportedCurvesBadLength) {
+  EnableSomeEcdheCiphers();
+  const uint8_t val[] = { 0x09, 0x99, 0x00, 0x00 };
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_elliptic_curves_xtn,
+                                                extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, SupportedCurvesTrailingData) {
+  EnableSomeEcdheCiphers();
+  const uint8_t val[] = { 0x00, 0x02, 0x00, 0x00, 0x00 };
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_elliptic_curves_xtn,
+                                                extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, SupportedPointsEmpty) {
+  EnableSomeEcdheCiphers();
+  const uint8_t val[] = { 0x00 };
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_ec_point_formats_xtn,
+                                                extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, SupportedPointsBadLength) {
+  EnableSomeEcdheCiphers();
+  const uint8_t val[] = { 0x99, 0x00, 0x00 };
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_ec_point_formats_xtn,
+                                                extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, SupportedPointsTrailingData) {
+  EnableSomeEcdheCiphers();
+  const uint8_t val[] = { 0x01, 0x00, 0x00 };
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_ec_point_formats_xtn,
+                                                extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, RenegotiationInfoBadLength) {
+  const uint8_t val[] = { 0x99 };
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_renegotiation_info_xtn,
+                                                extension));
+}
+
+TEST_P(TlsExtensionTestGeneric, RenegotiationInfoMismatch) {
+  const uint8_t val[] = { 0x01, 0x00 };
+  DataBuffer extension(val, sizeof(val));
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_renegotiation_info_xtn,
+                                                extension));
+}
+
+// The extension has to contain a length.
+TEST_P(TlsExtensionTestGeneric, RenegotiationInfoExtensionEmpty) {
+  DataBuffer extension;
+  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_renegotiation_info_xtn,
+                                                extension));
+}
+
+INSTANTIATE_TEST_CASE_P(ExtensionTls10, TlsExtensionTestGeneric,
+                        ::testing::Combine(
+                          TlsConnectTestBase::kTlsModesStream,
+                          TlsConnectTestBase::kTlsV10));
+INSTANTIATE_TEST_CASE_P(ExtensionVariants, TlsExtensionTestGeneric,
+                        ::testing::Combine(
+                          TlsConnectTestBase::kTlsModesAll,
+                          TlsConnectTestBase::kTlsV11V12));
+INSTANTIATE_TEST_CASE_P(ExtensionTls12Plus, TlsExtensionTest12Plus,
+                        TlsConnectTestBase::kTlsModesAll);
+INSTANTIATE_TEST_CASE_P(ExtensionDgram, TlsExtensionTestDtls,
+                        TlsConnectTestBase::kTlsV11V12);
+
+}  // namespace nspr_test
--- a/security/nss/external_tests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/security/nss/external_tests/ssl_gtest/ssl_loopback_unittest.cc
@@ -10,17 +10,17 @@
 #include <memory>
 
 #include "tls_parser.h"
 #include "tls_filter.h"
 #include "tls_connect.h"
 
 namespace nss_test {
 
-class TlsServerKeyExchangeECDHE {
+class TlsServerKeyExchangeEcdhe {
  public:
   bool Parse(const DataBuffer& buffer) {
     TlsParser parser(buffer);
 
     uint8_t curve_type;
     if (!parser.Read(&curve_type)) {
       return false;
     }
@@ -39,225 +39,234 @@ class TlsServerKeyExchangeECDHE {
 
   DataBuffer public_key_;
 };
 
 TEST_P(TlsConnectGeneric, SetupOnly) {}
 
 TEST_P(TlsConnectGeneric, Connect) {
   Connect();
-
-  // Check that we negotiated the expected version.
-  if (mode_ == STREAM) {
-    client_->CheckVersion(SSL_LIBRARY_VERSION_TLS_1_0);
-  } else {
-    client_->CheckVersion(SSL_LIBRARY_VERSION_TLS_1_1);
-  }
+  client_->CheckVersion(std::get<1>(GetParam()));
+  client_->CheckAuthType(ssl_auth_rsa);
 }
 
 TEST_P(TlsConnectGeneric, ConnectResumed) {
   ConfigureSessionCache(RESUME_SESSIONID, RESUME_SESSIONID);
   Connect();
 
-  Reset();
+  ResetRsa();
   Connect();
   CheckResumption(RESUME_SESSIONID);
 }
 
 TEST_P(TlsConnectGeneric, ConnectClientCacheDisabled) {
   ConfigureSessionCache(RESUME_NONE, RESUME_SESSIONID);
   Connect();
-  Reset();
+  ResetRsa();
   Connect();
   CheckResumption(RESUME_NONE);
 }
 
 TEST_P(TlsConnectGeneric, ConnectServerCacheDisabled) {
   ConfigureSessionCache(RESUME_SESSIONID, RESUME_NONE);
   Connect();
-  Reset();
+  ResetRsa();
   Connect();
   CheckResumption(RESUME_NONE);
 }
 
 TEST_P(TlsConnectGeneric, ConnectSessionCacheDisabled) {
   ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
   Connect();
-  Reset();
+  ResetRsa();
   Connect();
   CheckResumption(RESUME_NONE);
 }
 
 TEST_P(TlsConnectGeneric, ConnectResumeSupportBoth) {
   // This prefers tickets.
   ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
   Connect();
 
-  Reset();
+  ResetRsa();
   ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
   Connect();
   CheckResumption(RESUME_TICKET);
 }
 
 TEST_P(TlsConnectGeneric, ConnectResumeClientTicketServerBoth) {
   // This causes no resumption because the client needs the
   // session cache to resume even with tickets.
   ConfigureSessionCache(RESUME_TICKET, RESUME_BOTH);
   Connect();
 
-  Reset();
+  ResetRsa();
   ConfigureSessionCache(RESUME_TICKET, RESUME_BOTH);
   Connect();
   CheckResumption(RESUME_NONE);
 }
 
 TEST_P(TlsConnectGeneric, ConnectResumeClientBothTicketServerTicket) {
   // This causes a ticket resumption.
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   Connect();
 
-  Reset();
+  ResetRsa();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   Connect();
   CheckResumption(RESUME_TICKET);
 }
 
 TEST_P(TlsConnectGeneric, ConnectClientServerTicketOnly) {
   // This causes no resumption because the client needs the
   // session cache to resume even with tickets.
   ConfigureSessionCache(RESUME_TICKET, RESUME_TICKET);
   Connect();
 
-  Reset();
+  ResetRsa();
   ConfigureSessionCache(RESUME_TICKET, RESUME_TICKET);
   Connect();
   CheckResumption(RESUME_NONE);
 }
 
 TEST_P(TlsConnectGeneric, ConnectClientBothServerNone) {
   ConfigureSessionCache(RESUME_BOTH, RESUME_NONE);
   Connect();
 
-  Reset();
+  ResetRsa();
   ConfigureSessionCache(RESUME_BOTH, RESUME_NONE);
   Connect();
   CheckResumption(RESUME_NONE);
 }
 
 TEST_P(TlsConnectGeneric, ConnectClientNoneServerBoth) {
   ConfigureSessionCache(RESUME_NONE, RESUME_BOTH);
   Connect();
 
-  Reset();
+  ResetRsa();
   ConfigureSessionCache(RESUME_NONE, RESUME_BOTH);
   Connect();
   CheckResumption(RESUME_NONE);
 }
 
-TEST_P(TlsConnectGeneric, ConnectTLS_1_1_Only) {
+TEST_P(TlsConnectGeneric, ResumeWithHigherVersion) {
   EnsureTlsSetup();
+  ConfigureSessionCache(RESUME_SESSIONID, RESUME_SESSIONID);
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_1);
-
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_1);
-
   Connect();
 
-  client_->CheckVersion(SSL_LIBRARY_VERSION_TLS_1_1);
-}
-
-TEST_P(TlsConnectGeneric, ConnectTLS_1_2_Only) {
+  ResetRsa();
   EnsureTlsSetup();
-  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+  client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_2);
-  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
+  server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_2);
   Connect();
+  CheckResumption(RESUME_NONE);
   client_->CheckVersion(SSL_LIBRARY_VERSION_TLS_1_2);
 }
 
 TEST_P(TlsConnectGeneric, ConnectAlpn) {
   EnableAlpn();
   Connect();
   client_->CheckAlpn(SSL_NEXT_PROTO_SELECTED, "a");
   server_->CheckAlpn(SSL_NEXT_PROTO_NEGOTIATED, "a");
 }
 
-TEST_F(DtlsConnectTest, ConnectSrtp) {
+TEST_P(TlsConnectGeneric, ConnectEcdsa) {
+  ResetEcdsa();
+  Connect();
+  client_->CheckVersion(std::get<1>(GetParam()));
+  client_->CheckAuthType(ssl_auth_ecdsa);
+}
+
+TEST_P(TlsConnectDatagram, ConnectSrtp) {
   EnableSrtp();
   Connect();
   CheckSrtp();
 }
 
-TEST_F(TlsConnectTest, ConnectECDHE) {
-  EnableSomeECDHECiphers();
+TEST_P(TlsConnectStream, ConnectEcdhe) {
+  EnableSomeEcdheCiphers();
   Connect();
   client_->CheckKEAType(ssl_kea_ecdh);
 }
 
-TEST_F(TlsConnectTest, ConnectECDHETwiceReuseKey) {
-  EnableSomeECDHECiphers();
+TEST_P(TlsConnectStream, ConnectEcdheTwiceReuseKey) {
+  EnableSomeEcdheCiphers();
   TlsInspectorRecordHandshakeMessage* i1 =
       new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(i1);
   Connect();
   client_->CheckKEAType(ssl_kea_ecdh);
-  TlsServerKeyExchangeECDHE dhe1;
-  ASSERT_TRUE(dhe1.Parse(i1->buffer()));
+  TlsServerKeyExchangeEcdhe dhe1;
+  EXPECT_TRUE(dhe1.Parse(i1->buffer()));
 
   // Restart
-  Reset();
+  ResetRsa();
   TlsInspectorRecordHandshakeMessage* i2 =
       new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(i2);
-  EnableSomeECDHECiphers();
+  EnableSomeEcdheCiphers();
   ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
   Connect();
   client_->CheckKEAType(ssl_kea_ecdh);
 
-  TlsServerKeyExchangeECDHE dhe2;
-  ASSERT_TRUE(dhe2.Parse(i2->buffer()));
+  TlsServerKeyExchangeEcdhe dhe2;
+  EXPECT_TRUE(dhe2.Parse(i2->buffer()));
 
   // Make sure they are the same.
-  ASSERT_EQ(dhe1.public_key_.len(), dhe2.public_key_.len());
-  ASSERT_TRUE(!memcmp(dhe1.public_key_.data(), dhe2.public_key_.data(),
+  EXPECT_EQ(dhe1.public_key_.len(), dhe2.public_key_.len());
+  EXPECT_TRUE(!memcmp(dhe1.public_key_.data(), dhe2.public_key_.data(),
                       dhe1.public_key_.len()));
 }
 
-TEST_F(TlsConnectTest, ConnectECDHETwiceNewKey) {
-  EnableSomeECDHECiphers();
+TEST_P(TlsConnectStream, ConnectEcdheTwiceNewKey) {
+  EnableSomeEcdheCiphers();
   SECStatus rv =
       SSL_OptionSet(server_->ssl_fd(), SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
-  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(SECSuccess, rv);
   TlsInspectorRecordHandshakeMessage* i1 =
       new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(i1);
   Connect();
   client_->CheckKEAType(ssl_kea_ecdh);
-  TlsServerKeyExchangeECDHE dhe1;
-  ASSERT_TRUE(dhe1.Parse(i1->buffer()));
+  TlsServerKeyExchangeEcdhe dhe1;
+  EXPECT_TRUE(dhe1.Parse(i1->buffer()));
 
   // Restart
-  Reset();
-  EnableSomeECDHECiphers();
+  ResetRsa();
+  EnableSomeEcdheCiphers();
   rv = SSL_OptionSet(server_->ssl_fd(), SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
-  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(SECSuccess, rv);
   TlsInspectorRecordHandshakeMessage* i2 =
       new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(i2);
   ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
   Connect();
   client_->CheckKEAType(ssl_kea_ecdh);
 
-  TlsServerKeyExchangeECDHE dhe2;
-  ASSERT_TRUE(dhe2.Parse(i2->buffer()));
+  TlsServerKeyExchangeEcdhe dhe2;
+  EXPECT_TRUE(dhe2.Parse(i2->buffer()));
 
   // Make sure they are different.
-  ASSERT_FALSE((dhe1.public_key_.len() == dhe2.public_key_.len()) &&
+  EXPECT_FALSE((dhe1.public_key_.len() == dhe2.public_key_.len()) &&
                (!memcmp(dhe1.public_key_.data(), dhe2.public_key_.data(),
                         dhe1.public_key_.len())));
 }
 
-INSTANTIATE_TEST_CASE_P(Variants, TlsConnectGeneric,
-                        ::testing::Values("TLS", "DTLS"));
+INSTANTIATE_TEST_CASE_P(VariantsStream10, TlsConnectGeneric,
+                        ::testing::Combine(
+                          TlsConnectTestBase::kTlsModesStream,
+                          TlsConnectTestBase::kTlsV10));
+INSTANTIATE_TEST_CASE_P(VariantsAll, TlsConnectGeneric,
+                        ::testing::Combine(
+                          TlsConnectTestBase::kTlsModesAll,
+                          TlsConnectTestBase::kTlsV11V12));
+INSTANTIATE_TEST_CASE_P(VersionsDatagram, TlsConnectDatagram,
+                        TlsConnectTestBase::kTlsV11V12);
+INSTANTIATE_TEST_CASE_P(VersionsDatagram, TlsConnectStream,
+                        TlsConnectTestBase::kTlsV11V12);
 
 }  // namespace nspr_test
new file mode 100644
--- /dev/null
+++ b/security/nss/external_tests/ssl_gtest/ssl_skip_unittest.cc
@@ -0,0 +1,167 @@
+/* -*- 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 "sslerr.h"
+
+#include "tls_parser.h"
+#include "tls_filter.h"
+#include "tls_connect.h"
+
+/*
+ * The tests in this file test that the TLS state machine is robust against
+ * attacks that alter the order of handshake messages.
+ *
+ * See <https://www.smacktls.com/smack.pdf> for a description of the problems
+ * that this sort of attack can enable.
+ */
+namespace nss_test {
+
+class TlsHandshakeSkipFilter : public TlsRecordFilter {
+ public:
+  // A TLS record filter that skips handshake messages of the identified type.
+  TlsHandshakeSkipFilter(uint8_t handshake_type)
+      : handshake_type_(handshake_type),
+        skipped_(false) {}
+
+ protected:
+  // Takes a record; if it is a handshake record, it removes the first handshake
+  // message that is of handshake_type_ type.
+  virtual bool FilterRecord(uint8_t content_type, uint16_t version,
+                            const DataBuffer& input, DataBuffer* output) {
+    if (content_type != kTlsHandshakeType) {
+      return false;
+    }
+
+    size_t output_offset = 0U;
+    output->Allocate(input.len());
+
+    TlsParser parser(input);
+    while (parser.remaining()) {
+      size_t start = parser.consumed();
+      uint8_t handshake_type;
+      if (!parser.Read(&handshake_type)) {
+        return false;
+      }
+      uint32_t length;
+      if (!TlsHandshakeFilter::ReadLength(&parser, version, &length)) {
+        return false;
+      }
+
+      if (!parser.Skip(length)) {
+        return false;
+      }
+
+      if (skipped_ || handshake_type != handshake_type_) {
+        size_t entire_length = parser.consumed() - start;
+        output->Write(output_offset, input.data() + start,
+                      entire_length);
+        // DTLS sequence numbers need to be rewritten
+        if (skipped_ && IsDtls(version)) {
+          output->data()[start + 5] -= 1;
+        }
+        output_offset += entire_length;
+      } else {
+        std::cerr << "Dropping handshake: "
+                  << static_cast<unsigned>(handshake_type_) << std::endl;
+        // We only need to report that the output contains changed data if we
+        // drop a handshake message.  But once we've skipped one message, we
+        // have to modify all subsequent handshake messages so that they include
+        // the correct DTLS sequence numbers.
+        skipped_ = true;
+      }
+    }
+    output->Truncate(output_offset);
+    return skipped_;
+  }
+
+ private:
+  // The type of handshake message to drop.
+  uint8_t handshake_type_;
+  // Whether this filter has ever skipped a handshake message.  Track this so
+  // that sequence numbers on DTLS handshake messages can be rewritten in
+  // subsequent calls.
+  bool skipped_;
+};
+
+class TlsSkipTest
+  : public TlsConnectTestBase,
+    public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
+
+ protected:
+  TlsSkipTest()
+    : TlsConnectTestBase(TlsConnectTestBase::ToMode(std::get<0>(GetParam())),
+                         std::get<1>(GetParam())) {}
+
+  void ServerSkipTest(PacketFilter* filter,
+                      uint8_t alert = kTlsAlertUnexpectedMessage) {
+    auto alert_recorder = new TlsAlertRecorder();
+    client_->SetPacketFilter(alert_recorder);
+    if (filter) {
+      server_->SetPacketFilter(filter);
+    }
+    ConnectExpectFail();
+    EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
+    EXPECT_EQ(alert, alert_recorder->description());
+  }
+};
+
+TEST_P(TlsSkipTest, SkipCertificate) {
+  ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
+  client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
+}
+
+TEST_P(TlsSkipTest, SkipCertificateEcdhe) {
+  EnableSomeEcdheCiphers();
+  ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
+  client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH);
+}
+
+TEST_P(TlsSkipTest, SkipCertificateEcdsa) {
+  ResetEcdsa();
+  ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
+  client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH);
+}
+
+TEST_P(TlsSkipTest, SkipServerKeyExchange) {
+  // Have to enable some ephemeral suites, or ServerKeyExchange doesn't appear.
+  EnableSomeEcdheCiphers();
+  ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeServerKeyExchange));
+  client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
+}
+
+TEST_P(TlsSkipTest, SkipServerKeyExchangeEcdsa) {
+  ResetEcdsa();
+  ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeServerKeyExchange));
+  client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
+}
+
+TEST_P(TlsSkipTest, SkipCertAndKeyExch) {
+  auto chain = new ChainedPacketFilter();
+  chain->Add(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
+  chain->Add(new TlsHandshakeSkipFilter(kTlsHandshakeServerKeyExchange));
+  ServerSkipTest(chain);
+  client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
+}
+
+TEST_P(TlsSkipTest, SkipCertAndKeyExchEcdsa) {
+  ResetEcdsa();
+  auto chain = new ChainedPacketFilter();
+  chain->Add(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
+  chain->Add(new TlsHandshakeSkipFilter(kTlsHandshakeServerKeyExchange));
+  ServerSkipTest(chain);
+  client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
+}
+
+INSTANTIATE_TEST_CASE_P(SkipTls10, TlsSkipTest,
+                        ::testing::Combine(
+                          TlsConnectTestBase::kTlsModesStream,
+                          TlsConnectTestBase::kTlsV10));
+INSTANTIATE_TEST_CASE_P(SkipVariants, TlsSkipTest,
+                        ::testing::Combine(
+                          TlsConnectTestBase::kTlsModesAll,
+                          TlsConnectTestBase::kTlsV11V12));
+
+}  // namespace nss_test
--- a/security/nss/external_tests/ssl_gtest/test_io.cc
+++ b/security/nss/external_tests/ssl_gtest/test_io.cc
@@ -323,59 +323,49 @@ int32_t DummyPrSocket::Read(void *data, 
 
 int32_t DummyPrSocket::Recv(void *buf, int32_t buflen) {
   if (input_.empty()) {
     PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
     return -1;
   }
 
   Packet *front = input_.front();
-  if (buflen < front->len()) {
+  if (static_cast<size_t>(buflen) < front->len()) {
     PR_ASSERT(false);
     PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
     return -1;
   }
 
   size_t count = front->len();
   memcpy(buf, front->data(), count);
 
   input_.pop();
   delete front;
 
   return static_cast<int32_t>(count);
 }
 
 int32_t DummyPrSocket::Write(const void *buf, int32_t length) {
-  DataBuffer packet(static_cast<const uint8_t*>(buf),
-                    static_cast<size_t>(length));
-  if (filter_) {
-    DataBuffer filtered;
-    if (filter_->Filter(packet, &filtered)) {
-      if (WriteDirect(filtered) != filtered.len()) {
-        PR_SetError(PR_IO_ERROR, 0);
-        return -1;
-      }
-      LOG("Wrote: " << packet);
-      // libssl can't handle if this reports something other than the length of
-      // what was passed in (or less, but we're not doing partial writes).
-      return packet.len();
-    }
-  }
-
-  return WriteDirect(packet);
-}
-
-int32_t DummyPrSocket::WriteDirect(const DataBuffer& packet) {
   if (!peer_) {
     PR_SetError(PR_IO_ERROR, 0);
     return -1;
   }
 
-  peer_->PacketReceived(packet);
-  return static_cast<int32_t>(packet.len()); // ignore truncation
+  DataBuffer packet(static_cast<const uint8_t*>(buf),
+                    static_cast<size_t>(length));
+  DataBuffer filtered;
+  if (filter_ && filter_->Filter(packet, &filtered)) {
+    LOG("Filtered packet: " << filtered);
+    peer_->PacketReceived(filtered);
+  } else {
+    peer_->PacketReceived(packet);
+  }
+  // libssl can't handle it if this reports something other than the length
+  // of what was passed in (or less, but we're not doing partial writes).
+  return static_cast<int32_t>(packet.len());
 }
 
 Poller *Poller::instance;
 
 Poller *Poller::Instance() {
   if (!instance) instance = new Poller();
 
   return instance;
--- a/security/nss/external_tests/ssl_gtest/test_io.h
+++ b/security/nss/external_tests/ssl_gtest/test_io.h
@@ -7,16 +7,17 @@
 #ifndef test_io_h_
 #define test_io_h_
 
 #include <string.h>
 #include <map>
 #include <memory>
 #include <queue>
 #include <string>
+#include <ostream>
 
 #include "prio.h"
 
 namespace nss_test {
 
 class DataBuffer;
 class Packet;
 class DummyPrSocket;  // Fwd decl.
@@ -31,33 +32,36 @@ class PacketFilter {
   // A filter that modifies the data places the modified data in *output and
   // returns true.  A filter that does not modify data returns false, in which
   // case the value in *output is ignored.
   virtual bool Filter(const DataBuffer& input, DataBuffer* output) = 0;
 };
 
 enum Mode { STREAM, DGRAM };
 
+inline std::ostream& operator<<(std::ostream& os, Mode m) {
+  return os << ((m == STREAM) ? "TLS" : "DTLS");
+}
+
 class DummyPrSocket {
  public:
   ~DummyPrSocket();
 
   static PRFileDesc* CreateFD(const std::string& name,
                               Mode mode);  // Returns an FD.
   static DummyPrSocket* GetAdapter(PRFileDesc* fd);
 
   void SetPeer(DummyPrSocket* peer) { peer_ = peer; }
 
   void SetPacketFilter(PacketFilter* filter) { filter_ = filter; }
 
   void PacketReceived(const DataBuffer& data);
   int32_t Read(void* data, int32_t len);
   int32_t Recv(void* buf, int32_t buflen);
   int32_t Write(const void* buf, int32_t length);
-  int32_t WriteDirect(const DataBuffer& data);
 
   Mode mode() const { return mode_; }
   bool readable() const { return !input_.empty(); }
   bool writable() { return true; }
 
  private:
   DummyPrSocket(const std::string& name, Mode mode)
       : name_(name),
--- a/security/nss/external_tests/ssl_gtest/tls_agent.cc
+++ b/security/nss/external_tests/ssl_gtest/tls_agent.cc
@@ -37,138 +37,158 @@ bool TlsAgent::EnsureTlsSetup() {
     CERTCertificate* cert = PK11_FindCertFromNickname(name_.c_str(), nullptr);
     EXPECT_NE(nullptr, cert);
     if (!cert) return false;
 
     SECKEYPrivateKey* priv = PK11_FindKeyByAnyCert(cert, nullptr);
     EXPECT_NE(nullptr, priv);
     if (!priv) return false;  // Leak cert.
 
-    SECStatus rv = SSL_ConfigSecureServer(ssl_fd_, cert, priv, kt_rsa);
+    SECStatus rv = SSL_ConfigSecureServer(ssl_fd_, cert, priv, kea_);
     EXPECT_EQ(SECSuccess, rv);
     if (rv != SECSuccess) return false;  // Leak cert and key.
 
     SECKEY_DestroyPrivateKey(priv);
     CERT_DestroyCertificate(cert);
 
     rv = SSL_SNISocketConfigHook(ssl_fd_, SniHook,
                                  reinterpret_cast<void*>(this));
     EXPECT_EQ(SECSuccess, rv);  // don't abort, just fail
   } else {
     SECStatus rv = SSL_SetURL(ssl_fd_, "server");
     EXPECT_EQ(SECSuccess, rv);
     if (rv != SECSuccess) return false;
   }
 
-  SECStatus rv = SSL_AuthCertificateHook(ssl_fd_, AuthCertificateHook,
-                                         reinterpret_cast<void*>(this));
+  SECStatus rv = SSL_VersionRangeSet(ssl_fd_, &vrange_);
+  EXPECT_EQ(SECSuccess, rv);
+  if (rv != SECSuccess) return false;
+
+  rv = SSL_AuthCertificateHook(ssl_fd_, AuthCertificateHook,
+                               reinterpret_cast<void*>(this));
   EXPECT_EQ(SECSuccess, rv);
   if (rv != SECSuccess) return false;
 
   return true;
 }
 
 void TlsAgent::StartConnect() {
-  ASSERT_TRUE(EnsureTlsSetup());
+  EXPECT_TRUE(EnsureTlsSetup());
 
   SECStatus rv;
   rv = SSL_ResetHandshake(ssl_fd_, role_ == SERVER ? PR_TRUE : PR_FALSE);
-  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(SECSuccess, rv);
   SetState(CONNECTING);
 }
 
-void TlsAgent::EnableSomeECDHECiphers() {
-  ASSERT_TRUE(EnsureTlsSetup());
+void TlsAgent::EnableSomeEcdheCiphers() {
+  EXPECT_TRUE(EnsureTlsSetup());
 
-  const uint32_t EnabledCiphers[] = {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
-                                     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA};
+  const uint32_t EcdheCiphers[] = {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+                                   TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+                                   TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+                                   TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA};
 
-  for (size_t i = 0; i < PR_ARRAY_SIZE(EnabledCiphers); ++i) {
-    SECStatus rv = SSL_CipherPrefSet(ssl_fd_, EnabledCiphers[i], PR_TRUE);
-    ASSERT_EQ(SECSuccess, rv);
+  for (size_t i = 0; i < PR_ARRAY_SIZE(EcdheCiphers); ++i) {
+    SECStatus rv = SSL_CipherPrefSet(ssl_fd_, EcdheCiphers[i], PR_TRUE);
+    EXPECT_EQ(SECSuccess, rv);
   }
 }
 
 void TlsAgent::SetSessionTicketsEnabled(bool en) {
-  ASSERT_TRUE(EnsureTlsSetup());
+  EXPECT_TRUE(EnsureTlsSetup());
 
   SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_SESSION_TICKETS,
                                en ? PR_TRUE : PR_FALSE);
-  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::SetSessionCacheEnabled(bool en) {
-  ASSERT_TRUE(EnsureTlsSetup());
+  EXPECT_TRUE(EnsureTlsSetup());
 
   SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_NO_CACHE,
                                en ? PR_FALSE : PR_TRUE);
-  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::SetVersionRange(uint16_t minver, uint16_t maxver) {
-  SSLVersionRange range = {minver, maxver};
-  ASSERT_EQ(SECSuccess, SSL_VersionRangeSet(ssl_fd_, &range));
+   vrange_.min = minver;
+   vrange_.max = maxver;
+
+   if (ssl_fd_) {
+     SECStatus rv = SSL_VersionRangeSet(ssl_fd_, &vrange_);
+     EXPECT_EQ(SECSuccess, rv);
+   }
 }
 
 void TlsAgent::CheckKEAType(SSLKEAType type) const {
-  ASSERT_EQ(CONNECTED, state_);
-  ASSERT_EQ(type, csinfo_.keaType);
+  EXPECT_EQ(CONNECTED, state_);
+  EXPECT_EQ(type, csinfo_.keaType);
+}
+
+void TlsAgent::CheckAuthType(SSLAuthType type) const {
+  EXPECT_EQ(CONNECTED, state_);
+  EXPECT_EQ(type, csinfo_.authAlgorithm);
 }
 
 void TlsAgent::CheckVersion(uint16_t version) const {
-  ASSERT_EQ(CONNECTED, state_);
-  ASSERT_EQ(version, info_.protocolVersion);
+  EXPECT_EQ(CONNECTED, state_);
+  EXPECT_EQ(version, info_.protocolVersion);
 }
 
 void TlsAgent::EnableAlpn(const uint8_t* val, size_t len) {
-  ASSERT_TRUE(EnsureTlsSetup());
+  EXPECT_TRUE(EnsureTlsSetup());
 
-  ASSERT_EQ(SECSuccess, SSL_OptionSet(ssl_fd_, SSL_ENABLE_ALPN, PR_TRUE));
-  ASSERT_EQ(SECSuccess, SSL_SetNextProtoNego(ssl_fd_, val, len));
+  EXPECT_EQ(SECSuccess, SSL_OptionSet(ssl_fd_, SSL_ENABLE_ALPN, PR_TRUE));
+  EXPECT_EQ(SECSuccess, SSL_SetNextProtoNego(ssl_fd_, val, len));
 }
 
 void TlsAgent::CheckAlpn(SSLNextProtoState expected_state,
                          const std::string& expected) {
   SSLNextProtoState state;
   char chosen[10];
   unsigned int chosen_len;
   SECStatus rv = SSL_GetNextProto(ssl_fd_, &state,
                                   reinterpret_cast<unsigned char*>(chosen),
                                   &chosen_len, sizeof(chosen));
-  ASSERT_EQ(SECSuccess, rv);
-  ASSERT_EQ(expected_state, state);
-  ASSERT_EQ(expected, std::string(chosen, chosen_len));
+  EXPECT_EQ(SECSuccess, rv);
+  EXPECT_EQ(expected_state, state);
+  EXPECT_EQ(expected, std::string(chosen, chosen_len));
 }
 
 void TlsAgent::EnableSrtp() {
-  ASSERT_TRUE(EnsureTlsSetup());
+  EXPECT_TRUE(EnsureTlsSetup());
   const uint16_t ciphers[] = {
     SRTP_AES128_CM_HMAC_SHA1_80, SRTP_AES128_CM_HMAC_SHA1_32
   };
-  ASSERT_EQ(SECSuccess, SSL_SetSRTPCiphers(ssl_fd_, ciphers,
+  EXPECT_EQ(SECSuccess, SSL_SetSRTPCiphers(ssl_fd_, ciphers,
                                            PR_ARRAY_SIZE(ciphers)));
 
 }
 
 void TlsAgent::CheckSrtp() {
   uint16_t actual;
-  ASSERT_EQ(SECSuccess, SSL_GetSRTPCipher(ssl_fd_, &actual));
-  ASSERT_EQ(SRTP_AES128_CM_HMAC_SHA1_80, actual);
+  EXPECT_EQ(SECSuccess, SSL_GetSRTPCipher(ssl_fd_, &actual));
+  EXPECT_EQ(SRTP_AES128_CM_HMAC_SHA1_80, actual);
 }
 
+void TlsAgent::CheckErrorCode(int32_t expected) const {
+  EXPECT_EQ(ERROR, state_);
+  EXPECT_EQ(expected, error_code_);
+}
 
 void TlsAgent::Handshake() {
   SECStatus rv = SSL_ForceHandshake(ssl_fd_);
   if (rv == SECSuccess) {
     LOG("Handshake success");
     SECStatus rv = SSL_GetChannelInfo(ssl_fd_, &info_, sizeof(info_));
-    ASSERT_EQ(SECSuccess, rv);
+    EXPECT_EQ(SECSuccess, rv);
 
     rv = SSL_GetCipherSuiteInfo(info_.cipherSuite, &csinfo_, sizeof(csinfo_));
-    ASSERT_EQ(SECSuccess, rv);
+    EXPECT_EQ(SECSuccess, rv);
 
     SetState(CONNECTED);
     return;
   }
 
   int32_t err = PR_GetError();
   switch (err) {
     case PR_WOULD_BLOCK_ERROR:
@@ -178,31 +198,32 @@ void TlsAgent::Handshake() {
                                &TlsAgent::ReadableCallback);
       return;
       break;
 
       // TODO(ekr@rtfm.com): needs special case for DTLS
     case SSL_ERROR_RX_MALFORMED_HANDSHAKE:
     default:
       LOG("Handshake failed with error " << err);
+      error_code_ = err;
       SetState(ERROR);
       return;
   }
 }
 
 void TlsAgent::ConfigureSessionCache(SessionResumptionMode mode) {
-  ASSERT_TRUE(EnsureTlsSetup());
+  EXPECT_TRUE(EnsureTlsSetup());
 
   SECStatus rv = SSL_OptionSet(ssl_fd_,
                                SSL_NO_CACHE,
                                mode & RESUME_SESSIONID ?
                                PR_FALSE : PR_TRUE);
-  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(SECSuccess, rv);
 
   rv = SSL_OptionSet(ssl_fd_,
                      SSL_ENABLE_SESSION_TICKETS,
                      mode & RESUME_TICKET ?
                      PR_TRUE : PR_FALSE);
-  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(SECSuccess, rv);
 }
 
 
 } // namespace nss_test
--- a/security/nss/external_tests/ssl_gtest/tls_agent.h
+++ b/security/nss/external_tests/ssl_gtest/tls_agent.h
@@ -9,42 +9,51 @@
 
 #include "prio.h"
 #include "ssl.h"
 
 #include <iostream>
 
 #include "test_io.h"
 
+#define GTEST_HAS_RTTI 0
+#include "gtest/gtest.h"
+
 namespace nss_test {
 
 #define LOG(msg) std::cerr << name_ << ": " << msg << std::endl
 
 enum SessionResumptionMode {
   RESUME_NONE = 0,
   RESUME_SESSIONID = 1,
   RESUME_TICKET = 2,
   RESUME_BOTH = RESUME_SESSIONID | RESUME_TICKET
 };
 
 class TlsAgent : public PollTarget {
  public:
   enum Role { CLIENT, SERVER };
   enum State { INIT, CONNECTING, CONNECTED, ERROR };
 
-  TlsAgent(const std::string& name, Role role, Mode mode)
+  TlsAgent(const std::string& name, Role role, Mode mode, SSLKEAType kea)
       : name_(name),
         mode_(mode),
+        kea_(kea),
         pr_fd_(nullptr),
         adapter_(nullptr),
         ssl_fd_(nullptr),
         role_(role),
-        state_(INIT) {
+        state_(INIT),
+        error_code_(0) {
       memset(&info_, 0, sizeof(info_));
       memset(&csinfo_, 0, sizeof(csinfo_));
+      SECStatus rv = SSL_VersionRangeGetDefault(mode_ == STREAM ?
+                                                ssl_variant_stream : ssl_variant_datagram,
+                                                &vrange_);
+      EXPECT_EQ(SECSuccess, rv);
   }
 
   ~TlsAgent() {
     if (pr_fd_) {
       PR_Close(pr_fd_);
     }
 
     if (ssl_fd_) {
@@ -66,48 +75,59 @@ class TlsAgent : public PollTarget {
 
   void SetPacketFilter(PacketFilter* filter) {
     adapter_->SetPacketFilter(filter);
   }
 
 
   void StartConnect();
   void CheckKEAType(SSLKEAType type) const;
+  void CheckAuthType(SSLAuthType type) const;
   void CheckVersion(uint16_t version) const;
 
   void Handshake();
-  void EnableSomeECDHECiphers();
+  void EnableSomeEcdheCiphers();
   bool EnsureTlsSetup();
 
   void ConfigureSessionCache(SessionResumptionMode mode);
   void SetSessionTicketsEnabled(bool en);
   void SetSessionCacheEnabled(bool en);
   void SetVersionRange(uint16_t minver, uint16_t maxver);
   void EnableAlpn(const uint8_t* val, size_t len);
   void CheckAlpn(SSLNextProtoState expected_state,
                  const std::string& expected);
   void EnableSrtp();
   void CheckSrtp();
+  void CheckErrorCode(int32_t expected) const;
 
   State state() const { return state_; }
 
   const char* state_str() const { return state_str(state()); }
 
   const char* state_str(State state) const { return states[state]; }
 
   PRFileDesc* ssl_fd() { return ssl_fd_; }
 
+  uint16_t min_version() const { return vrange_.min; }
+  uint16_t max_version() const { return vrange_.max; }
+
   bool version(uint16_t* version) const {
     if (state_ != CONNECTED) return false;
 
     *version = info_.protocolVersion;
 
     return true;
   }
 
+  uint16_t version() const {
+    EXPECT_EQ(CONNECTED, state_);
+
+    return info_.protocolVersion;
+  }
+
   bool cipher_suite(int16_t* cipher_suite) const {
     if (state_ != CONNECTED) return false;
 
     *cipher_suite = info_.cipherSuite;
     return true;
   }
 
   std::string cipher_suite_name() const {
@@ -151,20 +171,23 @@ class TlsAgent : public PollTarget {
   static PRInt32 SniHook(PRFileDesc *fd, const SECItem *srvNameArr,
                          PRUint32 srvNameArrSize,
                          void *arg) {
     return SSL_SNI_CURRENT_CONFIG_IS_USED;
   }
 
   const std::string name_;
   Mode mode_;
+  SSLKEAType kea_;
   PRFileDesc* pr_fd_;
   DummyPrSocket* adapter_;
   PRFileDesc* ssl_fd_;
   Role role_;
   State state_;
   SSLChannelInfo info_;
   SSLCipherSuiteInfo csinfo_;
+  SSLVersionRange vrange_;
+  int32_t error_code_;
 };
 
 }  // namespace nss_test
 
 #endif
--- a/security/nss/external_tests/ssl_gtest/tls_connect.cc
+++ b/security/nss/external_tests/ssl_gtest/tls_connect.cc
@@ -3,26 +3,66 @@
 /* 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 "tls_connect.h"
 
 #include <iostream>
 
+#include "sslproto.h"
 #include "gtest_utils.h"
 
 extern std::string g_working_dir_path;
 
 namespace nss_test {
 
-TlsConnectTestBase::TlsConnectTestBase(Mode mode)
+static const std::string kTlsModesStreamArr[] = {"TLS"};
+::testing::internal::ParamGenerator<std::string>
+  TlsConnectTestBase::kTlsModesStream = ::testing::ValuesIn(kTlsModesStreamArr);
+static const std::string kTlsModesAllArr[] = {"TLS", "DTLS"};
+::testing::internal::ParamGenerator<std::string>
+  TlsConnectTestBase::kTlsModesAll = ::testing::ValuesIn(kTlsModesAllArr);
+static const uint16_t kTlsV10Arr[] = {SSL_LIBRARY_VERSION_TLS_1_0};
+::testing::internal::ParamGenerator<uint16_t>
+  TlsConnectTestBase::kTlsV10 = ::testing::ValuesIn(kTlsV10Arr);
+static const uint16_t kTlsV11V12Arr[] = {SSL_LIBRARY_VERSION_TLS_1_1,
+                                         SSL_LIBRARY_VERSION_TLS_1_2};
+::testing::internal::ParamGenerator<uint16_t>
+  TlsConnectTestBase::kTlsV11V12 = ::testing::ValuesIn(kTlsV11V12Arr);
+// TODO: add TLS 1.3
+static const uint16_t kTlsV12PlusArr[] = {SSL_LIBRARY_VERSION_TLS_1_2};
+::testing::internal::ParamGenerator<uint16_t>
+  TlsConnectTestBase::kTlsV12Plus = ::testing::ValuesIn(kTlsV12PlusArr);
+
+static std::string VersionString(uint16_t version) {
+  switch(version) {
+  case 0:
+    return "(no version)";
+  case SSL_LIBRARY_VERSION_TLS_1_0:
+    return "1.0";
+  case SSL_LIBRARY_VERSION_TLS_1_1:
+    return "1.1";
+  case SSL_LIBRARY_VERSION_TLS_1_2:
+    return "1.2";
+  default:
+    std::cerr << "Invalid version: " << version << std::endl;
+    EXPECT_TRUE(false);
+    return "";
+  }
+}
+
+TlsConnectTestBase::TlsConnectTestBase(Mode mode, uint16_t version)
       : mode_(mode),
-        client_(new TlsAgent("client", TlsAgent::CLIENT, mode_)),
-        server_(new TlsAgent("server", TlsAgent::SERVER, mode_)) {}
+        client_(new TlsAgent("client", TlsAgent::CLIENT, mode_, ssl_kea_rsa)),
+        server_(new TlsAgent("server", TlsAgent::SERVER, mode_, ssl_kea_rsa)),
+        version_(version),
+        session_ids_() {
+  std::cerr << "Version: " << mode_ << " " << VersionString(version_) << std::endl;
+}
 
 TlsConnectTestBase::~TlsConnectTestBase() {
   delete client_;
   delete server_;
 }
 
 void TlsConnectTestBase::SetUp() {
   // Configure a fresh session cache.
@@ -39,110 +79,132 @@ void TlsConnectTestBase::TearDown() {
   client_ = nullptr;
   server_ = nullptr;
 
   SSL_ClearSessionCache();
   SSL_ShutdownServerSessionIDCache();
 }
 
 void TlsConnectTestBase::Init() {
-  ASSERT_TRUE(client_->Init());
-  ASSERT_TRUE(server_->Init());
+  EXPECT_TRUE(client_->Init());
+  EXPECT_TRUE(server_->Init());
 
   client_->SetPeer(server_);
   server_->SetPeer(client_);
+
+  if (version_) {
+    client_->SetVersionRange(version_, version_);
+    server_->SetVersionRange(version_, version_);
+  }
 }
 
-void TlsConnectTestBase::Reset() {
+void TlsConnectTestBase::Reset(const std::string& server_name, SSLKEAType kea) {
   delete client_;
   delete server_;
 
-  client_ = new TlsAgent("client", TlsAgent::CLIENT, mode_);
-  server_ = new TlsAgent("server", TlsAgent::SERVER, mode_);
+  client_ = new TlsAgent("client", TlsAgent::CLIENT, mode_, kea);
+  server_ = new TlsAgent(server_name, TlsAgent::SERVER, mode_, kea);
 
   Init();
 }
 
+void TlsConnectTestBase::ResetRsa() {
+  Reset("server", ssl_kea_rsa);
+}
+
+void TlsConnectTestBase::ResetEcdsa() {
+  Reset("ecdsa", ssl_kea_ecdh);
+  EnableSomeEcdheCiphers();
+}
+
 void TlsConnectTestBase::EnsureTlsSetup() {
-  ASSERT_TRUE(client_->EnsureTlsSetup());
-  ASSERT_TRUE(server_->EnsureTlsSetup());
+  EXPECT_TRUE(client_->EnsureTlsSetup());
+  EXPECT_TRUE(server_->EnsureTlsSetup());
 }
 
 void TlsConnectTestBase::Handshake() {
   server_->StartConnect();
   client_->StartConnect();
   client_->Handshake();
   server_->Handshake();
 
-  ASSERT_TRUE_WAIT(client_->state() != TlsAgent::CONNECTING &&
-                   server_->state() != TlsAgent::CONNECTING,
+  ASSERT_TRUE_WAIT((client_->state() != TlsAgent::CONNECTING) &&
+                   (server_->state() != TlsAgent::CONNECTING),
                    5000);
+
 }
 
 void TlsConnectTestBase::Connect() {
   Handshake();
 
-  ASSERT_EQ(TlsAgent::CONNECTED, client_->state());
-  ASSERT_EQ(TlsAgent::CONNECTED, server_->state());
+  // Check the version is as expected
+  EXPECT_EQ(client_->version(), server_->version());
+  EXPECT_EQ(std::min(client_->max_version(),
+                     server_->max_version()),
+            client_->version());
+
+  EXPECT_EQ(TlsAgent::CONNECTED, client_->state());
+  EXPECT_EQ(TlsAgent::CONNECTED, server_->state());
 
   int16_t cipher_suite1, cipher_suite2;
   bool ret = client_->cipher_suite(&cipher_suite1);
-  ASSERT_TRUE(ret);
+  EXPECT_TRUE(ret);
   ret = server_->cipher_suite(&cipher_suite2);
-  ASSERT_TRUE(ret);
-  ASSERT_EQ(cipher_suite1, cipher_suite2);
+  EXPECT_TRUE(ret);
+  EXPECT_EQ(cipher_suite1, cipher_suite2);
 
-  std::cerr << "Connected with cipher suite " << client_->cipher_suite_name()
+  std::cerr << "Connected with version " << client_->version()
+            << " cipher suite " << client_->cipher_suite_name()
             << std::endl;
 
   // Check and store session ids.
   std::vector<uint8_t> sid_c1 = client_->session_id();
-  ASSERT_EQ(32, sid_c1.size());
+  EXPECT_EQ(32U, sid_c1.size());
   std::vector<uint8_t> sid_s1 = server_->session_id();
-  ASSERT_EQ(32, sid_s1.size());
-  ASSERT_EQ(sid_c1, sid_s1);
+  EXPECT_EQ(32U, sid_s1.size());
+  EXPECT_EQ(sid_c1, sid_s1);
   session_ids_.push_back(sid_c1);
 }
 
 void TlsConnectTestBase::ConnectExpectFail() {
   Handshake();
 
   ASSERT_EQ(TlsAgent::ERROR, client_->state());
   ASSERT_EQ(TlsAgent::ERROR, server_->state());
 }
 
-void TlsConnectTestBase::EnableSomeECDHECiphers() {
-  client_->EnableSomeECDHECiphers();
-  server_->EnableSomeECDHECiphers();
+void TlsConnectTestBase::EnableSomeEcdheCiphers() {
+  client_->EnableSomeEcdheCiphers();
+  server_->EnableSomeEcdheCiphers();
 }
 
 
 void TlsConnectTestBase::ConfigureSessionCache(SessionResumptionMode client,
                                                SessionResumptionMode server) {
   client_->ConfigureSessionCache(client);
   server_->ConfigureSessionCache(server);
 }
 
 void TlsConnectTestBase::CheckResumption(SessionResumptionMode expected) {
-  ASSERT_NE(RESUME_BOTH, expected);
+  EXPECT_NE(RESUME_BOTH, expected);
 
   int resume_ct = expected ? 1 : 0;
   int stateless_ct = (expected & RESUME_TICKET) ? 1 : 0;
 
   SSL3Statistics* stats = SSL_GetStatistics();
-  ASSERT_EQ(resume_ct, stats->hch_sid_cache_hits);
-  ASSERT_EQ(resume_ct, stats->hsh_sid_cache_hits);
+  EXPECT_EQ(resume_ct, stats->hch_sid_cache_hits);
+  EXPECT_EQ(resume_ct, stats->hsh_sid_cache_hits);
 
-  ASSERT_EQ(stateless_ct, stats->hch_sid_stateless_resumes);
-  ASSERT_EQ(stateless_ct, stats->hsh_sid_stateless_resumes);
+  EXPECT_EQ(stateless_ct, stats->hch_sid_stateless_resumes);
+  EXPECT_EQ(stateless_ct, stats->hsh_sid_stateless_resumes);
 
   if (resume_ct) {
     // Check that the last two session ids match.
-    ASSERT_GE(2, session_ids_.size());
-    ASSERT_EQ(session_ids_[session_ids_.size()-1],
+    EXPECT_GE(2U, session_ids_.size());
+    EXPECT_EQ(session_ids_[session_ids_.size()-1],
               session_ids_[session_ids_.size()-2]);
   }
 }
 
 void TlsConnectTestBase::EnableAlpn() {
   // A simple value of "a", "b".  Note that the preferred value of "a" is placed
   // at the end, because the NSS API follows the now defunct NPN specification,
   // which places the preferred (and default) entry at the end of the list.
@@ -158,13 +220,12 @@ void TlsConnectTestBase::EnableSrtp() {
 }
 
 void TlsConnectTestBase::CheckSrtp() {
   client_->CheckSrtp();
   server_->CheckSrtp();
 }
 
 TlsConnectGeneric::TlsConnectGeneric()
-    : TlsConnectTestBase((GetParam() == "TLS") ? STREAM : DGRAM) {
-  std::cerr << "Variant: " << GetParam() << std::endl;
-}
+  : TlsConnectTestBase(TlsConnectTestBase::ToMode(std::get<0>(GetParam())),
+                       std::get<1>(GetParam())) {}
 
 } // namespace nss_test
--- a/security/nss/external_tests/ssl_gtest/tls_connect.h
+++ b/security/nss/external_tests/ssl_gtest/tls_connect.h
@@ -2,78 +2,101 @@
 /* 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/. */
 
 #ifndef tls_connect_h_
 #define tls_connect_h_
 
+#include <tuple>
+
 #include "sslt.h"
 
 #include "tls_agent.h"
 
 #define GTEST_HAS_RTTI 0
 #include "gtest/gtest.h"
 
 namespace nss_test {
 
 // A generic TLS connection test base.
 class TlsConnectTestBase : public ::testing::Test {
  public:
-  TlsConnectTestBase(Mode mode);
+  static ::testing::internal::ParamGenerator<std::string> kTlsModesStream;
+  static ::testing::internal::ParamGenerator<std::string> kTlsModesAll;
+  static ::testing::internal::ParamGenerator<uint16_t> kTlsV10;
+  static ::testing::internal::ParamGenerator<uint16_t> kTlsV11V12;
+  static ::testing::internal::ParamGenerator<uint16_t> kTlsV12Plus;
+
+  static inline Mode ToMode(const std::string& str) {
+    return str == "TLS" ? STREAM : DGRAM;
+  }
+
+  TlsConnectTestBase(Mode mode, uint16_t version);
   virtual ~TlsConnectTestBase();
 
   void SetUp();
   void TearDown();
 
   // Initialize client and server.
   void Init();
-  // Re-initialize client and server.
-  void Reset();
+  // Re-initialize client and server with the default RSA cert.
+  void ResetRsa();
+  // Re-initialize client and server with an ECDSA cert on the server
+  // and some ECDHE suites.
+  void ResetEcdsa();
   // Make sure TLS is configured for a connection.
   void EnsureTlsSetup();
 
   // Run the handshake.
   void Handshake();
   // Connect and check that it works.
   void Connect();
   // Connect and expect it to fail.
   void ConnectExpectFail();
 
-  void EnableSomeECDHECiphers();
+  void EnableSomeEcdheCiphers();
   void ConfigureSessionCache(SessionResumptionMode client,
                              SessionResumptionMode server);
   void CheckResumption(SessionResumptionMode expected);
   void EnableAlpn();
   void EnableSrtp();
   void CheckSrtp();
+ protected:
 
- protected:
   Mode mode_;
   TlsAgent* client_;
   TlsAgent* server_;
+  uint16_t version_;
   std::vector<std::vector<uint8_t>> session_ids_;
+
+ private:
+  void Reset(const std::string& server_name, SSLKEAType kea);
 };
 
 // A TLS-only test base.
-class TlsConnectTest : public TlsConnectTestBase {
+class TlsConnectStream : public TlsConnectTestBase,
+                         public ::testing::WithParamInterface<uint16_t> {
  public:
-  TlsConnectTest() : TlsConnectTestBase(STREAM) {}
+  TlsConnectStream() : TlsConnectTestBase(STREAM, GetParam()) {}
 };
 
 // A DTLS-only test base.
-class DtlsConnectTest : public TlsConnectTestBase {
+class TlsConnectDatagram : public TlsConnectTestBase,
+                           public ::testing::WithParamInterface<uint16_t> {
  public:
-  DtlsConnectTest() : TlsConnectTestBase(DGRAM) {}
+  TlsConnectDatagram() : TlsConnectTestBase(DGRAM, GetParam()) {}
 };
 
-// A generic test class that can be either STREAM or DGRAM.  This is configured
-// in ssl_loopback_unittest.cc.  All uses of this should use TEST_P().
-class TlsConnectGeneric : public TlsConnectTestBase,
-                          public ::testing::WithParamInterface<std::string> {
+// A generic test class that can be either STREAM or DGRAM and a single version
+// of TLS.  This is configured in ssl_loopback_unittest.cc.  All uses of this
+// should use TEST_P().
+class TlsConnectGeneric
+  : public TlsConnectTestBase,
+    public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
  public:
   TlsConnectGeneric();
 };
 
 } // namespace nss_test
 
 #endif
--- a/security/nss/external_tests/ssl_gtest/tls_filter.cc
+++ b/security/nss/external_tests/ssl_gtest/tls_filter.cc
@@ -62,17 +62,17 @@ size_t TlsRecordFilter::ApplyFilter(uint
                                     DataBuffer* output,
                                     size_t offset, bool* changed) {
   const DataBuffer* source = &record;
   DataBuffer filtered;
   if (FilterRecord(content_type, version, record, &filtered) &&
       filtered.len() < 0x10000) {
     *changed = true;
     std::cerr << "record old: " << record << std::endl;
-    std::cerr << "record old: " << filtered << std::endl;
+    std::cerr << "record new: " << filtered << std::endl;
     source = &filtered;
   }
 
   output->Write(offset, source->len(), 2);
   output->Write(offset + 2, *source);
   return offset + 2 + source->len();
 }
 
@@ -91,21 +91,17 @@ bool TlsHandshakeFilter::FilterRecord(ui
   TlsParser parser(input);
   while (parser.remaining()) {
     size_t start = parser.consumed();
     uint8_t handshake_type;
     if (!parser.Read(&handshake_type)) {
       return false; // malformed
     }
     uint32_t length;
-    if (!parser.Read(&length, 3)) {
-      return false; // malformed
-    }
-
-    if (IsDtls(version) && !CheckDtls(parser, length)) {
+    if (!ReadLength(&parser, version, &length)) {
       return false;
     }
 
     size_t header_len = parser.consumed() - start;
     output->Write(output_offset, input.data() + start, header_len);
 
     DataBuffer handshake;
     if (!parser.Read(&handshake, length)) {
@@ -120,34 +116,42 @@ bool TlsHandshakeFilter::FilterRecord(ui
                                 output, output_offset + 1,
                                 output_offset + header_len,
                                 &changed);
   }
   output->Truncate(output_offset);
   return changed;
 }
 
-bool TlsHandshakeFilter::CheckDtls(TlsParser& parser, size_t length) {
+bool TlsHandshakeFilter::ReadLength(TlsParser* parser, uint16_t version, uint32_t *length) {
+  if (!parser->Read(length, 3)) {
+    return false; // malformed
+  }
+
+  if (!IsDtls(version)) {
+    return true; // nothing left to do
+  }
+
   // Read and check DTLS parameters
-  if (!parser.Skip(2)) { // sequence number
+  if (!parser->Skip(2)) { // sequence number
     return false;
   }
 
   uint32_t fragment_offset;
-  if (!parser.Read(&fragment_offset, 3)) {
+  if (!parser->Read(&fragment_offset, 3)) {
     return false;
   }
 
   uint32_t fragment_length;
-  if (!parser.Read(&fragment_length, 3)) {
+  if (!parser->Read(&fragment_length, 3)) {
     return false;
   }
 
   // All current tests where we are using this code don't fragment.
-  return (fragment_offset == 0 && fragment_length == length);
+  return (fragment_offset == 0 && fragment_length == *length);
 }
 
 size_t TlsHandshakeFilter::ApplyFilter(
     uint16_t version, uint8_t handshake_type, const DataBuffer& handshake,
     DataBuffer* output, size_t length_offset, size_t value_offset,
     bool* changed) {
   const DataBuffer* source = &handshake;
   DataBuffer filtered;
@@ -187,16 +191,18 @@ bool TlsAlertRecorder::FilterRecord(uint
                                     const DataBuffer& input, DataBuffer* output) {
   if (level_ == kTlsAlertFatal) { // already fatal
     return false;
   }
   if (content_type != kTlsAlertType) {
     return false;
   }
 
+  std::cerr << "Alert: " << input << std::endl;
+
   TlsParser parser(input);
   uint8_t lvl;
   if (!parser.Read(&lvl)) {
     return false;
   }
   if (lvl == kTlsAlertWarning) { // not strong enough
     return false;
   }
--- a/security/nss/external_tests/ssl_gtest/tls_filter.h
+++ b/security/nss/external_tests/ssl_gtest/tls_filter.h
@@ -38,24 +38,27 @@ class TlsRecordFilter : public PacketFil
 
 // Abstract filter that operates on handshake messages rather than records.
 // This assumes that the handshake messages are written in a block as entire
 // records and that they don't span records or anything crazy like that.
 class TlsHandshakeFilter : public TlsRecordFilter {
  public:
   TlsHandshakeFilter() {}
 
+  // Reads the length from the record header.
+  // This also reads the DTLS fragment information and checks it.
+  static bool ReadLength(TlsParser* parser, uint16_t version, uint32_t *length);
+
  protected:
   virtual bool FilterRecord(uint8_t content_type, uint16_t version,
                             const DataBuffer& input, DataBuffer* output);
   virtual bool FilterHandshake(uint16_t version, uint8_t handshake_type,
                                const DataBuffer& input, DataBuffer* output) = 0;
 
  private:
-  bool CheckDtls(TlsParser& parser, size_t length);
   size_t ApplyFilter(uint16_t version, uint8_t handshake_type,
                      const DataBuffer& record, DataBuffer* output,
                      size_t length_offset, size_t value_offset, bool* changed);
 };
 
 // Make a copy of the first instance of a handshake message.
 class TlsInspectorRecordHandshakeMessage : public TlsHandshakeFilter {
  public:
--- a/security/nss/external_tests/ssl_gtest/tls_parser.h
+++ b/security/nss/external_tests/ssl_gtest/tls_parser.h
@@ -10,33 +10,34 @@
 #include <memory>
 #include <cstdint>
 #include <cstring>
 #include <arpa/inet.h>
 #include "databuffer.h"
 
 namespace nss_test {
 
-const uint8_t kTlsChangeCipherSpecType = 0x14;
-const uint8_t kTlsAlertType = 0x15;
-const uint8_t kTlsHandshakeType = 0x16;
+const uint8_t kTlsChangeCipherSpecType = 20;
+const uint8_t kTlsAlertType = 21;
+const uint8_t kTlsHandshakeType = 22;
 
-const uint8_t kTlsHandshakeClientHello = 0x01;
-const uint8_t kTlsHandshakeServerHello = 0x02;
-const uint8_t kTlsHandshakeCertificate = 0x0b;
-const uint8_t kTlsHandshakeServerKeyExchange = 0x0c;
+const uint8_t kTlsHandshakeClientHello = 1;
+const uint8_t kTlsHandshakeServerHello = 2;
+const uint8_t kTlsHandshakeCertificate = 11;
+const uint8_t kTlsHandshakeServerKeyExchange = 12;
 
 const uint8_t kTlsAlertWarning = 1;
 const uint8_t kTlsAlertFatal = 2;
 
-const uint8_t kTlsAlertHandshakeFailure = 0x28;
-const uint8_t kTlsAlertIllegalParameter = 0x2f;
-const uint8_t kTlsAlertDecodeError = 0x32;
-const uint8_t kTlsAlertUnsupportedExtension = 0x6e;
-const uint8_t kTlsAlertNoApplicationProtocol = 0x78;
+const uint8_t kTlsAlertUnexpectedMessage = 10;
+const uint8_t kTlsAlertHandshakeFailure = 40;
+const uint8_t kTlsAlertIllegalParameter = 47;
+const uint8_t kTlsAlertDecodeError = 50;
+const uint8_t kTlsAlertUnsupportedExtension = 110;
+const uint8_t kTlsAlertNoApplicationProtocol = 120;
 
 const uint8_t kTlsFakeChangeCipherSpec[] = {
     kTlsChangeCipherSpecType,        // Type
     0xfe,                     0xff,  // Version
     0x00,                     0x00, 0x00, 0x00,
     0x00,                     0x00, 0x00, 0x10,  // Fictitious sequence #
     0x00,                     0x01,              // Length
     0x01                                         // Value
--- a/security/nss/lib/certdb/cert.h
+++ b/security/nss/lib/certdb/cert.h
@@ -1167,16 +1167,30 @@ extern CERTPrivKeyUsagePeriod *
 CERT_DecodePrivKeyUsagePeriodExtension(PLArenaPool *arena, SECItem *extnValue);
 
 extern CERTGeneralName *
 CERT_GetNextGeneralName(CERTGeneralName *current);
 
 extern CERTGeneralName *
 CERT_GetPrevGeneralName(CERTGeneralName *current);
 
+/*
+ * Look up name constraints for some certs that do not include name constraints
+ * (Most importantly, root certificates)
+ *
+ * If a matching subject is found, |extensions| will be populated with a copy of the
+ * DER-encoded name constraints extension. The data in |extensions| will point to
+ * memory that the caller owns.
+ *
+ * There is no mechanism to configure imposed name constraints right now.  All
+ * imposed name constraints are built into NSS.
+ */
+SECStatus
+CERT_GetImposedNameConstraints(const SECItem *derSubject, SECItem *extensions);
+
 CERTNameConstraint *
 CERT_GetNextNameConstraint(CERTNameConstraint *current);
 
 CERTNameConstraint *
 CERT_GetPrevNameConstraint(CERTNameConstraint *current);
 
 void
 CERT_DestroyUserNotice(CERTUserNotice *userNotice);
@@ -1538,16 +1552,19 @@ CERT_CopyNameConstraint(PLArenaPool     
  */
 extern SECStatus
 CERT_CheckNameSpace(PLArenaPool          *arena,
 		    const CERTNameConstraints *constraints,
 		    const CERTGeneralName *currentName);
 
 /*
  * Extract and allocate the name constraints extension from the CA cert.
+ * If the certificate contains no name constraints extension, but
+ * CERT_GetImposedNameConstraints returns a name constraints extension
+ * for the subject of the certificate, then that extension will be returned.
  */
 extern SECStatus
 CERT_FindNameConstraintsExten(PLArenaPool      *arena,
 			      CERTCertificate  *cert,
 			      CERTNameConstraints **constraints);
 
 /*
  * Initialize a new GERTGeneralName fields (link)
--- a/security/nss/lib/certdb/certt.h
+++ b/security/nss/lib/certdb/certt.h
@@ -181,17 +181,17 @@ struct CERTSubjectListStr {
 };
 
 /*
 ** An X.509 certificate object (the unsigned form)
 */
 struct CERTCertificateStr {
     /* the arena is used to allocate any data structures that have the same
      * lifetime as the cert.  This is all stuff that hangs off of the cert
-     * structure, and is all freed at the same time.  I is used when the
+     * structure, and is all freed at the same time.  It is used when the
      * cert is decoded, destroyed, and at some times when it changes
      * state
      */
     PLArenaPool *arena;
 
     /* The following fields are static after the cert has been decoded */
     char *subjectName;
     char *issuerName;
--- a/security/nss/lib/certdb/genname.c
+++ b/security/nss/lib/certdb/genname.c
@@ -1551,86 +1551,108 @@ done:
     if (rv == SECFailure) {
         PORT_ArenaRelease(arena, mark);
     } else {
         PORT_ArenaUnmark(arena, mark);
     }
     return rv;
 }
 
-/* Add name constraints to certain certs that do not include name constraints
- * This is the core of the implementation for bug 952572.
+/*
+ * Here we define a list of name constraints to be imposed on
+ * certain certificates, most importantly root certificates.
+ *
+ * Each entry in the name constraints list is constructed with this
+ * macro.  An entry contains two SECItems, which have names in
+ * specific forms to make the macro work:
+ *
+ *  * ${CA}_SUBJECT_DN - The subject DN for which the constraints
+ *                       should be applied
+ *  * ${CA}_NAME_CONSTRAINTS - The name constraints extension
+ *
+ * Entities subject to name constraints are identified by subject name
+ * so that we can cover all certificates for that entity, including, e.g.,
+ * cross-certificates.  We use subject rather than public key because
+ * calling methods often have easy access to that field (vs., say, a key ID),
+ * and in practice, subject names and public keys are usually in one-to-one
+ * correspondence anyway.
+ *
  */
 
-static SECStatus
-getNameExtensionsBuiltIn(CERTCertificate  *cert,
-                         SECItem *extensions)
+#define STRING_TO_SECITEM(str) \
+{ siBuffer, (unsigned char*) str, sizeof(str) - 1 }
+
+#define NAME_CONSTRAINTS_ENTRY(CA)  \
+    { \
+        STRING_TO_SECITEM(CA ## _SUBJECT_DN), \
+        STRING_TO_SECITEM(CA ## _NAME_CONSTRAINTS) \
+    }
+
+/* Agence Nationale de la Securite des Systemes d'Information (ANSSI) */
+
+#define ANSSI_SUBJECT_DN \
+    "\x30\x81\x85"                                                     \
+    "\x31\x0B\x30\x09\x06\x03\x55\x04\x06\x13\x02" "FR"       /* C */  \
+    "\x31\x0F\x30\x0D\x06\x03\x55\x04\x08\x13\x06" "France"   /* ST */ \
+    "\x31\x0E\x30\x0C\x06\x03\x55\x04\x07\x13\x05" "Paris"    /* L */  \
+    "\x31\x10\x30\x0E\x06\x03\x55\x04\x0A\x13\x07" "PM/SGDN"  /* O */  \
+    "\x31\x0E\x30\x0C\x06\x03\x55\x04\x0B\x13\x05" "DCSSI"    /* OU */ \
+    "\x31\x0E\x30\x0C\x06\x03\x55\x04\x03\x13\x05" "IGC/A"    /* CN */ \
+    "\x31\x23\x30\x21\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x01"     \
+    "\x16\x14" "igca@sgdn.pm.gouv.fr" /* emailAddress */ \
+
+#define ANSSI_NAME_CONSTRAINTS \
+    "\x30\x5D\xA0\x5B"       \
+    "\x30\x05\x82\x03" ".fr" \
+    "\x30\x05\x82\x03" ".gp" \
+    "\x30\x05\x82\x03" ".gf" \
+    "\x30\x05\x82\x03" ".mq" \
+    "\x30\x05\x82\x03" ".re" \
+    "\x30\x05\x82\x03" ".yt" \
+    "\x30\x05\x82\x03" ".pm" \
+    "\x30\x05\x82\x03" ".bl" \
+    "\x30\x05\x82\x03" ".mf" \
+    "\x30\x05\x82\x03" ".wf" \
+    "\x30\x05\x82\x03" ".pf" \
+    "\x30\x05\x82\x03" ".nc" \
+    "\x30\x05\x82\x03" ".tf" \
+
+static const SECItem builtInNameConstraints[][2] = {
+    NAME_CONSTRAINTS_ENTRY(ANSSI)
+};
+
+SECStatus
+CERT_GetImposedNameConstraints(const SECItem *derSubject,
+                               SECItem *extensions)
 {
-  const char constraintFranceGov[] = "\x30\x5D" /* sequence len = 93*/
-                                     "\xA0\x5B" /* element len =91 */
-                                     "\x30\x05" /* sequence len 5 */
-                                     "\x82\x03" /* entry len 3 */
-                                     ".fr"
-                                     "\x30\x05\x82\x03" /* sequence len5, entry len 3 */
-                                     ".gp"
-                                     "\x30\x05\x82\x03"
-                                     ".gf"
-                                     "\x30\x05\x82\x03"
-                                     ".mq"
-                                     "\x30\x05\x82\x03"
-                                     ".re"
-                                     "\x30\x05\x82\x03"
-                                     ".yt"
-                                     "\x30\x05\x82\x03"
-                                     ".pm"
-                                     "\x30\x05\x82\x03"
-                                     ".bl"
-                                     "\x30\x05\x82\x03"
-                                     ".mf"
-                                     "\x30\x05\x82\x03"
-                                     ".wf"
-                                     "\x30\x05\x82\x03"
-                                     ".pf"
-                                     "\x30\x05\x82\x03"
-                                     ".nc"
-                                     "\x30\x05\x82\x03"
-                                     ".tf";
+    size_t i;
+
+    if (!extensions) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
 
-  /* The stringified value for the subject is:
-     E=igca@sgdn.pm.gouv.fr,CN=IGC/A,OU=DCSSI,O=PM/SGDN,L=Paris,ST=France,C=FR
-   */
-  const char rawANSSISubject[] = "\x30\x81\x85\x31\x0B\x30\x09\x06\x03\x55\x04"
-                                 "\x06\x13\x02\x46\x52\x31\x0F\x30\x0D\x06\x03"
-                                 "\x55\x04\x08\x13\x06\x46\x72\x61\x6E\x63\x65"
-                                 "\x31\x0E\x30\x0C\x06\x03\x55\x04\x07\x13\x05"
-                                 "\x50\x61\x72\x69\x73\x31\x10\x30\x0E\x06\x03"
-                                 "\x55\x04\x0A\x13\x07\x50\x4D\x2F\x53\x47\x44"
-                                 "\x4E\x31\x0E\x30\x0C\x06\x03\x55\x04\x0B\x13"
-                                 "\x05\x44\x43\x53\x53\x49\x31\x0E\x30\x0C\x06"
-                                 "\x03\x55\x04\x03\x13\x05\x49\x47\x43\x2F\x41"
-                                 "\x31\x23\x30\x21\x06\x09\x2A\x86\x48\x86\xF7"
-                                 "\x0D\x01\x09\x01\x16\x14\x69\x67\x63\x61\x40"
-                                 "\x73\x67\x64\x6E\x2E\x70\x6D\x2E\x67\x6F\x75"
-                                 "\x76\x2E\x66\x72";
+    for (i = 0; i < PR_ARRAY_SIZE(builtInNameConstraints); ++i) {
+        if (SECITEM_ItemsAreEqual(derSubject, &builtInNameConstraints[i][0])) {
+            return SECITEM_CopyItem(NULL,
+                                    extensions, 
+                                    &builtInNameConstraints[i][1]);
+        }
+    }
 
-  const SECItem anssi_subject = {0, (unsigned char *) rawANSSISubject,
-                                 sizeof(rawANSSISubject)-1};
-  const SECItem permitFranceGovNC = {0, (unsigned char *) constraintFranceGov,
-                                     sizeof(constraintFranceGov)-1};
-
-  if (SECITEM_ItemsAreEqual(&cert->derSubject, &anssi_subject)) {
-    SECStatus rv;
-    rv = SECITEM_CopyItem(NULL, extensions, &permitFranceGovNC);
-    return rv;
-  }
-  PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
-  return SECFailure;
+    PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
+    return SECFailure;
 }
 
-/* Extract the name constraints extension from the CA cert. */
+/* 
+ * Extract the name constraints extension from the CA cert.
+ * If the certificate contains no name constraints extension, but
+ * CERT_GetImposedNameConstraints returns a name constraints extension
+ * for the subject of the certificate, then that extension will be returned.
+ */
 SECStatus
 CERT_FindNameConstraintsExten(PLArenaPool      *arena,
                               CERTCertificate  *cert,
                               CERTNameConstraints **constraints)
 {
     SECStatus            rv = SECSuccess;
     SECItem              constraintsExtension;
     void                *mark = NULL;
@@ -1638,17 +1660,18 @@ CERT_FindNameConstraintsExten(PLArenaPoo
     *constraints = NULL;
 
     rv = CERT_FindCertExtension(cert, SEC_OID_X509_NAME_CONSTRAINTS, 
                                 &constraintsExtension);
     if (rv != SECSuccess) {
         if (PORT_GetError() != SEC_ERROR_EXTENSION_NOT_FOUND) {
             return rv;
         }
-        rv = getNameExtensionsBuiltIn(cert, &constraintsExtension);
+        rv = CERT_GetImposedNameConstraints(&cert->derSubject,
+                                            &constraintsExtension);
         if (rv != SECSuccess) {
           if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) {
             return SECSuccess;
           }
           return rv;
         }
     }
 
--- a/security/nss/lib/ckfw/builtins/config.mk
+++ b/security/nss/lib/ckfw/builtins/config.mk
@@ -25,13 +25,10 @@ endif
 
 # Needed for compilation of $(OBJDIR)/certdata.c
 INCLUDES += -I.
 
 #
 # To create a loadable module on Darwin, we must use -bundle.
 #
 ifeq ($(OS_TARGET),Darwin)
-ifndef USE_64
 DSO_LDOPTS = -bundle
 endif
-endif
-
--- a/security/nss/lib/ckfw/capi/config.mk
+++ b/security/nss/lib/ckfw/capi/config.mk
@@ -22,13 +22,10 @@ endif
 ifdef BUILD_IDG
     DEFINES += -DNSSDEBUG
 endif
 
 #
 # To create a loadable module on Darwin, we must use -bundle.
 #
 ifeq ($(OS_TARGET),Darwin)
-ifndef USE_64
 DSO_LDOPTS = -bundle
 endif
-endif
-
--- a/security/nss/lib/cryptohi/keyhi.h
+++ b/security/nss/lib/cryptohi/keyhi.h
@@ -32,16 +32,21 @@ extern SECStatus SECKEY_CopySubjectPubli
 
 /*
 ** Update the PQG parameters for a cert's public key.
 ** Only done for DSA certs
 */
 extern SECStatus
 SECKEY_UpdateCertPQG(CERTCertificate * subjectCert);
 
+/*
+** Return the number of bits in the provided big integer.  This assumes that the
+** SECItem contains a big-endian number and counts from the first non-zero bit.
+*/
+extern unsigned SECKEY_BigIntegerBitLength(const SECItem *number);
 
 /*
 ** Return the strength of the public key in bytes
 */
 extern unsigned SECKEY_PublicKeyStrength(const SECKEYPublicKey *pubk);
 
 /*
 ** Return the strength of the public key in bits
--- a/security/nss/lib/cryptohi/seckey.c
+++ b/security/nss/lib/cryptohi/seckey.c
@@ -173,18 +173,18 @@ SECKEY_CreateRSAPrivateKey(int keySizeIn
 */
 SECKEYPrivateKey *
 SECKEY_CreateDHPrivateKey(SECKEYDHParams *param, SECKEYPublicKey **pubk, void *cx)
 {
     SECKEYPrivateKey *privk;
     PK11SlotInfo *slot;
 
     if (!param || !param->base.data || !param->prime.data ||
-        param->prime.len < 512/8 || param->base.len == 0 || 
-        param->base.len > param->prime.len + 1 || 
+        SECKEY_BigIntegerBitLength(&param->prime) < DH_MIN_P_BITS ||
+        param->base.len == 0 || param->base.len > param->prime.len + 1 ||
 	(param->base.len == 1 && param->base.data[0] == 0)) {
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 	return NULL;
     }
 
     slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN,cx);
     if (!slot) {
 	return NULL;
@@ -936,71 +936,86 @@ SECKEY_ECParamsToBasePointOrderLen(const
 	return 570;
 
     default:
 	PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
 	return 0;
     }
 }
 
+/* The number of bits in the number from the first non-zero bit onward. */
+unsigned
+SECKEY_BigIntegerBitLength(const SECItem *number)
+{
+    const unsigned char *p;
+    unsigned octets;
+    unsigned bits;
+
+    if (!number || !number->data) {
+        PORT_SetError(SEC_ERROR_INVALID_KEY);
+        return 0;
+    }
+
+    p = number->data;
+    octets = number->len;
+    while (octets > 0 && !*p) {
+        ++p;
+        --octets;
+    }
+    if (octets == 0) {
+        return 0;
+    }
+    /* bits = 7..1 because we know at least one bit is set already */
+    /* Note: This could do a binary search, but this is faster for keys if we
+     * assume that good keys will have the MSB set. */
+    for (bits = 7; bits > 0; --bits) {
+        if (*p & (1 << bits)) {
+            break;
+        }
+    }
+    return octets * 8 + bits - 7;
+}
+
 /* returns key strength in bytes (not bits) */
 unsigned
 SECKEY_PublicKeyStrength(const SECKEYPublicKey *pubk)
 {
-    unsigned char b0;
-    unsigned size;
-
-    /* interpret modulus length as key strength */
-    if (!pubk)
-    	goto loser;
-    switch (pubk->keyType) {
-    case rsaKey:
-	if (!pubk->u.rsa.modulus.data) break;
-    	b0 = pubk->u.rsa.modulus.data[0];
-    	return b0 ? pubk->u.rsa.modulus.len : pubk->u.rsa.modulus.len - 1;
-    case dsaKey:
-	if (!pubk->u.dsa.publicValue.data) break;
-    	b0 = pubk->u.dsa.publicValue.data[0];
-    	return b0 ? pubk->u.dsa.publicValue.len :
-	    pubk->u.dsa.publicValue.len - 1;
-    case dhKey:
-	if (!pubk->u.dh.publicValue.data) break;
-    	b0 = pubk->u.dh.publicValue.data[0];
-    	return b0 ? pubk->u.dh.publicValue.len :
-	    pubk->u.dh.publicValue.len - 1;
-    case ecKey:
-	/* Get the key size in bits and adjust */
-	size =	SECKEY_ECParamsToKeySize(&pubk->u.ec.DEREncodedParams);
-	return (size + 7)/8;
-    default:
-	break;
-    }
-loser:
-    PORT_SetError(SEC_ERROR_INVALID_KEY);
-    return 0;
+    return (SECKEY_PublicKeyStrengthInBits(pubk) + 7) / 8;
 }
 
 /* returns key strength in bits */
 unsigned
 SECKEY_PublicKeyStrengthInBits(const SECKEYPublicKey *pubk)
 {
-    unsigned size;
+    unsigned bitSize = 0;
+
+    if (!pubk) {
+        PORT_SetError(SEC_ERROR_INVALID_KEY);
+        return 0;
+    }
+
+    /* interpret modulus length as key strength */
     switch (pubk->keyType) {
     case rsaKey:
+        bitSize = SECKEY_BigIntegerBitLength(&pubk->u.rsa.modulus);
+        break;
     case dsaKey:
+        bitSize = SECKEY_BigIntegerBitLength(&pubk->u.dsa.publicValue);
+        break;
     case dhKey:
-	return SECKEY_PublicKeyStrength(pubk) * 8; /* 1 byte = 8 bits */
+        bitSize = SECKEY_BigIntegerBitLength(&pubk->u.dh.publicValue);
+        break;
     case ecKey:
-	size = SECKEY_ECParamsToKeySize(&pubk->u.ec.DEREncodedParams);
-	return size;
+        bitSize = SECKEY_ECParamsToKeySize(&pubk->u.ec.DEREncodedParams);
+        break;
     default:
-	break;
+        PORT_SetError(SEC_ERROR_INVALID_KEY);
+        break;
     }
-    PORT_SetError(SEC_ERROR_INVALID_KEY);
-    return 0;
+    return bitSize;
 }
 
 /* returns signature length in bytes (not bits) */
 unsigned
 SECKEY_SignatureLen(const SECKEYPublicKey *pubk)
 {
     unsigned char b0;
     unsigned size;
--- a/security/nss/lib/freebl/blapit.h
+++ b/security/nss/lib/freebl/blapit.h
@@ -133,20 +133,23 @@ typedef int __BLAPI_DEPRECATED __attribu
 #define SEED_KEY_LENGTH 16              /* bytes */
 
 #define NSS_FREEBL_DEFAULT_CHUNKSIZE 2048
 
 /*
  * These values come from the initial key size limits from the PKCS #11
  * module. They may be arbitrarily adjusted to any value freebl supports.
  */
-#define RSA_MIN_MODULUS_BITS   128
+#define RSA_MIN_MODULUS_BITS   512
 #define RSA_MAX_MODULUS_BITS 16384
 #define RSA_MAX_EXPONENT_BITS   64
-#define DH_MIN_P_BITS	       128
+/* 1023 to avoid cases where p = 2q+1 for a 512-bit q turns out to be
+ * only 1023 bits and similar.  We don't have good data on whether this
+ * happens because NSS used to count bit lengths incorrectly. */
+#define DH_MIN_P_BITS	      1023
 #define DH_MAX_P_BITS        16384
 
 /*
  * The FIPS 186-1 algorithm for generating primes P and Q allows only 9
  * distinct values for the length of P, and only one value for the
  * length of Q.
  * The algorithm uses a variable j to indicate which of the 9 lengths
  * of P is to be used.
@@ -176,17 +179,17 @@ typedef int __BLAPI_DEPRECATED __attribu
  *      3072           256
  *
  * The FIPS-186-3 complaiant PQG generator (PQG V2) takes arbitrary p and q
  * lengths as input and returns an error if they aren't in this list.
  */
 
 #define DSA1_Q_BITS      160
 #define DSA_MAX_P_BITS	3072
-#define DSA_MIN_P_BITS	 512
+#define DSA_MIN_P_BITS  1023
 #define DSA_MAX_Q_BITS   256
 #define DSA_MIN_Q_BITS   160
 
 #if DSA_MAX_Q_BITS != DSA_MAX_SUBPRIME_LEN*8
 #error "Inconsistent declaration of DSA SUBPRIME/Q parameters in blapit.h"
 #endif
 
 
--- a/security/nss/lib/freebl/ecl/ecp_jac.c
+++ b/security/nss/lib/freebl/ecl/ecp_jac.c
@@ -139,16 +139,30 @@ ec_GFp_pt_add_jac_aff(const mp_int *px, 
 	MP_CHECKOK(group->meth->field_mul(&A, pz, &B, group->meth));
 	MP_CHECKOK(group->meth->field_mul(&A, qx, &A, group->meth));
 	MP_CHECKOK(group->meth->field_mul(&B, qy, &B, group->meth));
 
 	/* C = A - px, D = B - py */
 	MP_CHECKOK(group->meth->field_sub(&A, px, &C, group->meth));
 	MP_CHECKOK(group->meth->field_sub(&B, py, &D, group->meth));
 
+	if (mp_cmp_z(&C) == 0) {
+		/* P == Q or P == -Q */
+		if (mp_cmp_z(&D) == 0) {
+			/* P == Q */
+			/* It is cheaper to double (qx, qy, 1) than (px, py, pz). */
+			MP_DIGIT(&D, 0) = 1; /* Set D to 1. */
+			MP_CHECKOK(ec_GFp_pt_dbl_jac(qx, qy, &D, rx, ry, rz, group));
+		} else {
+			/* P == -Q */
+			MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz));
+		}
+		goto CLEANUP;
+	}
+
 	/* C2 = C^2, C3 = C^3 */
 	MP_CHECKOK(group->meth->field_sqr(&C, &C2, group->meth));
 	MP_CHECKOK(group->meth->field_mul(&C, &C2, &C3, group->meth));
 
 	/* rz = pz * C */
 	MP_CHECKOK(group->meth->field_mul(pz, &C, rz, group->meth));
 
 	/* C = px * C^2 */
@@ -200,17 +214,18 @@ ec_GFp_pt_dbl_jac(const mp_int *px, cons
 	MP_DIGITS(&t1) = 0;
 	MP_DIGITS(&M) = 0;
 	MP_DIGITS(&S) = 0;
 	MP_CHECKOK(mp_init(&t0));
 	MP_CHECKOK(mp_init(&t1));
 	MP_CHECKOK(mp_init(&M));
 	MP_CHECKOK(mp_init(&S));
 
-	if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES) {
+	/* P == inf or P == -P */
+	if (ec_GFp_pt_is_inf_jac(px, py, pz) == MP_YES || mp_cmp_z(py) == 0) {
 		MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, rz));
 		goto CLEANUP;
 	}
 
 	if (mp_cmp_d(pz, 1) == 0) {
 		/* M = 3 * px^2 + a */
 		MP_CHECKOK(group->meth->field_sqr(px, &t0, group->meth));
 		MP_CHECKOK(group->meth->field_add(&t0, &t0, &M, group->meth));
--- a/security/nss/lib/freebl/ecl/ecp_jm.c
+++ b/security/nss/lib/freebl/ecl/ecp_jm.c
@@ -11,17 +11,17 @@
 
 /* Computes R = 2P.  Elliptic curve points P and R can be identical.  Uses 
  * Modified Jacobian coordinates.
  *
  * Assumes input is already field-encoded using field_enc, and returns 
  * output that is still field-encoded.
  *
  */
-mp_err
+static mp_err
 ec_GFp_pt_dbl_jm(const mp_int *px, const mp_int *py, const mp_int *pz,
 				 const mp_int *paz4, mp_int *rx, mp_int *ry, mp_int *rz,
 				 mp_int *raz4, mp_int scratch[], const ECGroup *group)
 {
 	mp_err res = MP_OKAY;
 	mp_int *t0, *t1, *M, *S;
 
 	t0 = &scratch[0];
@@ -81,17 +81,17 @@ ec_GFp_pt_dbl_jm(const mp_int *px, const
 	return res;
 }
 
 /* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and Q is
  * (qx, qy, 1).  Elliptic curve points P, Q, and R can all be identical.
  * Uses mixed Modified_Jacobian-affine coordinates. Assumes input is
  * already field-encoded using field_enc, and returns output that is still
  * field-encoded. */
-mp_err
+static mp_err
 ec_GFp_pt_add_jm_aff(const mp_int *px, const mp_int *py, const mp_int *pz,
 					 const mp_int *paz4, const mp_int *qx,
 					 const mp_int *qy, mp_int *rx, mp_int *ry, mp_int *rz,
 					 mp_int *raz4, mp_int scratch[], const ECGroup *group)
 {
 	mp_err res = MP_OKAY;
 	mp_int *A, *B, *C, *D, *C2, *C3;
 
--- a/security/nss/lib/freebl/mpi/mpmontg.c
+++ b/security/nss/lib/freebl/mpi/mpmontg.c
@@ -878,58 +878,55 @@ mp_err mp_exptmod_safe_i(const mp_int * 
 {
   mp_int *pa1, *pa2, *ptmp;
   mp_size i;
   mp_size first_window;
   mp_err  res;
   int     expOff;
   mp_int  accum1, accum2, accum[WEAVE_WORD_SIZE];
   mp_int  tmp;
-  unsigned char *powersArray;
-  unsigned char *powers;
+  unsigned char *powersArray = NULL;
+  unsigned char *powers = NULL;
 
   MP_DIGITS(&accum1) = 0;
   MP_DIGITS(&accum2) = 0;
   MP_DIGITS(&accum[0]) = 0;
   MP_DIGITS(&accum[1]) = 0;
   MP_DIGITS(&accum[2]) = 0;
   MP_DIGITS(&accum[3]) = 0;
   MP_DIGITS(&tmp) = 0;
 
-  powersArray = (unsigned char *)malloc(num_powers*(nLen*sizeof(mp_digit)+1));
-  if (powersArray == NULL) {
-    res = MP_MEM;
-    goto CLEANUP;
-  }
-
-  /* powers[i] = base ** (i); */
-  powers = (unsigned char *)MP_ALIGN(powersArray,num_powers);
-
   /* grab the first window value. This allows us to preload accumulator1
    * and save a conversion, some squares and a multiple*/
   MP_CHECKOK( mpl_get_bits(exponent, 
 				bits_in_exponent-window_bits, window_bits) );
   first_window = (mp_size)res;
 
   MP_CHECKOK( mp_init_size(&accum1, 3 * nLen + 2) );
   MP_CHECKOK( mp_init_size(&accum2, 3 * nLen + 2) );
-  MP_CHECKOK( mp_init_size(&tmp, 3 * nLen + 2) );
 
   /* build the first WEAVE_WORD powers inline */
   /* if WEAVE_WORD_SIZE is not 4, this code will have to change */
   if (num_powers > 2) {
     MP_CHECKOK( mp_init_size(&accum[0], 3 * nLen + 2) );
     MP_CHECKOK( mp_init_size(&accum[1], 3 * nLen + 2) );
     MP_CHECKOK( mp_init_size(&accum[2], 3 * nLen + 2) );
     MP_CHECKOK( mp_init_size(&accum[3], 3 * nLen + 2) );
     mp_set(&accum[0], 1);
     MP_CHECKOK( s_mp_to_mont(&accum[0], mmm, &accum[0]) );
     MP_CHECKOK( mp_copy(montBase, &accum[1]) );
     SQR(montBase, &accum[2]);
     MUL_NOWEAVE(montBase, &accum[2], &accum[3]);
+    powersArray = (unsigned char *)malloc(num_powers*(nLen*sizeof(mp_digit)+1));
+    if (!powersArray) {
+      res = MP_MEM;
+      goto CLEANUP;
+    }
+    /* powers[i] = base ** (i); */ \
+    powers = (unsigned char *)MP_ALIGN(powersArray,num_powers); \
     MP_CHECKOK( mpi_to_weave(accum, powers, nLen, num_powers) );
     if (first_window < 4) {
       MP_CHECKOK( mp_copy(&accum[first_window], &accum1) );
       first_window = num_powers;
     }
   } else {
       if (first_window == 0) {
         mp_set(&accum1, 1);
@@ -941,17 +938,20 @@ mp_err mp_exptmod_safe_i(const mp_int * 
   }
 
   /*
    * calculate all the powers in the powers array.
    * this adds 2**(k-1)-2 square operations over just calculating the
    * odd powers where k is the window size in the two other mp_modexpt
    * implementations in this file. We will get some of that
    * back by not needing the first 'k' squares and one multiply for the 
-   * first window */ 
+   * first window.
+   * Given the value of 4 for WEAVE_WORD_SIZE, this loop will only execute if
+   * num_powers > 2, in which case powers will have been allocated.
+   */
   for (i = WEAVE_WORD_SIZE; i < num_powers; i++) {
     int acc_index = i & (WEAVE_WORD_SIZE-1); /* i % WEAVE_WORD_SIZE */
     if ( i & 1 ) {
       MUL_NOWEAVE(montBase, &accum[acc_index-1] , &accum[acc_index]);
       /* we've filled the array do our 'per array' processing */
       if (acc_index == (WEAVE_WORD_SIZE-1)) {
         MP_CHECKOK( mpi_to_weave(accum, powers + i - (WEAVE_WORD_SIZE-1),
 							 nLen, num_powers) );
@@ -988,16 +988,21 @@ mp_err mp_exptmod_safe_i(const mp_int * 
 #if MP_ARGCHK == 2
   assert(MP_USED(&accum1) != 0);
 #endif
 
   /* set accumulator to montgomery residue of 1 */
   pa1 = &accum1;
   pa2 = &accum2;
 
+  /* tmp is not used if window_bits == 1. */
+  if (window_bits != 1) {
+    MP_CHECKOK( mp_init_size(&tmp, 3 * nLen + 2) );
+  }
+
   for (expOff = bits_in_exponent - window_bits*2; expOff >= 0; expOff -= window_bits) {
     mp_size smallExp;
     MP_CHECKOK( mpl_get_bits(exponent, expOff, window_bits) );
     smallExp = (mp_size)res;
 
     /* handle unroll the loops */
     switch (window_bits) {
     case 1:
--- a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c
@@ -1127,31 +1127,27 @@ cleanup:
 }
 
 PKIX_Error *
 pkix_pl_HttpDefaultClient_KeepAliveSession(
         SEC_HTTP_SERVER_SESSION session,
         PRPollDesc **pPollDesc,
         void *plContext)
 {
-        PKIX_PL_HttpDefaultClient *client = NULL;
-
         PKIX_ENTER
                 (HTTPDEFAULTCLIENT,
                 "pkix_pl_HttpDefaultClient_KeepAliveSession");
         PKIX_NULLCHECK_TWO(session, pPollDesc);
 
         PKIX_CHECK(pkix_CheckType
                 ((PKIX_PL_Object *)session,
                 PKIX_HTTPDEFAULTCLIENT_TYPE,
                 plContext),
                 PKIX_SESSIONNOTANHTTPDEFAULTCLIENT);
 
-        client = (PKIX_PL_HttpDefaultClient *)session;
-
         /* XXX Not implemented */
 
 cleanup:
 
         PKIX_RETURN(HTTPDEFAULTCLIENT);
 
 }
 
--- a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.c
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.c
@@ -206,17 +206,16 @@ pkix_pl_PublicKey_Hashcode(
 {
         PKIX_PL_PublicKey *pkixPubKey = NULL;
         SECItem algOID;
         SECItem algParams;
         SECItem nssPubKey;
         PKIX_UInt32 algOIDHash;
         PKIX_UInt32 algParamsHash;
         PKIX_UInt32 pubKeyHash;
-        PKIX_UInt32 fullHash;
 
         PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_Hashcode");
         PKIX_NULLCHECK_TWO(object, pHashcode);
 
         PKIX_CHECK(pkix_CheckType(object, PKIX_PUBLICKEY_TYPE, plContext),
                     PKIX_OBJECTNOTPUBLICKEY);
 
         pkixPubKey = (PKIX_PL_PublicKey *)object;
@@ -234,18 +233,16 @@ pkix_pl_PublicKey_Hashcode(
         PKIX_CHECK(pkix_hash
                     (algParams.data, algParams.len, &algParamsHash, plContext),
                     PKIX_HASHFAILED);
 
         PKIX_CHECK(pkix_hash
                     (nssPubKey.data, nssPubKey.len, &pubKeyHash, plContext),
                     PKIX_HASHFAILED);
 
-        fullHash = algOIDHash + algParamsHash + pubKeyHash;
-
         *pHashcode = pubKeyHash;
 
 cleanup:
 
         PKIX_RETURN(PUBLICKEY);
 }
 
 
--- a/security/nss/lib/nss/nss.def
+++ b/security/nss/lib/nss/nss.def
@@ -1065,8 +1065,20 @@ PK11_PrivDecrypt;
 ;+NSS_3.18 { 	# NSS 3.18 release
 ;+    global:
 __PK11_SetCertificateNickname;
 SEC_CheckCrlTimes;
 SEC_GetCrlTimes;
 ;+    local:
 ;+       *;
 ;+};
+;+NSS_3.19 { 	# NSS 3.19 release
+;+    global:
+CERT_GetImposedNameConstraints;
+;+    local:
+;+       *;
+;+};
+;+NSS_3.19.1 { 	# NSS 3.19.1 release
+;+    global:
+SECKEY_BigIntegerBitLength;
+;+    local:
+;+       *;
+;+};
--- a/security/nss/lib/nss/nss.h
+++ b/security/nss/lib/nss/nss.h
@@ -28,19 +28,19 @@
 
 /*
  * NSS's major version, minor version, patch level, build number, and whether
  * this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
  */
-#define NSS_VERSION  "3.18.1" _NSS_ECC_STRING _NSS_CUSTOMIZED
+#define NSS_VERSION  "3.19.1" _NSS_ECC_STRING _NSS_CUSTOMIZED
 #define NSS_VMAJOR   3
-#define NSS_VMINOR   18
+#define NSS_VMINOR   19
 #define NSS_VPATCH   1
 #define NSS_VBUILD   0
 #define NSS_BETA     PR_FALSE
 
 #ifndef RC_INVOKED
 
 #include "seccomon.h"
 
--- a/security/nss/lib/smime/cmsmessage.c
+++ b/security/nss/lib/smime/cmsmessage.c
@@ -23,36 +23,36 @@
 NSSCMSMessage *
 NSS_CMSMessage_Create(PLArenaPool *poolp)
 {
     void *mark = NULL;
     NSSCMSMessage *cmsg;
     PRBool poolp_is_ours = PR_FALSE;
 
     if (poolp == NULL) {
-	poolp = PORT_NewArena (1024);           /* XXX what is right value? */
-	if (poolp == NULL)
-	    return NULL;
-	poolp_is_ours = PR_TRUE;
-    } 
+        poolp = PORT_NewArena (1024);           /* XXX what is right value? */
+        if (poolp == NULL)
+            return NULL;
+        poolp_is_ours = PR_TRUE;
+    }
 
     if (!poolp_is_ours)
-	mark = PORT_ArenaMark(poolp);
+        mark = PORT_ArenaMark(poolp);
 
-    cmsg = (NSSCMSMessage *)PORT_ArenaZAlloc (poolp, sizeof(NSSCMSMessage));
-    if (cmsg == NULL) {
-	if (!poolp_is_ours) {
-	    if (mark) {
-		PORT_ArenaRelease(poolp, mark);
-	    }
-	} else
-	    PORT_FreeArena(poolp, PR_FALSE);
-	return NULL;
+    cmsg = (NSSCMSMessage *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSMessage));
+    if (cmsg == NULL ||
+        NSS_CMSContentInfo_Private_Init(&(cmsg->contentInfo)) != SECSuccess) {
+        if (!poolp_is_ours) {
+            if (mark) {
+                PORT_ArenaRelease(poolp, mark);
+            }
+        } else
+            PORT_FreeArena(poolp, PR_FALSE);
+        return NULL;
     }
-    NSS_CMSContentInfo_Private_Init(&(cmsg->contentInfo));
 
     cmsg->poolp = poolp;
     cmsg->poolp_is_ours = poolp_is_ours;
     cmsg->refCount = 1;
 
     if (mark)
 	PORT_ArenaUnmark(poolp, mark);
 
--- a/security/nss/lib/softoken/config.mk
+++ b/security/nss/lib/softoken/config.mk
@@ -17,42 +17,42 @@ ifeq (,$(filter-out WIN%,$(OS_TARGET)))
 SHARED_LIBRARY = $(OBJDIR)/$(DLL_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
 IMPORT_LIBRARY = $(OBJDIR)/$(IMPORT_LIB_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION)$(IMPORT_LIB_SUFFIX)
 
 RES = $(OBJDIR)/$(LIBRARY_NAME).res
 RESNAME = $(LIBRARY_NAME).rc
 
 ifdef NS_USE_GCC
 EXTRA_SHARED_LIBS += \
-	-L$(DIST)/lib \
+	-L$(SQLITE_LIB_DIR) \
 	-l$(SQLITE_LIB_NAME) \
 	-L$(NSSUTIL_LIB_DIR) \
 	-lnssutil3 \
 	-L$(NSPR_LIB_DIR) \
 	-lplc4 \
 	-lplds4 \
 	-lnspr4 \
 	$(NULL)
 else # ! NS_USE_GCC
 
 EXTRA_SHARED_LIBS += \
-	$(DIST)/lib/$(SQLITE_LIB_NAME).lib \
+	$(SQLITE_LIB_DIR)/$(SQLITE_LIB_NAME).lib \
 	$(NSSUTIL_LIB_DIR)/nssutil3.lib \
 	$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plc4.lib \
 	$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plds4.lib \
 	$(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)nspr4.lib \
 	$(NULL)
 endif # NS_USE_GCC
 
 else
 
 # $(PROGRAM) has NO explicit dependencies on $(EXTRA_SHARED_LIBS)
 # $(EXTRA_SHARED_LIBS) come before $(OS_LIBS), except on AIX.
 EXTRA_SHARED_LIBS += \
-	-L$(DIST)/lib \
+	-L$(SQLITE_LIB_DIR) \
 	-l$(SQLITE_LIB_NAME) \
 	-L$(NSSUTIL_LIB_DIR) \
 	-lnssutil3 \
 	-L$(NSPR_LIB_DIR) \
 	-lplc4 \
 	-lplds4 \
 	-lnspr4 \
 	$(NULL)
--- a/security/nss/lib/softoken/sftkpwd.c
+++ b/security/nss/lib/softoken/sftkpwd.c
@@ -1242,17 +1242,17 @@ sftkdb_ChangePassword(SFTKDBHandle *keyd
 
     sftkdb_switchKeys(keydb, &newKey);
 
 loser:
     if (newKey.data) {
 	PORT_ZFree(newKey.data,newKey.len);
     }
     if (result) {
-	SECITEM_FreeItem(result, PR_FALSE);
+	SECITEM_FreeItem(result, PR_TRUE);
     }
     if (rv != SECSuccess) {
         (*keydb->db->sdb_Abort)(keydb->db);
     }
     
     return rv;
 }
 
--- a/security/nss/lib/softoken/softkver.h
+++ b/security/nss/lib/softoken/softkver.h
@@ -20,16 +20,16 @@
 
 /*
  * Softoken's major version, minor version, patch level, build number,
  * and whether this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
  */
-#define SOFTOKEN_VERSION  "3.18.1" SOFTOKEN_ECC_STRING
+#define SOFTOKEN_VERSION  "3.19.1" SOFTOKEN_ECC_STRING
 #define SOFTOKEN_VMAJOR   3
-#define SOFTOKEN_VMINOR   18
+#define SOFTOKEN_VMINOR   19
 #define SOFTOKEN_VPATCH   1
 #define SOFTOKEN_VBUILD   0
 #define SOFTOKEN_BETA     PR_FALSE
 
 #endif /* _SOFTKVER_H_ */
--- a/security/nss/lib/ssl/SSLerrs.h
+++ b/security/nss/lib/ssl/SSLerrs.h
@@ -417,8 +417,11 @@ ER3(SSL_ERROR_NEXT_PROTOCOL_NO_CALLBACK,
 "The next protocol negotiation extension was enabled, but the callback was cleared prior to being needed.")
 
 ER3(SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL, (SSL_ERROR_BASE + 130),
 "The server supports no protocols that the client advertises in the ALPN extension.")
 
 ER3(SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT, (SSL_ERROR_BASE + 131),
 "The server rejected the handshake because the client downgraded to a lower "
 "TLS version than the server supports.")
+
+ER3(SSL_ERROR_WEAK_SERVER_CERT_KEY, (SSL_ERROR_BASE + 132),
+"The server certificate included a public key that was too weak.")
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -279,40 +279,40 @@ static const ssl3BulkCipherDef bulk_ciph
     {cipher_aes_256,      calg_aes,         32,32, type_block, 16,16, 0, 0},
     {cipher_camellia_128, calg_camellia,    16,16, type_block, 16,16, 0, 0},
     {cipher_camellia_256, calg_camellia,    32,32, type_block, 16,16, 0, 0},
     {cipher_seed,         calg_seed,        16,16, type_block, 16,16, 0, 0},
     {cipher_aes_128_gcm,  calg_aes_gcm,     16,16, type_aead,   4, 0,16, 8},
     {cipher_missing,      calg_null,         0, 0, type_stream, 0, 0, 0, 0},
 };
 
-static const ssl3KEADef kea_defs[] = 
+static const ssl3KEADef kea_defs[] =
 { /* indexed by SSL3KeyExchangeAlgorithm */
-    /* kea              exchKeyType signKeyType is_limited limit  tls_keygen */
-    {kea_null,           kt_null,     sign_null, PR_FALSE,   0, PR_FALSE},
-    {kea_rsa,            kt_rsa,      sign_rsa,  PR_FALSE,   0, PR_FALSE},
-    {kea_rsa_export,     kt_rsa,      sign_rsa,  PR_TRUE,  512, PR_FALSE},
-    {kea_rsa_export_1024,kt_rsa,      sign_rsa,  PR_TRUE, 1024, PR_FALSE},
-    {kea_dh_dss,         kt_dh,       sign_dsa,  PR_FALSE,   0, PR_FALSE},
-    {kea_dh_dss_export,  kt_dh,       sign_dsa,  PR_TRUE,  512, PR_FALSE},
-    {kea_dh_rsa,         kt_dh,       sign_rsa,  PR_FALSE,   0, PR_FALSE},
-    {kea_dh_rsa_export,  kt_dh,       sign_rsa,  PR_TRUE,  512, PR_FALSE},
-    {kea_dhe_dss,        kt_dh,       sign_dsa,  PR_FALSE,   0, PR_FALSE},
-    {kea_dhe_dss_export, kt_dh,       sign_dsa,  PR_TRUE,  512, PR_FALSE},
-    {kea_dhe_rsa,        kt_dh,       sign_rsa,  PR_FALSE,   0, PR_FALSE},
-    {kea_dhe_rsa_export, kt_dh,       sign_rsa,  PR_TRUE,  512, PR_FALSE},
-    {kea_dh_anon,        kt_dh,       sign_null, PR_FALSE,   0, PR_FALSE},
-    {kea_dh_anon_export, kt_dh,       sign_null, PR_TRUE,  512, PR_FALSE},
-    {kea_rsa_fips,       kt_rsa,      sign_rsa,  PR_FALSE,   0, PR_TRUE },
+    /* kea            exchKeyType signKeyType is_limited limit tls_keygen ephemeral */
+    {kea_null,           kt_null, sign_null,  PR_FALSE,   0, PR_FALSE, PR_FALSE},
+    {kea_rsa,            kt_rsa,  sign_rsa,   PR_FALSE,   0, PR_FALSE, PR_FALSE},
+    {kea_rsa_export,     kt_rsa,  sign_rsa,   PR_TRUE,  512, PR_FALSE, PR_TRUE},
+    {kea_rsa_export_1024,kt_rsa,  sign_rsa,   PR_TRUE, 1024, PR_FALSE, PR_TRUE},
+    {kea_dh_dss,         kt_dh,   sign_dsa,   PR_FALSE,   0, PR_FALSE, PR_FALSE},
+    {kea_dh_dss_export,  kt_dh,   sign_dsa,   PR_TRUE,  512, PR_FALSE, PR_FALSE},
+    {kea_dh_rsa,         kt_dh,   sign_rsa,   PR_FALSE,   0, PR_FALSE, PR_FALSE},
+    {kea_dh_rsa_export,  kt_dh,   sign_rsa,   PR_TRUE,  512, PR_FALSE, PR_FALSE},
+    {kea_dhe_dss,        kt_dh,   sign_dsa,   PR_FALSE,   0, PR_FALSE, PR_TRUE},
+    {kea_dhe_dss_export, kt_dh,   sign_dsa,   PR_TRUE,  512, PR_FALSE, PR_TRUE},
+    {kea_dhe_rsa,        kt_dh,   sign_rsa,   PR_FALSE,   0, PR_FALSE, PR_TRUE},
+    {kea_dhe_rsa_export, kt_dh,   sign_rsa,   PR_TRUE,  512, PR_FALSE, PR_TRUE},
+    {kea_dh_anon,        kt_dh,   sign_null,  PR_FALSE,   0, PR_FALSE, PR_TRUE},
+    {kea_dh_anon_export, kt_dh,   sign_null,  PR_TRUE,  512, PR_FALSE, PR_TRUE},
+    {kea_rsa_fips,       kt_rsa,  sign_rsa,   PR_FALSE,   0, PR_TRUE,  PR_FALSE},
 #ifndef NSS_DISABLE_ECC
-    {kea_ecdh_ecdsa,     kt_ecdh,     sign_ecdsa,  PR_FALSE, 0, PR_FALSE},
-    {kea_ecdhe_ecdsa,    kt_ecdh,     sign_ecdsa,  PR_FALSE,   0, PR_FALSE},
-    {kea_ecdh_rsa,       kt_ecdh,     sign_rsa,  PR_FALSE,   0, PR_FALSE},
-    {kea_ecdhe_rsa,      kt_ecdh,     sign_rsa,  PR_FALSE,   0, PR_FALSE},
-    {kea_ecdh_anon,      kt_ecdh,     sign_null,  PR_FALSE,   0, PR_FALSE},
+    {kea_ecdh_ecdsa,     kt_ecdh, sign_ecdsa, PR_FALSE,   0, PR_FALSE, PR_FALSE},
+    {kea_ecdhe_ecdsa,    kt_ecdh, sign_ecdsa, PR_FALSE,   0, PR_FALSE, PR_TRUE},
+    {kea_ecdh_rsa,       kt_ecdh, sign_rsa,   PR_FALSE,   0, PR_FALSE, PR_FALSE},
+    {kea_ecdhe_rsa,      kt_ecdh, sign_rsa,   PR_FALSE,   0, PR_FALSE, PR_TRUE},
+    {kea_ecdh_anon,      kt_ecdh, sign_null,  PR_FALSE,   0, PR_FALSE, PR_TRUE},
 #endif /* NSS_DISABLE_ECC */
 };
 
 /* must use ssl_LookupCipherSuiteDef to access */
 static const ssl3CipherSuiteDef cipher_suite_defs[] = 
 {
 /*  cipher_suite                    bulk_cipher_alg mac_alg key_exchange_alg */
 
@@ -2783,16 +2783,22 @@ ssl3_SendRecord(   sslSocket *        ss
 
     SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d",
 		SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type),
 		nIn));
     PRINT_BUF(50, (ss, "Send record (plain text)", pIn, nIn));
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
 
+    if (ss->ssl3.fatalAlertSent) {
+        SSL_TRC(3, ("%d: SSL3[%d] Suppress write, fatal alert already sent",
+                    SSL_GETPID(), ss->fd));
+        return SECFailure;
+    }
+
     capRecordVersion = ((flags & ssl_SEND_FLAG_CAP_RECORD_VERSION) != 0);
 
     if (capRecordVersion) {
 	/* ssl_SEND_FLAG_CAP_RECORD_VERSION can only be used with the
 	 * TLS initial ClientHello. */
 	PORT_Assert(!IS_DTLS(ss));
 	PORT_Assert(!ss->firstHsDone);
 	PORT_Assert(type == content_handshake);
@@ -3228,16 +3234,19 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertL
     rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
     if (rv == SECSuccess) {
 	PRInt32 sent;
 	sent = ssl3_SendRecord(ss, 0, content_alert, bytes, 2, 
 			       desc == no_certificate 
 			       ? ssl_SEND_FLAG_FORCE_INTO_BUFFER : 0);
 	rv = (sent >= 0) ? SECSuccess : (SECStatus)sent;
     }
+    if (level == alert_fatal) {
+        ss->ssl3.fatalAlertSent = PR_TRUE;
+    }
     ssl_ReleaseXmitBufLock(ss);
     ssl_ReleaseSSL3HandshakeLock(ss);
     return rv;	/* error set by ssl3_FlushHandshake or ssl3_SendRecord */
 }
 
 /*
  * Send illegal_parameter alert.  Set generic error number.
  */
@@ -4973,50 +4982,56 @@ ssl3_SendClientHello(sslSocket *ss, PRBo
 	/* If we previously did client-auth, make sure that the token that
 	** holds the private key still exists, is logged in, hasn't been
 	** removed, etc.
 	*/
 	if (sidOK && !ssl3_ClientAuthTokenPresent(sid)) {
 	    sidOK = PR_FALSE;
 	}
 
-	/* TLS 1.0 (RFC 2246) Appendix E says:
-	 *   Whenever a client already knows the highest protocol known to
-	 *   a server (for example, when resuming a session), it should
-	 *   initiate the connection in that native protocol.
-	 * So we pass sid->version to ssl3_NegotiateVersion() here, except
-	 * when renegotiating.
-	 *
-	 * Windows SChannel compares the client_version inside the RSA
-	 * EncryptedPreMasterSecret of a renegotiation with the
-	 * client_version of the initial ClientHello rather than the
-	 * ClientHello in the renegotiation. To work around this bug, we
-	 * continue to use the client_version used in the initial
-	 * ClientHello when renegotiating.
-	 */
 	if (sidOK) {
+            /* Set ss->version based on the session cache */
 	    if (ss->firstHsDone) {
 		/*
+	         * Windows SChannel compares the client_version inside the RSA
+	         * EncryptedPreMasterSecret of a renegotiation with the
+	         * client_version of the initial ClientHello rather than the
+	         * ClientHello in the renegotiation. To work around this bug, we
+	         * continue to use the client_version used in the initial
+	         * ClientHello when renegotiating.
+	         *
 		 * The client_version of the initial ClientHello is still
 		 * available in ss->clientHelloVersion. Ensure that
 		 * sid->version is bounded within
 		 * [ss->vrange.min, ss->clientHelloVersion], otherwise we
 		 * can't use sid.
 		 */
 		if (sid->version >= ss->vrange.min &&
 		    sid->version <= ss->clientHelloVersion) {
 		    ss->version = ss->clientHelloVersion;
 		} else {
 		    sidOK = PR_FALSE;
 		}
 	    } else {
-		if (ssl3_NegotiateVersion(ss, sid->version,
-					  PR_FALSE) != SECSuccess) {
+                /*
+                 * Check sid->version is OK first.
+                 * Previously, we would cap the version based on sid->version,
+                 * but that prevents negotiation of a higher version if the
+                 * previous session was reduced (e.g., with version fallback)
+                 */
+		if (sid->version < ss->vrange.min || 
+                    sid->version > ss->vrange.max) {
 		    sidOK = PR_FALSE;
-		}
+		} else {
+	            rv = ssl3_NegotiateVersion(ss, SSL_LIBRARY_VERSION_MAX_SUPPORTED,
+                                               PR_TRUE);
+	            if (rv != SECSuccess) {
+                        return rv;	/* error code was set */
+                    }
+	        }
 	    }
 	}
 
 	if (!sidOK) {
 	    SSL_AtomicIncrementLong(& ssl3stats.sch_sid_cache_not_ok );
 	    if (ss->sec.uncache)
                 (*ss->sec.uncache)(sid);
 	    ssl_FreeSID(sid);
@@ -5381,19 +5396,17 @@ ssl3_HandleHelloRequest(sslSocket *ss)
     if (ss->ssl3.hs.ws == wait_server_hello)
 	return SECSuccess;
     if (ss->ssl3.hs.ws != idle_handshake || ss->sec.isServer) {
 	(void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
 	PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST);
 	return SECFailure;
     }
     if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
-	ssl_GetXmitBufLock(ss);
-	rv = SSL3_SendAlert(ss, alert_warning, no_renegotiation);
-	ssl_ReleaseXmitBufLock(ss);
+	(void)SSL3_SendAlert(ss, alert_warning, no_renegotiation);
 	PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED);
 	return SECFailure;
     }
 
     if (sid) {
 	if (ss->sec.uncache)
             ss->sec.uncache(sid);
 	ssl_FreeSID(sid);
@@ -6561,50 +6574,36 @@ ssl3_HandleServerHello(sslSocket *ss, SS
 	goto alert_loser;	/* memory error is set. */
     }
 
     sid->version = ss->version;
     sid->u.ssl3.sessionIDLength = sidBytes.len;
     PORT_Memcpy(sid->u.ssl3.sessionID, sidBytes.data, sidBytes.len);
 
     ss->ssl3.hs.isResuming = PR_FALSE;
-    ss->ssl3.hs.ws         = wait_server_cert;
+    if (ss->ssl3.hs.kea_def->signKeyType != sign_null) {
+        /* All current cipher suites other than those with sign_null (i.e.,
+         * DH_anon_* suites) require a certificate, so use that signal. */
+        ss->ssl3.hs.ws = wait_server_cert;
+    } else if (ss->ssl3.hs.kea_def->ephemeral) {
+        /* Only ephemeral cipher suites use ServerKeyExchange. */
+        ss->ssl3.hs.ws = wait_server_key;
+    } else {
+        ss->ssl3.hs.ws = wait_cert_request;
+    }
     return SECSuccess;
 
 alert_loser:
     (void)SSL3_SendAlert(ss, alert_fatal, desc);
 
 loser:
     errCode = ssl_MapLowLevelError(errCode);
     return SECFailure;
 }
 
-/* ssl3_BigIntGreaterThanOne returns true iff |mpint|, taken as an unsigned,
- * big-endian integer is > 1 */
-static PRBool
-ssl3_BigIntGreaterThanOne(const SECItem* mpint) {
-    unsigned char firstNonZeroByte = 0;
-    unsigned int i;
-
-    for (i = 0; i < mpint->len; i++) {
-	if (mpint->data[i]) {
-	    firstNonZeroByte = mpint->data[i];
-	    break;
-	}
-    }
-
-    if (firstNonZeroByte == 0)
-	return PR_FALSE;
-    if (firstNonZeroByte > 1)
-	return PR_TRUE;
-
-    /* firstNonZeroByte == 1, therefore mpint > 1 iff the first non-zero byte
-     * is followed by another byte. */
-    return (i < mpint->len - 1);
-}
 
 /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
  * ssl3 ServerKeyExchange message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
 {
@@ -6620,41 +6619,41 @@ ssl3_HandleServerKeyExchange(sslSocket *
 
     sigAndHash.hashAlg = SEC_OID_UNKNOWN;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle server_key_exchange handshake",
 		SSL_GETPID(), ss->fd));
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
 
-    if (ss->ssl3.hs.ws != wait_server_key &&
-	ss->ssl3.hs.ws != wait_server_cert) {
-	errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH;
-	desc    = unexpected_message;
-	goto alert_loser;
-    }
-    if (ss->sec.peerCert == NULL) {
-	errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH;
-	desc    = unexpected_message;
-	goto alert_loser;
+    if (ss->ssl3.hs.ws != wait_server_key) {
+        errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH;
+        desc = unexpected_message;
+        goto alert_loser;
     }
 
     isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
     isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
 
     switch (ss->ssl3.hs.kea_def->exchKeyType) {
 
     case kt_rsa: {
 	SECItem          modulus   = {siBuffer, NULL, 0};
 	SECItem          exponent  = {siBuffer, NULL, 0};
 
     	rv = ssl3_ConsumeHandshakeVariable(ss, &modulus, 2, &b, &length);
     	if (rv != SECSuccess) {
 	    goto loser;		/* malformed. */
 	}
+        /* This exchange method is only used by export cipher suites.
+         * Those are broken and so this code will eventually be removed. */
+        if (SECKEY_BigIntegerBitLength(&modulus) < 512) {
+            desc = isTLS ? insufficient_security : illegal_parameter;
+            goto alert_loser;
+        }
     	rv = ssl3_ConsumeHandshakeVariable(ss, &exponent, 2, &b, &length);
     	if (rv != SECSuccess) {
 	    goto loser;		/* malformed. */
 	}
 	if (isTLS12) {
 	    rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
 						       &sigAndHash);
 	    if (rv != SECSuccess) {
@@ -6730,36 +6729,43 @@ ssl3_HandleServerKeyExchange(sslSocket *
     	ss->ssl3.hs.ws = wait_cert_request;
     	return SECSuccess;
     }
 
     case kt_dh: {
 	SECItem          dh_p      = {siBuffer, NULL, 0};
 	SECItem          dh_g      = {siBuffer, NULL, 0};
 	SECItem          dh_Ys     = {siBuffer, NULL, 0};
+        unsigned dh_p_bits;
+        unsigned dh_g_bits;
+        unsigned dh_Ys_bits;
 
     	rv = ssl3_ConsumeHandshakeVariable(ss, &dh_p, 2, &b, &length);
     	if (rv != SECSuccess) {
 	    goto loser;		/* malformed. */
 	}
-	if (dh_p.len < 512/8) {
+        dh_p_bits = SECKEY_BigIntegerBitLength(&dh_p);
+        if (dh_p_bits < DH_MIN_P_BITS) {
 	    errCode = SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY;
 	    goto alert_loser;
 	}
     	rv = ssl3_ConsumeHandshakeVariable(ss, &dh_g, 2, &b, &length);
     	if (rv != SECSuccess) {
 	    goto loser;		/* malformed. */
 	}
-	if (dh_g.len > dh_p.len || !ssl3_BigIntGreaterThanOne(&dh_g))
+        /* Abort if dh_g is 0, 1, or obviously too big. */
+        dh_g_bits = SECKEY_BigIntegerBitLength(&dh_g);
+        if (dh_g_bits > dh_p_bits || dh_g_bits <= 1)
 	    goto alert_loser;
     	rv = ssl3_ConsumeHandshakeVariable(ss, &dh_Ys, 2, &b, &length);
     	if (rv != SECSuccess) {
 	    goto loser;		/* malformed. */
 	}
-	if (dh_Ys.len > dh_p.len || !ssl3_BigIntGreaterThanOne(&dh_Ys))
+        dh_Ys_bits = SECKEY_BigIntegerBitLength(&dh_Ys);
+        if (dh_Ys_bits > dh_p_bits || dh_Ys_bits <= 1)
 	    goto alert_loser;
 	if (isTLS12) {
 	    rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
 						       &sigAndHash);
 	    if (rv != SECSuccess) {
 		goto loser;	/* malformed or unsupported. */
 	    }
 	    rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
@@ -6856,17 +6862,16 @@ loser:
     PORT_SetError( errCode );
     return SECFailure;
 
 no_memory:	/* no-memory error has already been set. */
     ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
     return SECFailure;
 }
 
-
 /*
  * Returns the TLS signature algorithm for the client authentication key and
  * whether it is an RSA or DSA key that may be able to sign only SHA-1 hashes.
  */
 static SECStatus
 ssl3_ExtractClientKeyInfo(sslSocket *ss,
 			  TLSSignatureAlgorithm *sigAlg,
 			  PRBool *preferSha1)
@@ -6984,21 +6989,20 @@ ssl3_HandleCertificateRequest(sslSocket 
     SECItem              algorithms  = {siBuffer, NULL, 0};
     CERTDistNames        ca_list;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_request handshake",
 		SSL_GETPID(), ss->fd));
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
 
-    if (ss->ssl3.hs.ws != wait_cert_request &&
-    	ss->ssl3.hs.ws != wait_server_key) {
-	desc    = unexpected_message;
-	errCode = SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST;
-	goto alert_loser;
+    if (ss->ssl3.hs.ws != wait_cert_request) {
+        desc = unexpected_message;
+        errCode = SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST;
+        goto alert_loser;
     }
 
     PORT_Assert(ss->ssl3.clientCertChain == NULL);
     PORT_Assert(ss->ssl3.clientCertificate == NULL);
     PORT_Assert(ss->ssl3.clientPrivateKey == NULL);
 
     isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
     isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
@@ -7237,19 +7241,18 @@ ssl3_HandleServerHelloDone(sslSocket *ss
     SECStatus     rv;
     SSL3WaitState ws          = ss->ssl3.hs.ws;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello_done handshake",
 		SSL_GETPID(), ss->fd));
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
 
+    /* Skipping CertificateRequest is always permitted. */
     if (ws != wait_hello_done  &&
-        ws != wait_server_cert &&
-	ws != wait_server_key  &&
 	ws != wait_cert_request) {
 	SSL3_SendAlert(ss, alert_fatal, unexpected_message);
 	PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
 	return SECFailure;
     }
 
     rv = ssl3_SendClientSecondRound(ss);
 
@@ -7575,24 +7578,21 @@ ssl3_SendServerHelloSequence(sslSocket *
 		return rv;	/* err code was set. */
 	    }
 	} else {
 #ifndef HACKED_EXPORT_SERVER
 	    PORT_SetError(SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED);
 	    return rv;
 #endif
 	}
-#ifndef NSS_DISABLE_ECC
-    } else if ((kea_def->kea == kea_ecdhe_rsa) ||
-	       (kea_def->kea == kea_ecdhe_ecdsa)) {
-	rv = ssl3_SendServerKeyExchange(ss);
-	if (rv != SECSuccess) {
-	    return rv;	/* err code was set. */
-	}
-#endif /* NSS_DISABLE_ECC */
+    } else if (kea_def->ephemeral) {
+        rv = ssl3_SendServerKeyExchange(ss);
+        if (rv != SECSuccess) {
+            return rv;	/* err code was set. */
+        }
     }
 
     if (ss->opt.requestCertificate) {
 	rv = ssl3_SendCertificateRequest(ss);
 	if (rv != SECSuccess) {
 	    return rv;		/* err code is set. */
 	}
     }
@@ -7634,16 +7634,31 @@ ssl3_HandleClientHello(sslSocket *ss, SS
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle client_hello handshake",
     	SSL_GETPID(), ss->fd));
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
     PORT_Assert( ss->ssl3.initialized );
 
+    if (!ss->sec.isServer ||
+        (ss->ssl3.hs.ws != wait_client_hello &&
+         ss->ssl3.hs.ws != idle_handshake)) {
+        desc = unexpected_message;
+        errCode = SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO;
+        goto alert_loser;
+    }
+    if (ss->ssl3.hs.ws == idle_handshake &&
+        ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
+        desc = no_renegotiation;
+        level = alert_warning;
+        errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
+        goto alert_loser;
+    }
+
     /* Get peer name of client */
     rv = ssl_GetPeerInfo(ss);
     if (rv != SECSuccess) {
 	return rv;		/* error code is set. */
     }
 
     /* Clearing the handshake pointers so that ssl_Do1stHandshake won't
      * call ssl2_HandleMessage.
@@ -7660,30 +7675,16 @@ ssl3_HandleClientHello(sslSocket *ss, SS
     }
 
     /* We might be starting session renegotiation in which case we should
      * clear previous state.
      */
     PORT_Memset(&ss->xtnData, 0, sizeof(TLSExtensionData));
     ss->statelessResume = PR_FALSE;
 
-    if ((ss->ssl3.hs.ws != wait_client_hello) &&
-	(ss->ssl3.hs.ws != idle_handshake)) {
-	desc    = unexpected_message;
-	errCode = SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO;
-	goto alert_loser;
-    }
-    if (ss->ssl3.hs.ws == idle_handshake  &&
-        ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
-	desc    = no_renegotiation;
-	level   = alert_warning;
-	errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
-	goto alert_loser;
-    }
-
     if (IS_DTLS(ss)) {
 	dtls_RehandshakeCleanup(ss);
     }
 
     tmp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
     if (tmp < 0)
 	goto loser;		/* malformed, alert already sent */
 
@@ -8863,16 +8864,20 @@ ssl3_SendServerKeyExchange(sslSocket *ss
 	    /* how can this happen and rv == SECSuccess ?? */
 	    PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
 	    goto loser;
 	}
 	length = 2 + sdPub->u.rsa.modulus.len +
 	         2 + sdPub->u.rsa.publicExponent.len +
 	         2 + signed_hash.len;
 
+	if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+	    length += 2;
+	}
+
 	rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length);
 	if (rv != SECSuccess) {
 	    goto loser; 	/* err set by AppendHandshake. */
 	}
 
 	rv = ssl3_AppendHandshakeVariable(ss, sdPub->u.rsa.modulus.data,
 					  sdPub->u.rsa.modulus.len, 2);
 	if (rv != SECSuccess) {
@@ -9039,17 +9044,17 @@ ssl3_HandleCertificateVerify(sslSocket *
     SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_verify handshake",
 		SSL_GETPID(), ss->fd));
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
 
     isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
     isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
 
-    if (ss->ssl3.hs.ws != wait_cert_verify || ss->sec.peerCert == NULL) {
+    if (ss->ssl3.hs.ws != wait_cert_verify) {
 	desc    = unexpected_message;
 	errCode = SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY;
 	goto alert_loser;
     }
 
     if (isTLS12) {
 	rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
 						   &sigAndHash);
@@ -9825,21 +9830,21 @@ ssl3_HandleCertificate(sslSocket *ss, SS
     int              errCode    = SSL_ERROR_RX_MALFORMED_CERTIFICATE;
     SECItem          certItem;
 
     SSL_TRC(3, ("%d: SSL3[%d]: handle certificate handshake",
 		SSL_GETPID(), ss->fd));
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
 
-    if ((ss->ssl3.hs.ws != wait_server_cert) &&
-	(ss->ssl3.hs.ws != wait_client_cert)) {
-	desc    = unexpected_message;
-	errCode = SSL_ERROR_RX_UNEXPECTED_CERTIFICATE;
-	goto alert_loser;
+    if ((isServer && ss->ssl3.hs.ws != wait_client_cert) ||
+        (!isServer && ss->ssl3.hs.ws != wait_server_cert)) {
+        desc = unexpected_message;
+        errCode = SSL_ERROR_RX_UNEXPECTED_CERTIFICATE;
+        goto alert_loser;
     }
 
     if (ss->sec.peerCert != NULL) {
 	if (ss->sec.peerKey) {
 	    SECKEY_DestroyPublicKey(ss->sec.peerKey);
 	    ss->sec.peerKey = NULL;
 	}
 	CERT_DestroyCertificate(ss->sec.peerCert);
@@ -10035,59 +10040,47 @@ ssl3_AuthCertificate(sslSocket *ss)
 	/* set the server authentication and key exchange types and sizes
 	** from the value in the cert.  If the key exchange key is different,
 	** it will get fixed when we handle the server key exchange message.
 	*/
 	SECKEYPublicKey * pubKey  = CERT_ExtractPublicKey(cert);
 	ss->sec.authAlgorithm = ss->ssl3.hs.kea_def->signKeyType;
 	ss->sec.keaType       = ss->ssl3.hs.kea_def->exchKeyType;
 	if (pubKey) {
+	    KeyType pubKeyType;
 	    ss->sec.keaKeyBits = ss->sec.authKeyBits =
 		SECKEY_PublicKeyStrengthInBits(pubKey);
-#ifndef NSS_DISABLE_ECC
-	    if (ss->sec.keaType == kt_ecdh) {
-		/* Get authKeyBits from signing key.
-		 * XXX The code below uses a quick approximation of
-		 * key size based on cert->signatureWrap.signature.data
-		 * (which contains the DER encoded signature). The field
-		 * cert->signatureWrap.signature.len contains the
-		 * length of the encoded signature in bits.
-		 */
-		if (ss->ssl3.hs.kea_def->kea == kea_ecdh_ecdsa) {
-		    ss->sec.authKeyBits = 
-			cert->signatureWrap.signature.data[3]*8;
-		    if (cert->signatureWrap.signature.data[4] == 0x00)
-			    ss->sec.authKeyBits -= 8;
-		    /* 
-		     * XXX: if cert is not signed by ecdsa we should
-		     * destroy pubKey and goto bad_cert
-		     */
-		} else if (ss->ssl3.hs.kea_def->kea == kea_ecdh_rsa) {
-		    ss->sec.authKeyBits = cert->signatureWrap.signature.len;
-		    /* 
-		     * XXX: if cert is not signed by rsa we should
-		     * destroy pubKey and goto bad_cert
-		     */
-		}
-	    }
-#endif /* NSS_DISABLE_ECC */
+            pubKeyType = SECKEY_GetPublicKeyType(pubKey);
+            /* Too small: not good enough. Send a fatal alert. */
+            /* TODO: Use 1023 for RSA because a higher RSA_MIN_MODULUS_BITS
+             * breaks export cipher suites, not 1024 to be conservative; when
+             * export removed, increase RSA_MIN_MODULUS_BITS and use that. */
+            /* We aren't checking EC here on the understanding that we only
+             * support curves we like, a decision that might need revisiting. */
+            if (((pubKeyType == rsaKey || pubKeyType == rsaPssKey ||
+                  pubKeyType == rsaOaepKey) && ss->sec.authKeyBits < 1023) ||
+                (pubKeyType == dsaKey && ss->sec.authKeyBits < DSA_MIN_P_BITS) ||
+                (pubKeyType == dhKey && ss->sec.authKeyBits < DH_MIN_P_BITS)) {
+                PORT_SetError(SSL_ERROR_WEAK_SERVER_CERT_KEY);
+                (void)SSL3_SendAlert(ss, alert_fatal,
+                                     ss->version >= SSL_LIBRARY_VERSION_TLS_1_0
+                                     ? insufficient_security
+                                     : illegal_parameter);
+                SECKEY_DestroyPublicKey(pubKey);
+                return SECFailure;
+            }
 	    SECKEY_DestroyPublicKey(pubKey); 
 	    pubKey = NULL;
     	}
 
-	ss->ssl3.hs.ws = wait_cert_request; /* disallow server_key_exchange */
-	if (ss->ssl3.hs.kea_def->is_limited ||
-	    /* XXX OR server cert is signing only. */
-#ifndef NSS_DISABLE_ECC
-	    ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa ||
-	    ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa ||
-#endif /* NSS_DISABLE_ECC */
-	    ss->ssl3.hs.kea_def->exchKeyType == kt_dh) {
-	    ss->ssl3.hs.ws = wait_server_key; /* allow server_key_exchange */
-	}
+        if (ss->ssl3.hs.kea_def->ephemeral) {
+            ss->ssl3.hs.ws = wait_server_key; /* require server_key_exchange */
+        } else {
+            ss->ssl3.hs.ws = wait_cert_request; /* disallow server_key_exchange */
+        }
     } else {
 	ss->ssl3.hs.ws = wait_client_key;
     }
 
     PORT_Assert(rv == SECSuccess);
     if (rv != SECSuccess) {
 	errCode = SEC_ERROR_LIBRARY_FAILURE;
 	rv = SECFailure;
--- a/security/nss/lib/ssl/ssl3ecc.c
+++ b/security/nss/lib/ssl/ssl3ecc.c
@@ -1,8 +1,9 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
  * SSL3 Protocol
  *
  * 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/. */
 
 /* ECC code moved here from ssl3con.c */
@@ -1179,32 +1180,31 @@ ssl3_SendSupportedPointFormatsXtn(
 SECStatus
 ssl3_HandleSupportedPointFormatsXtn(sslSocket *ss, PRUint16 ex_type,
                                     SECItem *data)
 {
     int i;
 
     if (data->len < 2 || data->len > 255 || !data->data ||
         data->len != (unsigned int)data->data[0] + 1) {
-        /* malformed */
-        goto loser;
+        return ssl3_DecodeError(ss);
     }
     for (i = data->len; --i > 0; ) {
         if (data->data[i] == 0) {
             /* indicate that we should send a reply */
             SECStatus rv;
             rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type,
                               &ssl3_SendSupportedPointFormatsXtn);
             return rv;
         }
     }
-loser:
+
     /* evil client doesn't support uncompressed */
     ssl3_DisableECCSuites(ss, ecSuites);
-    return SECFailure;
+    return SECSuccess;
 }
 
 
 #define SSL3_GET_SERVER_PUBLICKEY(sock, type) \
     (ss->serverCerts[type].serverKeyPair ? \
     ss->serverCerts[type].serverKeyPair->pubKey : NULL)
 
 /* Extract the TLS curve name for the public key in our EC server cert. */
@@ -1215,63 +1215,66 @@ ECName ssl3_GetSvrCertCurveName(sslSocke
 
     srvPublicKey = SSL3_GET_SERVER_PUBLICKEY(ss, kt_ecdh);
     if (srvPublicKey) {
         ec_curve = params2ecName(&srvPublicKey->u.ec.DEREncodedParams);
     }
     return ec_curve;
 }
 
-/* Ensure that the curve in our server cert is one of the ones suppored
+/* Ensure that the curve in our server cert is one of the ones supported
  * by the remote client, and disable all ECC cipher suites if not.
  */
 SECStatus
 ssl3_HandleSupportedCurvesXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
 {
     PRInt32  list_len;
     PRUint32 peerCurves   = 0;
     PRUint32 mutualCurves = 0;
     PRUint16 svrCertCurveName;
 
-    if (!data->data || data->len < 4 || data->len > 65535)
-        goto loser;
+    if (!data->data || data->len < 4) {
+        (void)ssl3_DecodeError(ss);
+        return SECFailure;
+    }
+
     /* get the length of elliptic_curve_list */
     list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
     if (list_len < 0 || data->len != list_len || (data->len % 2) != 0) {
-        /* malformed */
-        goto loser;
+        (void)ssl3_DecodeError(ss);
+        return SECFailure;
     }
     /* build bit vector of peer's supported curve names */
     while (data->len) {
-        PRInt32  curve_name =
-                 ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+        PRInt32 curve_name =
+                ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+        if (curve_name < 0) {
+            return SECFailure; /* fatal alert already sent */
+        }
         if (curve_name > ec_noName && curve_name < ec_pastLastName) {
             peerCurves |= (1U << curve_name);
         }
     }
     /* What curves do we support in common? */
     mutualCurves = ss->ssl3.hs.negotiatedECCurves &= peerCurves;
-    if (!mutualCurves) { /* no mutually supported EC Curves */
-        goto loser;
+    if (!mutualCurves) {
+        /* no mutually supported EC Curves, disable ECC */
+        ssl3_DisableECCSuites(ss, ecSuites);
+        return SECSuccess;
     }
 
     /* if our ECC cert doesn't use one of these supported curves,
      * disable ECC cipher suites that require an ECC cert.
      */
     svrCertCurveName = ssl3_GetSvrCertCurveName(ss);
     if (svrCertCurveName != ec_noName &&
         (mutualCurves & (1U << svrCertCurveName)) != 0) {
         return SECSuccess;
     }
     /* Our EC cert doesn't contain a mutually supported curve.
      * Disable all ECC cipher suites that require an EC cert
      */
     ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites);
     ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites);
-    return SECFailure;
-
-loser:
-    /* no common curve supported */
-    ssl3_DisableECCSuites(ss, ecSuites);
-    return SECFailure;
+    return SECSuccess;
 }
 
 #endif /* NSS_DISABLE_ECC */
--- a/security/nss/lib/ssl/ssl3ext.c
+++ b/security/nss/lib/ssl/ssl3ext.c
@@ -1,8 +1,9 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /*
  * SSL3 Protocol
  *
  * 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/. */
 
 /* TLS extension code moved here from ssl3ecc.c */
@@ -59,20 +60,24 @@ static SECStatus ssl3_ServerHandleNextPr
 static SECStatus ssl3_ServerHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type,
                                               SECItem *data);
 static PRInt32 ssl3_ClientSendNextProtoNegoXtn(sslSocket *ss, PRBool append,
                                                PRUint32 maxBytes);
 static PRInt32 ssl3_ClientSendAppProtoXtn(sslSocket *ss, PRBool append,
                                           PRUint32 maxBytes);
 static PRInt32 ssl3_ServerSendAppProtoXtn(sslSocket *ss, PRBool append,
                                           PRUint32 maxBytes);
-static PRInt32 ssl3_SendUseSRTPXtn(sslSocket *ss, PRBool append,
-    PRUint32 maxBytes);
-static SECStatus ssl3_HandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type,
-    SECItem *data);
+static PRInt32 ssl3_ClientSendUseSRTPXtn(sslSocket *ss, PRBool append,
+                                         PRUint32 maxBytes);
+static PRInt32 ssl3_ServerSendUseSRTPXtn(sslSocket *ss, PRBool append,
+                                         PRUint32 maxBytes);
+static SECStatus ssl3_ClientHandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type,
+                                             SECItem *data);
+static SECStatus ssl3_ServerHandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type,
+                                             SECItem *data);
 static PRInt32 ssl3_ServerSendStatusRequestXtn(sslSocket * ss,
     PRBool append, PRUint32 maxBytes);
 static SECStatus ssl3_ServerHandleStatusRequestXtn(sslSocket *ss,
     PRUint16 ex_type, SECItem *data);
 static SECStatus ssl3_ClientHandleStatusRequestXtn(sslSocket *ss,
                                                    PRUint16 ex_type,
                                                    SECItem *data);
 static PRInt32 ssl3_ClientSendStatusRequestXtn(sslSocket * ss, PRBool append,
@@ -242,33 +247,33 @@ static const ssl3HelloExtensionHandler c
 #ifndef NSS_DISABLE_ECC
     { ssl_elliptic_curves_xtn,    &ssl3_HandleSupportedCurvesXtn },
     { ssl_ec_point_formats_xtn,   &ssl3_HandleSupportedPointFormatsXtn },
 #endif
     { 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_HandleUseSRTPXtn },
+    { ssl_use_srtp_xtn,           &ssl3_ServerHandleUseSRTPXtn },
     { ssl_cert_status_xtn,        &ssl3_ServerHandleStatusRequestXtn },
     { ssl_signature_algorithms_xtn, &ssl3_ServerHandleSigAlgsXtn },
     { ssl_tls13_draft_version_xtn, &ssl3_ServerHandleDraftVersionXtn },
     { -1, NULL }
 };
 
 /* These two tables are used by the client, to handle server hello
  * extensions. */
 static const ssl3HelloExtensionHandler 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_HandleUseSRTPXtn },
+    { ssl_use_srtp_xtn,           &ssl3_ClientHandleUseSRTPXtn },
     { ssl_cert_status_xtn,        &ssl3_ClientHandleStatusRequestXtn },
     { -1, NULL }
 };
 
 static const ssl3HelloExtensionHandler serverHelloHandlersSSL3[] = {
     { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn },
     { -1, NULL }
 };
@@ -285,17 +290,17 @@ ssl3HelloExtensionSender clientHelloSend
     { ssl_renegotiation_info_xtn, &ssl3_SendRenegotiationInfoXtn },
 #ifndef NSS_DISABLE_ECC
     { ssl_elliptic_curves_xtn,    &ssl3_SendSupportedCurvesXtn },
     { ssl_ec_point_formats_xtn,   &ssl3_SendSupportedPointFormatsXtn },
 #endif
     { ssl_session_ticket_xtn,     &ssl3_SendSessionTicketXtn },
     { ssl_next_proto_nego_xtn,    &ssl3_ClientSendNextProtoNegoXtn },
     { ssl_app_layer_protocol_xtn, &ssl3_ClientSendAppProtoXtn },
-    { ssl_use_srtp_xtn,           &ssl3_SendUseSRTPXtn },
+    { ssl_use_srtp_xtn,           &ssl3_ClientSendUseSRTPXtn },
     { ssl_cert_status_xtn,        &ssl3_ClientSendStatusRequestXtn },
     { ssl_signature_algorithms_xtn, &ssl3_ClientSendSigAlgsXtn },
     { ssl_tls13_draft_version_xtn, &ssl3_ClientSendDraftVersionXtn },
     /* any extra entries will appear as { 0, NULL }    */
 };
 
 static const
 ssl3HelloExtensionSender clientHelloSendersSSL3[SSL_MAX_EXTENSIONS] = {
@@ -393,101 +398,100 @@ ssl3_HandleServerNameXtn(sslSocket * ss,
 {
     SECItem *names = NULL;
     PRUint32 listCount = 0, namesPos = 0, i;
     TLSExtensionData *xtnData = &ss->xtnData;
     SECItem  ldata;
     PRInt32  listLenBytes = 0;
 
     if (!ss->sec.isServer) {
-        /* Verify extension_data is empty. */
-        if (data->data || data->len ||
-            !ssl3_ExtensionNegotiated(ss, ssl_server_name_xtn)) {
-            /* malformed or was not initiated by the client.*/
-            return SECFailure;
-        }
-        return SECSuccess;
+        return SECSuccess; /* ignore extension */
     }
 
     /* Server side - consume client data and register server sender. */
     /* do not parse the data if don't have user extension handling function. */
     if (!ss->sniSocketConfig) {
         return SECSuccess;
     }
     /* length of server_name_list */
     listLenBytes = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
-    if (listLenBytes == 0 || listLenBytes != data->len) {
+    if (listLenBytes < 0 || listLenBytes != data->len) {
+        (void)ssl3_DecodeError(ss);
         return SECFailure;
     }
+    if (listLenBytes == 0) {
+        return SECSuccess; /* ignore an empty extension */
+    }
     ldata = *data;
     /* Calculate the size of the array.*/
     while (listLenBytes > 0) {
         SECItem litem;
         SECStatus rv;
-        PRInt32  type;
-        /* Name Type (sni_host_name) */
+        PRInt32 type;
+        /* Skip Name Type (sni_host_name); checks are on the second pass */
         type = ssl3_ConsumeHandshakeNumber(ss, 1, &ldata.data, &ldata.len);
-        if (!ldata.len) {
+        if (type < 0) { /* i.e., SECFailure cast to PRint32 */
             return SECFailure;
         }
         rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 2, &ldata.data, &ldata.len);
         if (rv != SECSuccess) {
-            return SECFailure;
+            return rv;
         }
-        /* Adjust total length for cunsumed item, item len and type.*/
+        /* Adjust total length for consumed item, item len and type.*/
         listLenBytes -= litem.len + 3;
         if (listLenBytes > 0 && !ldata.len) {
+            (void)ssl3_DecodeError(ss);
             return SECFailure;
         }
         listCount += 1;
     }
     if (!listCount) {
-        return SECFailure;
+        return SECFailure;  /* nothing we can act on */
     }
     names = PORT_ZNewArray(SECItem, listCount);
     if (!names) {
         return SECFailure;
     }
     for (i = 0;i < listCount;i++) {
         int j;
         PRInt32  type;
         SECStatus rv;
         PRBool nametypePresent = PR_FALSE;
         /* Name Type (sni_host_name) */
         type = ssl3_ConsumeHandshakeNumber(ss, 1, &data->data, &data->len);
         /* Check if we have such type in the list */
         for (j = 0;j < listCount && names[j].data;j++) {
+            /* TODO bug 998524: .type is not assigned a value */
             if (names[j].type == type) {
                 nametypePresent = PR_TRUE;
                 break;
             }
         }
         /* HostName (length and value) */
         rv = ssl3_ConsumeHandshakeVariable(ss, &names[namesPos], 2,
                                            &data->data, &data->len);
         if (rv != SECSuccess) {
-            goto loser;
+            PORT_Assert(0);
+            PORT_Free(names);
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            return rv;
         }
         if (nametypePresent == PR_FALSE) {
             namesPos += 1;
         }
     }
     /* Free old and set the new data. */
     if (xtnData->sniNameArr) {
         PORT_Free(ss->xtnData.sniNameArr);
     }
     xtnData->sniNameArr = names;
     xtnData->sniNameArrSize = namesPos;
     xtnData->negotiated[xtnData->numNegotiated++] = ssl_server_name_xtn;
 
     return SECSuccess;
-
-loser:
-    PORT_Free(names);
-    return SECFailure;
 }
 
 /* Called by both clients and servers.
  * Clients sends a filled in session ticket if one is available, and otherwise
  * sends an empty ticket.  Servers always send empty tickets.
  */
 PRInt32
 ssl3_SendSessionTicketXtn(
@@ -598,109 +602,114 @@ ssl3_ValidateNextProtoNego(const unsigne
     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.
          */
         if (newOffset > length || data[offset] == 0) {
-            PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
             return SECFailure;
         }
         offset = newOffset;
     }
 
-    if (offset > length) {
-        PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
-        return SECFailure;
-    }
-
     return SECSuccess;
 }
 
 /* protocol selection handler for ALPN (server side) and NPN (client side) */
 static SECStatus
 ssl3_SelectAppProtocol(sslSocket *ss, PRUint16 ex_type, SECItem *data)
 {
     SECStatus rv;
     unsigned char resultBuffer[255];
     SECItem result = { siBuffer, resultBuffer, 0 };
 
     rv = ssl3_ValidateNextProtoNego(data->data, data->len);
-    if (rv != SECSuccess)
+    if (rv != SECSuccess) {
+        (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
+        PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
         return rv;
+    }
 
     PORT_Assert(ss->nextProtoCallback);
     rv = ss->nextProtoCallback(ss->nextProtoArg, ss->fd, data->data, data->len,
-                               result.data, &result.len, sizeof resultBuffer);
-    if (rv != SECSuccess)
-        return rv;
-    /* 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);
+                               result.data, &result.len, sizeof(resultBuffer));
+    if (rv != SECSuccess) {
+        /* Expect callback to call PORT_SetError() */
+        (void)SSL3_SendAlert(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 */
+        return SECFailure;
+    }
+
+    SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
+
     if (ex_type == ssl_app_layer_protocol_xtn &&
         ss->ssl3.nextProtoState != SSL_NEXT_PROTO_NEGOTIATED) {
-        /* The callback might say OK, but then it's picked a default.
-         * That's OK for NPN, but not ALPN. */
-        SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
+        /* 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. */
+        (void)SSL3_SendAlert(ss, alert_fatal, no_application_protocol);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL);
-        (void)SSL3_SendAlert(ss, alert_fatal, no_application_protocol);
         return SECFailure;
     }
 
     ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
-
-    SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
     return SECITEM_CopyItem(NULL, &ss->ssl3.nextProto, &result);
 }
 
 /* handle an incoming ALPN extension at the server */
 static SECStatus
 ssl3_ServerHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
 {
     int count;
     SECStatus rv;
 
     /* We expressly don't want to allow ALPN on renegotiation,
      * despite it being permitted by the spec. */
     if (ss->firstHsDone || data->len == 0) {
         /* Clients MUST send a non-empty ALPN extension. */
+        (void)SSL3_SendAlert(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
-     * the extension is the same in both ClientHello and ServerHello */
+    /* Unlike NPN, ALPN has extra redundant length information so that
+     * the extension is the same in both ClientHello and ServerHello. */
     count = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
-    if (count < 0) {
-        return SECFailure; /* fatal alert was sent */
-    }
     if (count != data->len) {
-        return ssl3_DecodeError(ss);
+        (void)ssl3_DecodeError(ss);
+        return SECFailure;
     }
 
     if (!ss->nextProtoCallback) {
         /* we're not configured for it */
         return SECSuccess;
     }
 
     rv = ssl3_SelectAppProtocol(ss, ex_type, data);
     if (rv != SECSuccess) {
       return rv;
     }
 
     /* prepare to send back a response, if we negotiated */
     if (ss->ssl3.nextProtoState == SSL_NEXT_PROTO_NEGOTIATED) {
-        return ssl3_RegisterServerHelloExtensionSender(
+        rv = ssl3_RegisterServerHelloExtensionSender(
             ss, ex_type, ssl3_ServerSendAppProtoXtn);
+        if (rv != SECSuccess) {
+            (void)SSL3_SendAlert(ss, alert_fatal, internal_error);
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            return rv;
+        }
     }
     return SECSuccess;
 }
 
 static SECStatus
 ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type,
                                   SECItem *data)
 {
@@ -708,62 +717,73 @@ ssl3_ClientHandleNextProtoNegoXtn(sslSoc
 
     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. */
-        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+        (void)SSL3_SendAlert(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);
+        (void)SSL3_SendAlert(ss, alert_fatal, internal_error);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_NO_CALLBACK);
         return SECFailure;
     }
 
     return ssl3_SelectAppProtocol(ss, ex_type, data);
 }
 
 static SECStatus
 ssl3_ClientHandleAppProtoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data)
 {
-    const unsigned char* d = data->data;
-    PRUint16 name_list_len;
+    SECStatus rv;
+    PRInt32 list_len;
     SECItem protocol_name;
 
     if (ssl3_ExtensionNegotiated(ss, ssl_next_proto_nego_xtn)) {
         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
         return SECFailure;
     }
 
     /* The extension data from the server has the following format:
      *   uint16 name_list_len;
-     *   uint8 len;
+     *   uint8 len;  // where len >= 1
      *   uint8 protocol_name[len]; */
     if (data->len < 4 || data->len > 2 + 1 + 255) {
+        (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
         return SECFailure;
     }
 
-    name_list_len = ((PRUint16) d[0]) << 8 |
-                    ((PRUint16) d[1]);
-    if (name_list_len != data->len - 2 || d[2] != data->len - 3) {
+    list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
+    /* The list has to be the entire extension. */
+    if (list_len != data->len) {
+        (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
         return SECFailure;
     }
 
-    protocol_name.data = data->data + 3;
-    protocol_name.len = data->len - 3;
+    rv = ssl3_ConsumeHandshakeVariable(ss, &protocol_name, 1,
+                                       &data->data, &data->len);
+    /* The list must have exactly one value. */
+    if (rv != SECSuccess || data->len != 0) {
+        (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
+        PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID);
+        return SECFailure;
+    }
 
     SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
     ss->ssl3.nextProtoState = SSL_NEXT_PROTO_SELECTED;
     ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
     return SECITEM_CopyItem(NULL, &ss->ssl3.nextProto, &protocol_name);
 }
 
 static PRInt32
@@ -1381,18 +1401,19 @@ ssl3_ServerHandleSessionTicketXtn(sslSoc
 {
     SECStatus rv;
     SECItem *decrypted_state = NULL;
     SessionTicket *parsed_session_ticket = NULL;
     sslSessionID *sid = NULL;
     SSL3Statistics *ssl3stats;
 
     /* Ignore the SessionTicket extension if processing is disabled. */
-    if (!ss->opt.enableSessionTickets)
+    if (!ss->opt.enableSessionTickets) {
         return SECSuccess;
+    }
 
     /* Keep track of negotiated extensions. */
     ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
 
     /* Parse the received ticket sent in by the client.  We are
      * lenient about some parse errors, falling back to a fullshake
      * instead of terminating the current connection.
      */
@@ -1440,18 +1461,19 @@ ssl3_ServerHandleSessionTicketXtn(sslSoc
             ssl_FreeSID(ss->sec.ci.sid);
             ss->sec.ci.sid = NULL;
         }
 
         extension_data.data = data->data; /* Keep a copy for future use. */
         extension_data.len = data->len;
 
         if (ssl3_ParseEncryptedSessionTicket(ss, data, &enc_session_ticket)
-            != SECSuccess)
-            return SECFailure;
+            != SECSuccess) {
+            return SECSuccess; /* Pretend it isn't there */
+        }
 
         /* Get session ticket keys. */
 #ifndef NO_PKCS11_BYPASS
         if (ss->opt.bypassPKCS11) {
             rv = ssl3_GetSessionTicketKeys(&aes_key, &aes_key_length,
                 &mac_key, &mac_key_length);
         } else
 #endif
@@ -1869,38 +1891,46 @@ ssl3_HandleHelloExtensions(sslSocket *ss
         /* Get the extension's type field */
         extension_type = ssl3_ConsumeHandshakeNumber(ss, 2, b, length);
         if (extension_type < 0)  /* failure to decode extension_type */
             return SECFailure;   /* alert already sent */
 
         /* get the data for this extension, so we can pass it or skip it. */
         rv = ssl3_ConsumeHandshakeVariable(ss, &extension_data, 2, b, length);
         if (rv != SECSuccess)
-            return rv;
+            return rv; /* alert already sent */
 
         /* Check whether the server sent an extension which was not advertised
          * in the ClientHello.
          */
         if (!ss->sec.isServer &&
-            !ssl3_ClientExtensionAdvertised(ss, extension_type))
-            return SECFailure;  /* TODO: send unsupported_extension alert */
+            !ssl3_ClientExtensionAdvertised(ss, extension_type)) {
+            (void)SSL3_SendAlert(ss, alert_fatal, unsupported_extension);
+            return SECFailure;
+        }
 
         /* Check whether an extension has been sent multiple times. */
-        if (ssl3_ExtensionNegotiated(ss, extension_type))
+        if (ssl3_ExtensionNegotiated(ss, extension_type)) {
+            (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
             return SECFailure;
+        }
 
         /* find extension_type in table of Hello Extension Handlers */
         for (handler = handlers; handler->ex_type >= 0; handler++) {
             /* if found, call this handler */
             if (handler->ex_type == extension_type) {
                 rv = (*handler->ex_handler)(ss, (PRUint16)extension_type,
                                                         &extension_data);
-                /* Ignore this result */
-                /* Treat all bad extensions as unrecognized types. */
-                break;
+                if (rv != SECSuccess) {
+                    if (!ss->ssl3.fatalAlertSent) {
+                        /* send a generic alert if the handler didn't already */
+                        (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
+                    }
+                    return SECFailure;
+                }
             }
         }
     }
     return SECSuccess;
 }
 
 /* Add a callback function to the table of senders of server hello extensions.
  */
@@ -2022,201 +2052,209 @@ ssl3_HandleRenegotiationInfoXtn(sslSocke
 {
     SECStatus rv = SECSuccess;
     PRUint32 len = 0;
 
     if (ss->firstHsDone) {
         len = ss->sec.isServer ? ss->ssl3.hs.finishedBytes
                                : ss->ssl3.hs.finishedBytes * 2;
     }
-    if (data->len != 1 + len  ||
-        data->data[0] != len  || (len &&
-        NSS_SecureMemcmp(ss->ssl3.hs.finishedMsgs.data,
-                         data->data + 1, len))) {
-        /* Can we do this here? Or, must we arrange for the caller to do it? */
+    if (data->len != 1 + len || data->data[0] != len ) {
+        (void)ssl3_DecodeError(ss);
+        return SECFailure;
+    }
+    if (len && NSS_SecureMemcmp(ss->ssl3.hs.finishedMsgs.data,
+                                data->data + 1, len)) {
         (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
         PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
         return SECFailure;
     }
     /* remember that we got this extension and it was correct. */
     ss->peerRequestedProtection = 1;
     ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
     if (ss->sec.isServer) {
         /* prepare to send back the appropriate response */
         rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type,
-                                             ssl3_SendRenegotiationInfoXtn);
+                                                     ssl3_SendRenegotiationInfoXtn);
     }
     return rv;
 }
 
 static PRInt32
-ssl3_SendUseSRTPXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
+ssl3_ClientSendUseSRTPXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
 {
     PRUint32 ext_data_len;
     PRInt16 i;
     SECStatus rv;
 
     if (!ss)
         return 0;
 
-    if (!ss->sec.isServer) {
-        /* Client side */
-
-        if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount)
-            return 0;  /* Not relevant */
-
-        ext_data_len = 2 + 2 * ss->ssl3.dtlsSRTPCipherCount + 1;
+    if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount)
+        return 0;  /* Not relevant */
 
-        if (append && maxBytes >= 4 + ext_data_len) {
-            /* Extension type */
-            rv = ssl3_AppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2);
-            if (rv != SECSuccess) return -1;
-            /* Length of extension data */
-            rv = ssl3_AppendHandshakeNumber(ss, ext_data_len, 2);
-            if (rv != SECSuccess) return -1;
-            /* Length of the SRTP cipher list */
-            rv = ssl3_AppendHandshakeNumber(ss,
-                                            2 * ss->ssl3.dtlsSRTPCipherCount,
-                                            2);
-            if (rv != SECSuccess) return -1;
-            /* The SRTP ciphers */
-            for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) {
-                rv = ssl3_AppendHandshakeNumber(ss,
-                                                ss->ssl3.dtlsSRTPCiphers[i],
-                                                2);
-            }
-            /* Empty MKI value */
-            ssl3_AppendHandshakeVariable(ss, NULL, 0, 1);
+    ext_data_len = 2 + 2 * ss->ssl3.dtlsSRTPCipherCount + 1;
 
-            ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
-                ssl_use_srtp_xtn;
-        }
-
-        return 4 + ext_data_len;
-    }
-
-    /* Server side */
-    if (append && maxBytes >= 9) {
+    if (append && maxBytes >= 4 + ext_data_len) {
         /* Extension type */
         rv = ssl3_AppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2);
         if (rv != SECSuccess) return -1;
         /* Length of extension data */
-        rv = ssl3_AppendHandshakeNumber(ss, 5, 2);
+        rv = ssl3_AppendHandshakeNumber(ss, ext_data_len, 2);
         if (rv != SECSuccess) return -1;
         /* Length of the SRTP cipher list */
-        rv = ssl3_AppendHandshakeNumber(ss, 2, 2);
+        rv = ssl3_AppendHandshakeNumber(ss,
+                                        2 * ss->ssl3.dtlsSRTPCipherCount,
+                                        2);
         if (rv != SECSuccess) return -1;
-        /* The selected cipher */
-        rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.dtlsSRTPCipherSuite, 2);
-        if (rv != SECSuccess) return -1;
+        /* The SRTP ciphers */
+        for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) {
+            rv = ssl3_AppendHandshakeNumber(ss,
+                                            ss->ssl3.dtlsSRTPCiphers[i],
+                                            2);
+        }
         /* Empty MKI value */
         ssl3_AppendHandshakeVariable(ss, NULL, 0, 1);
+
+        ss->xtnData.advertised[ss->xtnData.numAdvertised++] =
+                ssl_use_srtp_xtn;
     }
 
+    return 4 + ext_data_len;
+}
+
+static PRInt32
+ssl3_ServerSendUseSRTPXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes)
+{
+    SECStatus rv;
+
+    /* Server side */
+    if (!append || maxBytes < 9) {
+        return 9;
+    }
+
+    /* Extension type */
+    rv = ssl3_AppendHandshakeNumber(ss, ssl_use_srtp_xtn, 2);
+    if (rv != SECSuccess) return -1;
+    /* Length of extension data */
+    rv = ssl3_AppendHandshakeNumber(ss, 5, 2);
+    if (rv != SECSuccess) return -1;
+    /* Length of the SRTP cipher list */
+    rv = ssl3_AppendHandshakeNumber(ss, 2, 2);
+    if (rv != SECSuccess) return -1;
+    /* The selected cipher */
+    rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.dtlsSRTPCipherSuite, 2);
+    if (rv != SECSuccess) return -1;
+    /* Empty MKI value */
+    ssl3_AppendHandshakeVariable(ss, NULL, 0, 1);
+
     return 9;
 }
 
 static SECStatus
-ssl3_HandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
+ssl3_ClientHandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
+{
+    SECStatus rv;
+    SECItem ciphers = {siBuffer, NULL, 0};
+    PRUint16 i;
+    PRUint16 cipher = 0;
+    PRBool found = PR_FALSE;
+    SECItem litem;
+
+    if (!data->data || !data->len) {
+        (void)ssl3_DecodeError(ss);
+        return SECFailure;
+    }
+
+    /* Get the cipher list */
+    rv = ssl3_ConsumeHandshakeVariable(ss, &ciphers, 2,
+                                       &data->data, &data->len);
+    if (rv != SECSuccess) {
+        return SECFailure;  /* fatal alert already sent */
+    }
+    /* Now check that the server has picked just 1 (i.e., len = 2) */
+    if (ciphers.len != 2) {
+        (void)ssl3_DecodeError(ss);
+        return SECFailure;
+    }
+
+    /* Get the selected cipher */
+    cipher = (ciphers.data[0] << 8) | ciphers.data[1];
+
+    /* Now check that this is one of the ciphers we offered */
+    for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) {
+        if (cipher == ss->ssl3.dtlsSRTPCiphers[i]) {
+            found = PR_TRUE;
+            break;
+        }
+    }
+
+    if (!found) {
+        (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
+        return SECFailure;
+    }
+
+    /* Get the srtp_mki value */
+    rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 1,
+                                       &data->data, &data->len);
+    if (rv != SECSuccess) {
+        return SECFailure; /* alert already sent */
+    }
+
+    /* We didn't offer an MKI, so this must be 0 length */
+    if (litem.len != 0) {
+        (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
+        return SECFailure;
+    }
+
+    /* extra trailing bytes */
+    if (data->len != 0) {
+        (void)ssl3_DecodeError(ss);
+        return SECFailure;
+    }
+
+    /* OK, this looks fine. */
+    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ssl_use_srtp_xtn;
+    ss->ssl3.dtlsSRTPCipherSuite = cipher;
+    return SECSuccess;
+}
+
+static SECStatus
+ssl3_ServerHandleUseSRTPXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
 {
     SECStatus rv;
     SECItem ciphers = {siBuffer, NULL, 0};
     PRUint16 i;
     unsigned int j;
     PRUint16 cipher = 0;
     PRBool found = PR_FALSE;
     SECItem litem;
 
-    if (!ss->sec.isServer) {
-        /* Client side */
-        if (!data->data || !data->len) {
-            /* malformed */
-            return SECFailure;
-        }
-
-        /* Get the cipher list */
-        rv = ssl3_ConsumeHandshakeVariable(ss, &ciphers, 2,
-                                           &data->data, &data->len);
-        if (rv != SECSuccess) {
-            return SECFailure;
-        }
-        /* Now check that the number of ciphers listed is 1 (len = 2) */
-        if (ciphers.len != 2) {
-            return SECFailure;
-        }
-
-        /* Get the selected cipher */
-        cipher = (ciphers.data[0] << 8) | ciphers.data[1];
-
-        /* Now check that this is one of the ciphers we offered */
-        for (i = 0; i < ss->ssl3.dtlsSRTPCipherCount; i++) {
-            if (cipher == ss->ssl3.dtlsSRTPCiphers[i]) {
-                found = PR_TRUE;
-                break;
-            }
-        }
-
-        if (!found) {
-            return SECFailure;
-        }
-
-        /* Get the srtp_mki value */
-        rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 1,
-                                           &data->data, &data->len);
-        if (rv != SECSuccess) {
-            return SECFailure;
-        }
-
-        /* We didn't offer an MKI, so this must be 0 length */
-        /* XXX RFC 5764 Section 4.1.3 says:
-         *   If the client detects a nonzero-length MKI in the server's
-         *   response that is different than the one the client offered,
-         *   then the client MUST abort the handshake and SHOULD send an
-         *   invalid_parameter alert.
-         *
-         * Due to a limitation of the ssl3_HandleHelloExtensions function,
-         * returning SECFailure here won't abort the handshake.  It will
-         * merely cause the use_srtp extension to be not negotiated.  We
-         * should fix this.  See NSS bug 753136.
-         */
-        if (litem.len != 0) {
-            return SECFailure;
-        }
-
-        if (data->len != 0) {
-            /* malformed */
-            return SECFailure;
-        }
-
-        /* OK, this looks fine. */
-        ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ssl_use_srtp_xtn;
-        ss->ssl3.dtlsSRTPCipherSuite = cipher;
-        return SECSuccess;
-    }
-
-    /* Server side */
     if (!IS_DTLS(ss) || !ss->ssl3.dtlsSRTPCipherCount) {
         /* Ignore the extension if we aren't doing DTLS or no DTLS-SRTP
          * preferences have been set. */
         return SECSuccess;
     }
 
     if (!data->data || data->len < 5) {
-        /* malformed */
+        (void)ssl3_DecodeError(ss);
         return SECFailure;
     }
 
     /* Get the cipher list */
     rv = ssl3_ConsumeHandshakeVariable(ss, &ciphers, 2,
                                        &data->data, &data->len);
     if (rv != SECSuccess) {
-        return SECFailure;
+        return SECFailure; /* alert already sent */
     }
     /* Check that the list is even length */
     if (ciphers.len % 2) {
+        (void)ssl3_DecodeError(ss);
         return SECFailure;
     }
 
     /* Walk through the offered list and pick the most preferred of our
      * ciphers, if any */
     for (i = 0; !found && i < ss->ssl3.dtlsSRTPCipherCount; i++) {
         for (j = 0; j + 1 < ciphers.len; j += 2) {
             cipher = (ciphers.data[j] << 8) | ciphers.data[j + 1];
@@ -2229,31 +2267,32 @@ ssl3_HandleUseSRTPXtn(sslSocket * ss, PR
 
     /* Get the srtp_mki value */
     rv = ssl3_ConsumeHandshakeVariable(ss, &litem, 1, &data->data, &data->len);
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     if (data->len != 0) {
-        return SECFailure; /* Malformed */
+        (void)ssl3_DecodeError(ss); /* trailing bytes */
+        return SECFailure;
     }
 
     /* Now figure out what to do */
     if (!found) {
-        /* No matching ciphers */
+        /* No matching ciphers, pretend we don't support use_srtp */
         return SECSuccess;
     }
 
     /* OK, we have a valid cipher and we've selected it */
     ss->ssl3.dtlsSRTPCipherSuite = cipher;
     ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ssl_use_srtp_xtn;
 
     return ssl3_RegisterServerHelloExtensionSender(ss, ssl_use_srtp_xtn,
-                                                   ssl3_SendUseSRTPXtn);
+                                                   ssl3_ServerSendUseSRTPXtn);
 }
 
 /* ssl3_ServerHandleSigAlgsXtn handles the signature_algorithms extension
  * from a client.
  * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
 static SECStatus
 ssl3_ServerHandleSigAlgsXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
 {
@@ -2262,40 +2301,40 @@ ssl3_ServerHandleSigAlgsXtn(sslSocket * 
     const unsigned char *b;
     unsigned int numAlgorithms, i, j;
 
     /* Ignore this extension if we aren't doing TLS 1.2 or greater. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2) {
         return SECSuccess;
     }
 
-    /* Keep track of negotiated extensions. */
-    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
-
     rv = ssl3_ConsumeHandshakeVariable(ss, &algorithms, 2, &data->data,
                                        &data->len);
     if (rv != SECSuccess) {
         return SECFailure;
     }
     /* Trailing data, empty value, or odd-length value is invalid. */
     if (data->len != 0 || algorithms.len == 0 || (algorithms.len & 1) != 0) {
+        (void)SSL3_SendAlert(ss, alert_fatal, decode_error);
         PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
         return SECFailure;
     }
 
     numAlgorithms = algorithms.len/2;
 
     /* We don't care to process excessive numbers of algorithms. */
     if (numAlgorithms > 512) {
         numAlgorithms = 512;
     }
 
     ss->ssl3.hs.clientSigAndHash =
             PORT_NewArray(SSL3SignatureAndHashAlgorithm, numAlgorithms);
     if (!ss->ssl3.hs.clientSigAndHash) {
+        (void)SSL3_SendAlert(ss, alert_fatal, internal_error);
+        PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
         return SECFailure;
     }
     ss->ssl3.hs.numClientSigAndHash = 0;
 
     b = algorithms.data;
     for (i = j = 0; i < numAlgorithms; i++) {
         unsigned char tls_hash = *(b++);
         unsigned char tls_sig = *(b++);
@@ -2315,34 +2354,38 @@ ssl3_ServerHandleSigAlgsXtn(sslSocket * 
 
     if (!ss->ssl3.hs.numClientSigAndHash) {
         /* We didn't understand any of the client's requested signature
          * formats. We'll use the defaults. */
         PORT_Free(ss->ssl3.hs.clientSigAndHash);
         ss->ssl3.hs.clientSigAndHash = NULL;
     }
 
+    /* Keep track of negotiated extensions. */
+    ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
     return SECSuccess;
 }
 
 /* ssl3_ClientSendSigAlgsXtn sends the signature_algorithm extension for TLS
  * 1.2 ClientHellos. */
 static PRInt32
 ssl3_ClientSendSigAlgsXtn(sslSocket * ss, PRBool append, PRUint32 maxBytes)
 {
     static const unsigned char signatureAlgorithms[] = {
         /* This block is the contents of our signature_algorithms extension, in
          * wire format. See
          * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
         tls_hash_sha256, tls_sig_rsa,
         tls_hash_sha384, tls_sig_rsa,
+        tls_hash_sha512, tls_sig_rsa,
         tls_hash_sha1,   tls_sig_rsa,
 #ifndef NSS_DISABLE_ECC
         tls_hash_sha256, tls_sig_ecdsa,
         tls_hash_sha384, tls_sig_ecdsa,
+        tls_hash_sha512, tls_sig_ecdsa,
         tls_hash_sha1,   tls_sig_ecdsa,
 #endif
         tls_hash_sha256, tls_sig_dsa,
         tls_hash_sha1,   tls_sig_dsa,
     };
     PRInt32 extension_length;
 
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2) {
@@ -2478,46 +2521,37 @@ ssl3_ServerHandleDraftVersionXtn(sslSock
 {
     PRInt32 draft_version;
 
     /* Ignore this extension if we aren't doing TLS 1.3 */
     if (ss->version != SSL_LIBRARY_VERSION_TLS_1_3) {
         return SECSuccess;
     }
 
-    if (data->len != 2)
-        goto loser;
+    if (data->len != 2) {
+        (void)ssl3_DecodeError(ss);
+        return SECFailure;
+    }
 
     /* Get the draft version out of the handshake */
     draft_version = ssl3_ConsumeHandshakeNumber(ss, 2,
                                                 &data->data, &data->len);
     if (draft_version < 0) {
-        goto loser;
+        return SECFailure;
     }
 
     /*  Keep track of negotiated extensions. */
     ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type;
 
-    /* Compare the version */
     if (draft_version != TLS_1_3_DRAFT_VERSION) {
+        /*
+         * Incompatible/broken TLS 1.3 implementation. Fall back to TLS 1.2.
+         * TODO(ekr@rtfm.com): It's not entirely clear it's safe to roll back
+         * here. Need to double-check.
+         */
         SSL_TRC(30, ("%d: SSL3[%d]: Incompatible version of TLS 1.3 (%d), "
                      "expected %d",
                      SSL_GETPID(), ss->fd, draft_version, TLS_1_3_DRAFT_VERSION));
-        goto loser;
+        ss->version = SSL_LIBRARY_VERSION_TLS_1_2;
     }
 
     return SECSuccess;
-
-loser:
-    /*
-     * Incompatible/broken TLS 1.3 implementation. Fall back to TLS 1.2.
-     * TODO(ekr@rtfm.com): It's not entirely clear it's safe to roll back
-     * here. Need to double-check.
-     * TODO(ekr@rtfm.com): Currently we fall back even on broken extensions.
-     * because SECFailure does not cause handshake failures. See bug
-     * 753136.
-     */
-    SSL_TRC(30, ("%d: SSL3[%d]: Rolling back to TLS 1.2", SSL_GETPID(), ss->fd));
-    ss->version = SSL_LIBRARY_VERSION_TLS_1_2;
-
-    return SECSuccess;
 }
-
--- a/security/nss/lib/ssl/sslerr.h
+++ b/security/nss/lib/ssl/sslerr.h
@@ -193,13 +193,15 @@ SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM    
 SSL_ERROR_DIGEST_FAILURE                = (SSL_ERROR_BASE + 127),
 SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM = (SSL_ERROR_BASE + 128),
 
 SSL_ERROR_NEXT_PROTOCOL_NO_CALLBACK     = (SSL_ERROR_BASE + 129),
 SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL     = (SSL_ERROR_BASE + 130),
 
 SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT  = (SSL_ERROR_BASE + 131),
 
+SSL_ERROR_WEAK_SERVER_CERT_KEY          = (SSL_ERROR_BASE + 132),
+
 SSL_ERROR_END_OF_LIST   /* let the c compiler determine the value of this. */
 } SSLErrorCodes;
 #endif /* NO_SECURITY_ERROR_ENUM */
 
 #endif /* __SSL_ERR_H_ */
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -720,19 +720,25 @@ typedef struct ssl3CipherSuiteDefStr {
 
 /*
 ** There are tables of these, all const.
 */
 typedef struct {
     SSL3KeyExchangeAlgorithm kea;
     SSL3KEAType              exchKeyType;
     SSL3SignType             signKeyType;
+    /* For export cipher suites:
+     * is_limited identifies a suite as having a limit on the key size.
+     * key_size_limit provides the corresponding limit. */
     PRBool                   is_limited;
     int                      key_size_limit;
     PRBool                   tls_keygen;
+    /* True if the key exchange for the suite can be ephemeral.  Or to be more
+     * precise: true if the ServerKeyExchange message is required. */
+    PRBool                   ephemeral;
 } ssl3KEADef;
 
 /*
 ** There are tables of these, all const.
 */
 struct ssl3BulkCipherDefStr {
     SSL3BulkCipher  cipher;
     SSLCipherAlgorithm calg;
@@ -976,16 +982,17 @@ struct ssl3StateStr {
     SSLNextProtoState    nextProtoState;
 
     PRUint16             mtu;   /* Our estimate of the MTU */
 
     /* DTLS-SRTP cipher suite preferences (if any) */
     PRUint16             dtlsSRTPCiphers[MAX_DTLS_SRTP_CIPHER_SUITES];
     PRUint16             dtlsSRTPCipherCount;
     PRUint16             dtlsSRTPCipherSuite;	/* 0 if not selected */
+    PRBool               fatalAlertSent;
 };
 
 #define DTLS_MAX_MTU  1500      /* Ethernet MTU but without subtracting the
 				 * headers, so slightly larger than expected */
 #define IS_DTLS(ss) (ss->protocolVariant == ssl_variant_datagram)
 
 typedef struct {
     SSL3ContentType      type;
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -84,17 +84,17 @@ static sslOptions ssl_defaults = {
     PR_TRUE,    /* reuseServerECDHEKey */
     PR_FALSE    /* enableFallbackSCSV */
 };
 
 /*
  * default range of enabled SSL/TLS protocols
  */
 static SSLVersionRange versions_defaults_stream = {
-    SSL_LIBRARY_VERSION_3_0,
+    SSL_LIBRARY_VERSION_TLS_1_0,
     SSL_LIBRARY_VERSION_TLS_1_2
 };
 
 static SSLVersionRange versions_defaults_datagram = {
     SSL_LIBRARY_VERSION_TLS_1_1,
     SSL_LIBRARY_VERSION_TLS_1_2
 };
 
--- a/security/nss/lib/util/nssutil.h
+++ b/security/nss/lib/util/nssutil.h
@@ -14,19 +14,19 @@
 
 /*
  * NSS utilities's major version, minor version, patch level, build number,
  * and whether this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
  */
-#define NSSUTIL_VERSION  "3.18.1"
+#define NSSUTIL_VERSION  "3.19.1"
 #define NSSUTIL_VMAJOR   3
-#define NSSUTIL_VMINOR   18
+#define NSSUTIL_VMINOR   19
 #define NSSUTIL_VPATCH   1
 #define NSSUTIL_VBUILD   0
 #define NSSUTIL_BETA     PR_FALSE
 
 SEC_BEGIN_PROTOS
 
 /*
  * Returns a const string of the UTIL library version.
--- a/security/nss/tests/all.sh
+++ b/security/nss/tests/all.sh
@@ -297,17 +297,17 @@ fi
 
 # NOTE:
 # Since in make at the top level, modutil is the last file
 # created, we check for modutil to know whether the build
 # is complete. If a new file is created after that, the 
 # following test for modutil should check for that instead.
 # Exception: when building softoken only, shlibsign is the
 # last file created.
-if [ ${NSS_BUILD_SOFTOKEN_ONLY} = "1" ]; then
+if [ "${NSS_BUILD_SOFTOKEN_ONLY}" = "1" ]; then
   LAST_FILE_BUILT=shlibsign
 else
   LAST_FILE_BUILT=modutil
 fi
 
 if [ ! -f ${DIST}/${OBJDIR}/bin/${LAST_FILE_BUILT}${PROG_SUFFIX} ]; then
     echo "Build Incomplete. Aborting test." >> ${LOGFILE}
     html_head "Testing Initialization"
--- a/security/nss/tests/cert/cert.sh
+++ b/security/nss/tests/cert/cert.sh
@@ -953,30 +953,45 @@ cert_ssl_gtests()
 {
   CERTFAILED=0
   echo "$SCRIPTNAME: Creating ssl_gtest DB dir"
   cert_init_cert ${SSLGTESTDIR} "server" 1 ${D_EXT_SERVER}
   echo "$SCRIPTNAME: Creating database for ssl_gtests"
   certu -N -d "${SSLGTESTDIR}" --empty-password 2>&1
   # the ssl server used here is special: is a self-signed server
   # certificate with name server.
-  echo "$SCRIPTNAME: Creating server cert for ssl_gtests"
-  certu -S -z ${R_NOISE_FILE} -g 2048 -d ${SSLGTESTDIR} -n server -s "CN=server" -t C,C,C -x -m 1 -w -2 -v 120 -Z SHA256 -1 -2 <<CERTSCRIPT
+  echo "$SCRIPTNAME: Creating server certs for ssl_gtests"
+  certu -S -z ${R_NOISE_FILE} -g 2048 -d ${SSLGTESTDIR} -n server -s "CN=server" \
+        -t C,C,C -x -m 1 -w -2 -v 120 -Z SHA256 -1 -2 <<CERTSCRIPT
+0
+2
+9
+n
+n
+
+n
+CERTSCRIPT
+  if [ "$RET" -ne 0 ]; then
+     echo "return value is $RET"
+     Exit 6 "Fatal - failed to create RSA server cert for ssl_gtests"
+  fi
+  certu -S -z ${R_NOISE_FILE} -k ec -q nistp256 -d ${SSLGTESTDIR} -n ecdsa -s CN=ecdsa \
+        -t C,C,C -x -m 1 -w -2 -v 120 -Z SHA256 -1 -2 <<CERTSCRIPT
 0
 2
 9
 n
 n
 
 n
 CERTSCRIPT
 
   if [ "$RET" -ne 0 ]; then
      echo "return value is $RET"
-     Exit 6 "Fatal - failed to create server cert for ssl_gtests"
+     Exit 6 "Fatal - failed to create ECDSA server cert for ssl_gtests"
   fi
 }
 
 ############################## cert_stresscerts ################################
 # local shell function to create client certs for SSL stresstest
 ########################################################################
 cert_stresscerts()
 {
--- a/security/nss/tests/chains/scenarios/realcerts.cfg
+++ b/security/nss/tests/chains/scenarios/realcerts.cfg
@@ -16,14 +16,14 @@ import BrAirWaysBadSig:x:
 
 verify TestUser50:x
   result pass
 
 verify TestUser51:x
   result pass
 
 verify PayPalEE:x
-  policy OID.2.16.840.1.113733.1.7.23.6 
+  policy OID.2.16.840.1.114412.1.1 
   result pass
 
 verify BrAirWaysBadSig:x
   result fail
 
index 32b46fcebaa22bc99e6d20fd5fef2447ffc7480a..a826a1da252f02cf2d1612d88b5e85356cce7810
GIT binary patch
literal 1382
zc$_n6Vofq=V)0tQ%*4pVB*2&II5FqN`AxH{g9;g0cO5a{W#iOp^Jx3d%gD&h%3x4n
z$Zf#M#vIDRCd?EXY$$3V4B~JJ^SETDXF8`Al_+@TB^yc_h=YW=g$2sX%k@%#QprFm
zz2y8{Lwy5XkQB498eB)Phog~#M`n74f@5)UX;ETca;idbYEfBgk%F_Mft)z6p^2f9
zp^*U?L;<;GK&}}?Aj+T?)kVSvf*=luFqd;;PG(wuQC?=Ep`ZajNRVBaBRDZn!7INw
z70KlRiIo9~IXWPR>lsQJNI+aJ2oY8YD9TSMO)kmI&x0AwEX-AqSXq#m1M-hS6QdGx
z7%{RkFgG#sGXTZ8n3@<F8Lpn#l*<19cOlpL73I_aJY3QqTdB$XKq~&wkHV8{_FNWw
zFh_6qO_}I36KWratPZXWFi+liIwR~|R`ewS3n|m@=0eRkivs6u|2ao?$I54))ptjC
z@7(vxQnLBx*|bdAGhL@6w+7pta{RWY(>H>RW$B}nQ&`n<RF*ZK@?sS9S=8HHHA|~j
zZ1SlE_ak>aw2;`e_jP%8`0x5_1rK!#?w(oi{Ndh$Kl*)BN^Jbso%;4^HD`Tt;WqUO
z-yaVjv{^OIzY^-I{@*uPf2Om>+FvJ=^HVg;uD?3W5YW-K_(Jo#eKRFgH@UDLdtv7F
z+jsT-T>b$2hCdd&e1Z?=dMIU7z0G5NGB@Hq6Eh<N<Kia9m%tEtY9J2`Kv`uL2?MbP
zk-&`q6V@}am)e}UnVOQcNN7i7k+p#=NC6*<7>kH}$Z=i1%Q;7q|E0;i>Io>dV(h<X
zpbC-}WRWwFX+nyGCO%LyLy8nWkTQNo#{VoV%uK8cAf~Fah#82macHwKva+%>Gs0O+
z2Bjcrd6qnb90QXDMhgtu^fF3H3as??lZ$eUQIfBIaYmw%ZbqVRF*tqdrW@-4)nMu}
zAx4)I$XW#!YXeIIb2iR|HV?+Ozd4MI23iIhFvl@5iphXXEe0Bko|W{S1A+}2n_)^B
z8Cl8=N)1$Cd;`Wd38;helZy*bv>N!rRWY?W!knE5k}gKI1C~iac@&gI;W-qNL7g3e
zJ}EKa0r^B26y8h*3}{6LGbk6>R%Uv{e%s?6-}rg@+{CAI+;$c-q;Y=iV(S!Htomx#
zqS!U%R{dFBg0l~srq7%|_t1eg^Ixk(obcMmZfMYx$-d|RfvAh($5_9Yp89uoMuoHE
z8j;fPCk4K+TSOFRwM59TG_2KdFPL%9{yIa`vKYNs!)ab@O^X&VP5qnyKFupU;ILGS
zhnjnF-ihl5ze@$Ly-TmVBD%>%^!>ZlyBZIDWo5bexnTD+N9NZTA3U)QckH#Ty8q!|
zM!s{#!(KVby6{z=&Kg=Dd%p87$?B0P&0cb5x&Bkdi;X>3_IzRR`DV_%IMI01D^U}V
h;AW5T9OF;he}De->OSv<N1lvZluz1LeR1-i0RU3D<)8on
index 459373be94872c6cf99e61b0550d14e82f28497d..07e025defbc58b3190f341c520ba3d26fc4cd59e
GIT binary patch
literal 1205
zc$_n6V%ccW#5{8WGZP~dlK{)Z=S%LyeEOVwK-+0Ytmu3LUN%mxHjlRNyo`+8tPBP@
zhTI06Y|No7Y{E>T!G@v+!XOTpFpo=SdZu$~QHg?QUb3O2fjCH*TUemHyj(8@D3uJ9
z(o4?IHPklH1W7RqE5UVmWTs~*I2IR|7A58-rz*IHDFo%`mnb+p8pw(B8X6lK7#SHF
z82~|)IIocf64#)BQrGAk=t5kh2G<en;b?^Jq~O$|veY7wi<%gfkb{Jgm4Ug5k)Hu5
z&c)Qk$jGqmf&L*CwiCH5@z>vTrLb+PRZ>e8Tj%63``n%R^UK)n4jY8FOYZca!WT6~
zJ~V90AttT$7iPTUcDR1zf_2dek$LYYY!qC%?$U`J&Q>?MxvyTG`qg3m3E8*4bK=9d
zw*_R({MvQv(s5S#71K}NS+cRIMfcd+rE`u;HZ5!Ak8_F8GVlLu`jMMM-6-no?(TU@
z_6A;1e{|Q{$#^lV#*y6`XJ)O@R_3iZR{bolaJ!cs$M44NVqy#DDhv5Oy*`O!P3e+3
zyUvPll5;Ultq)eUyePvpD_L4{Qb`7v`JqEW9;Yp%7HxYNd+_c8g&m5ECadL(cquv_
zf15k|lZXCi=C6w~CI#!qJ!WENWMEv}#OMhO5my5tVBpFMGcx{X;V@tWQcR2t27Dkf
zevlXoFv+zU$b$H)EMf*CY#iEbjI6Be%#3grlYt40&B(~2VW4K90^=Jnwn=1^loVL$
z>*psI7ofzefj7udc@`G~Cj*BCb_;CUte{Ghi*ig*l<LDG9u(#97<UZ=B|&FLJ)n96
zTaaN2EM^8K21aZwKqiBMmVpM$9ZZa3G9bf?fu^IUFMa2LV2B6#Sj1RF0yF+kSkJ^>
zYIEjhYD&@~p&gM$)&}w*X=N4(1F;5?jdq7KnSbneXS^~)O^So*eR7KSVYD2`3`%7Z
zT~j-mpXJ_<`6HY0%B#QmTA+S!wu{)jHOXHu<>j=@>|WJa*b@EL#Bam)%1N4MbQ`ih
z^eH^7T=I|EUHH}4wo{RXwO?4KWnYeru>E)0P&G!vqGj>3`AvU&qGuTTovoNB^|$r3
z=c-TY-7|~+*sZ$i$bIXo*~0xYdG4O|aW_3`m~Z~=_FOPS&B@{QwMl|YQn<oHj(nB9
z#uS&m=G~EoSwcm>!X{t;zu%yh&0s%wz2E<E*10NgTMujhURJtdjjq`H+Di3JuMf@T
zW`DJ+^)lmP1r5hYXN^mZk5_$rQ*B+o%^|6Q)zOvly*QiQy#vOx(=R9L6}3Of{3FB=
M?jTq2Rqo^#0PL8d<^TWy
index ea6402037fbb5eb28a1292e380d4af041e734103..dae0196507d9166bbf9de6ed93ed5bd91d2a6f7c
GIT binary patch
literal 969
zc$_n6Vm@ln#I$w+GZP~dlK|727_}^JhuQtym7mtRsg@h?vT<s)d9;1!Wn^S!WiZGw
z<Tl`BV-96u6J`nxHWW1w264EAd0aBnGo4e5N)$Zvk_{yd#6iN`!UE;x<$5VVsbrv(
zUUGh}p|*i0NQzll39iE<Gd)AWvADRjC^0WNRlzk(At*n;M8Vn7Ku(<3z|7Fl&;SCW
z#CeSkk+^hrO%tOMa&R!RGB7tW@-qO%xtN+585xe9d0PDJ_m$mGb#;xF-GAC>fAXxV
z=e9zv!&j%6q%Y!<*$|((%wgk^?VI{9%viG0G1BVtohjFBZkJdr@jBzH+VtIPX|RyR
zyU(7vg%j(Nx2;|le|SmD5C5dVeLs%Axot7&G22s)i9AO%97BJfj_MSxD|}(P-?xa<
zcAu3+Ky<mGbnoWlDz3AZugPT)iDKElOZasl*9=ETCBM|f_D08mWtB0V_awc-uj)OE
zl?m3Vn{if(O>9X<@dXnW;h2Smm!oPzZ^xxPG;cQuV|gmLMYBQZW2I%sA|}Ba^|b9B
z+bceu;#y&`nk(hd{<PSsEe98>%C*Nz1#l|}opIcq#~o;~!}~N7Gb01z;$(wF13qA&
z%JMTZ{%2tUCaX3Beh^<6#Ah{N22uvHAOSuWF&2@Hc84>Wf9!W>yfQ;gii7EWa*Fn0
z19_0NGK++PSOazisHu_}6#6n!Y}4;tpEKX4BaMwCT=BM|`wy-3Rr@83${Ym34|aX7
zx+$32XZma2AJ?t(Zu%H{@0j?)S*LGv#kt#$gDVTKJyo2-cq_DhmP*REuCz1v=9r&d
zVX`rEw(^O26-wF#&W}Ug4HG5bM;vX{_cQpmz)(#2#Pdg~V#cTUOGz)V{c$R;+ps%<
zqf?iMEhcFDk)K>ME{ev_7ur{2mTa-tWl8-LHEpgV(=&Nr_B=Wu5WeF?nb5@0Pac^!
z_GmFh^SfM8FueU`SAkmWgoJr}yu~^7x15%9&N#`ge(+Mv_g9KLGlb^Y%-KKhPeaV?
g<g;(wSE;I}FEIbi&{P|8edUjrdcup#U&wm_06cVGKL7v#
--- a/security/nss/tests/libpkix/vfychain_test.lst
+++ b/security/nss/tests/libpkix/vfychain_test.lst
@@ -1,4 +1,4 @@
 # Status | Leaf Cert | Policies | Others(undef)
 0 TestUser50 undef
 0 TestUser51 undef
-0 PayPalEE OID.2.16.840.1.113733.1.7.23.6
+0 PayPalEE OID.2.16.840.1.114412.1.1