Bug 1523175 - land NSS f7be0a534e89 UPGRADE_NSS_RELEASE, r=me
authorJ.C. Jones <jc@mozilla.com>
Mon, 25 Feb 2019 20:59:41 +0000
changeset 461097 13b6c8c4ab74420d6447c485d4013f1d9cb48842
parent 461096 f2c0c83ede1719776285efcfbc207dc0d5e08af0
child 461098 e5e2ac9bb33b81c020b6b7fcc20b706b3f9921f8
push id35618
push usershindli@mozilla.com
push dateTue, 26 Feb 2019 16:54:44 +0000
treeherdermozilla-central@d326a9d5f77b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs1523175
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1523175 - land NSS f7be0a534e89 UPGRADE_NSS_RELEASE, r=me
security/nss/TAG-INFO
security/nss/cmd/atob/atob.c
security/nss/cmd/btoa/btoa.c
security/nss/coreconf/coreconf.dep
security/nss/cpputil/scoped_ptrs_ssl.h
security/nss/gtests/ssl_gtest/manifest.mn
security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
security/nss/gtests/ssl_gtest/ssl_gtest.gyp
security/nss/gtests/ssl_gtest/ssl_primitive_unittest.cc
security/nss/gtests/ssl_gtest/ssl_recordsep_unittest.cc
security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc
security/nss/gtests/ssl_gtest/tls_connect.cc
security/nss/gtests/ssl_gtest/tls_connect.h
security/nss/gtests/ssl_gtest/tls_hkdf_unittest.cc
security/nss/gtests/ssl_gtest/tls_protect.cc
security/nss/gtests/ssl_gtest/tls_protect.h
security/nss/lib/certhigh/certvfy.c
security/nss/lib/freebl/unix_urandom.c
security/nss/lib/pk11wrap/pk11pars.c
security/nss/lib/ssl/manifest.mn
security/nss/lib/ssl/ssl.gyp
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/ssl3gthr.c
security/nss/lib/ssl/sslexp.h
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslprimitive.c
security/nss/lib/ssl/sslsock.c
security/nss/lib/ssl/sslspec.h
security/nss/lib/ssl/tls13con.c
security/nss/lib/ssl/tls13con.h
security/nss/lib/ssl/tls13esni.c
security/nss/lib/ssl/tls13esni.h
security/nss/lib/ssl/tls13exthandle.c
security/nss/lib/ssl/tls13hkdf.c
security/nss/tests/smime/alice.txt
security/nss/tests/smime/smime.sh
security/nss/tests/ssl/sslpolicy.txt
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-1f04eea8834a
+f7be0a534e89
--- a/security/nss/cmd/atob/atob.c
+++ b/security/nss/cmd/atob/atob.c
@@ -100,75 +100,89 @@ Usage(char *progName)
 {
     fprintf(stderr,
             "Usage: %s [-i input] [-o output]\n",
             progName);
     fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n",
             "-i input");
     fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n",
             "-o output");
-    exit(-1);
 }
 
 int
 main(int argc, char **argv)
 {
     char *progName;
     SECStatus rv;
-    FILE *inFile, *outFile;
-    PLOptState *optstate;
+    FILE *inFile = NULL, *outFile = NULL;
+    PRBool closeIn = PR_TRUE, closeOut = PR_TRUE;
+    PLOptState *optstate = NULL;
     PLOptStatus status;
+    int exitCode = -1;
 
-    inFile = 0;
-    outFile = 0;
     progName = strrchr(argv[0], '/');
     progName = progName ? progName + 1 : argv[0];
 
     /* Parse command line arguments */
     optstate = PL_CreateOptState(argc, argv, "?hi:o:");
     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
         switch (optstate->option) {
             case '?':
             case 'h':
                 Usage(progName);
+                goto loser;
                 break;
 
             case 'i':
                 inFile = fopen(optstate->value, "r");
                 if (!inFile) {
                     fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
                             progName, optstate->value);
-                    return -1;
+                    goto loser;
                 }
                 break;
 
             case 'o':
                 outFile = fopen(optstate->value, "wb");
                 if (!outFile) {
                     fprintf(stderr, "%s: unable to open \"%s\" for writing\n",
                             progName, optstate->value);
-                    return -1;
+                    goto loser;
                 }
                 break;
         }
     }
-    if (!inFile)
+    if (!inFile) {
         inFile = stdin;
+        closeIn = PR_FALSE;
+    }
     if (!outFile) {
 #if defined(WIN32)
         int smrv = _setmode(_fileno(stdout), _O_BINARY);
         if (smrv == -1) {
             fprintf(stderr,
                     "%s: Cannot change stdout to binary mode. Use -o option instead.\n",
                     progName);
-            return smrv;
+            goto loser;
         }
 #endif
         outFile = stdout;
+        closeOut = PR_FALSE;
     }
     rv = decode_file(outFile, inFile);
     if (rv != SECSuccess) {
         fprintf(stderr, "%s: lossage: error=%d errno=%d\n",
                 progName, PORT_GetError(), errno);
-        return -1;
+        goto loser;
+    }
+    exitCode = 0;
+loser:
+    if (optstate) {
+        PL_DestroyOptState(optstate);
     }
-    return 0;
+    if (inFile && closeIn) {
+        fclose(inFile);
+    }
+    if (outFile && closeOut) {
+        fclose(outFile);
+    }
+    return exitCode;
 }
--- a/security/nss/cmd/btoa/btoa.c
+++ b/security/nss/cmd/btoa/btoa.c
@@ -94,59 +94,59 @@ Usage(char *progName)
     fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n",
             "-i input");
     fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n",
             "-o output");
     fprintf(stderr, "%-20s Wrap output in BEGIN/END lines and the given suffix\n",
             "-w suffix");
     fprintf(stderr, "%-20s (use \"c\" as a shortcut for suffix CERTIFICATE)\n",
             "");
-    exit(-1);
 }
 
 int
 main(int argc, char **argv)
 {
     char *progName;
     SECStatus rv;
-    FILE *inFile, *outFile;
-    PLOptState *optstate;
+    FILE *inFile = NULL, *outFile = NULL;
+    PRBool closeIn = PR_TRUE, closeOut = PR_TRUE;
+    PLOptState *optstate = NULL;
     PLOptStatus status;
     char *suffix = NULL;
+    int exitCode = -1;
 
-    inFile = 0;
-    outFile = 0;
     progName = strrchr(argv[0], '/');
     if (!progName)
         progName = strrchr(argv[0], '\\');
     progName = progName ? progName + 1 : argv[0];
 
     /* Parse command line arguments */
     optstate = PL_CreateOptState(argc, argv, "i:o:w:");
     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
         switch (optstate->option) {
             default:
                 Usage(progName);
+                goto loser;
                 break;
 
             case 'i':
                 inFile = fopen(optstate->value, "rb");
                 if (!inFile) {
                     fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
                             progName, optstate->value);
-                    return -1;
+                    goto loser;
                 }
                 break;
 
             case 'o':
                 outFile = fopen(optstate->value, "wb");
                 if (!outFile) {
                     fprintf(stderr, "%s: unable to open \"%s\" for writing\n",
                             progName, optstate->value);
-                    return -1;
+                    goto loser;
                 }
                 break;
 
             case 'w':
                 if (!strcmp(optstate->value, "c"))
                     suffix = strdup("CERTIFICATE");
                 else
                     suffix = strdup(optstate->value);
@@ -161,43 +161,56 @@ main(int argc, char **argv)
         ** into O_BINARY mode or else incoming \r\n's will become \n's.
         */
 
         int smrv = _setmode(_fileno(stdin), _O_BINARY);
         if (smrv == -1) {
             fprintf(stderr,
                     "%s: Cannot change stdin to binary mode. Use -i option instead.\n",
                     progName);
-            return smrv;
+            goto loser;
         }
 #endif
         inFile = stdin;
+        closeIn = PR_FALSE;
     }
     if (!outFile) {
 #if defined(WIN32)
         /* We're going to write binary data to stdout. We must put stdout
         ** into O_BINARY mode or else outgoing \r\n's will become \r\r\n's.
         */
 
         int smrv = _setmode(_fileno(stdout), _O_BINARY);
         if (smrv == -1) {
             fprintf(stderr,
                     "%s: Cannot change stdout to binary mode. Use -o option instead.\n",
                     progName);
-            return smrv;
+            goto loser;
         }
 #endif
         outFile = stdout;
+        closeOut = PR_FALSE;
     }
     if (suffix) {
         fprintf(outFile, "-----BEGIN %s-----\n", suffix);
     }
     rv = encode_file(outFile, inFile);
     if (rv != SECSuccess) {
         fprintf(stderr, "%s: lossage: error=%d errno=%d\n",
                 progName, PORT_GetError(), errno);
-        return -1;
+        goto loser;
     }
     if (suffix) {
         fprintf(outFile, "-----END %s-----\n", suffix);
     }
-    return 0;
+    exitCode = 0;
+loser:
+    if (optstate) {
+        PL_DestroyOptState(optstate);
+    }
+    if (inFile && closeIn) {
+        fclose(inFile);
+    }
+    if (outFile && closeOut) {
+        fclose(outFile);
+    }
+    return exitCode;
 }
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/security/nss/cpputil/scoped_ptrs_ssl.h
+++ b/security/nss/cpputil/scoped_ptrs_ssl.h
@@ -9,27 +9,29 @@
 
 #include <memory>
 #include "sslexp.h"
 
 struct ScopedDeleteSSL {
   void operator()(SSLResumptionTokenInfo* token) {
     SSL_DestroyResumptionTokenInfo(token);
   }
+  void operator()(SSLAeadContext* ctx) { SSL_DestroyAead(ctx); }
 };
 
 template <class T>
 struct ScopedMaybeDeleteSSL {
   void operator()(T* ptr) {
     if (ptr) {
       ScopedDeleteSSL del;
       del(ptr);
     }
   }
 };
 
 #define SCOPED(x) typedef std::unique_ptr<x, ScopedMaybeDeleteSSL<x> > Scoped##x
 
 SCOPED(SSLResumptionTokenInfo);
+SCOPED(SSLAeadContext);
 
 #undef SCOPED
 
 #endif  // scoped_ptrs_ssl_h__
--- a/security/nss/gtests/ssl_gtest/manifest.mn
+++ b/security/nss/gtests/ssl_gtest/manifest.mn
@@ -30,16 +30,17 @@ CPPSRCS = \
       ssl_fuzz_unittest.cc \
       ssl_gather_unittest.cc \
       ssl_gtest.cc \
       ssl_hrr_unittest.cc \
       ssl_keylog_unittest.cc \
       ssl_keyupdate_unittest.cc \
       ssl_loopback_unittest.cc \
       ssl_misc_unittest.cc \
+      ssl_primitive_unittest.cc \
       ssl_record_unittest.cc \
       ssl_recordsep_unittest.cc \
       ssl_recordsize_unittest.cc \
       ssl_resumption_unittest.cc \
       ssl_renegotiation_unittest.cc \
       ssl_skip_unittest.cc \
       ssl_staticrsa_unittest.cc \
       ssl_tls13compat_unittest.cc \
--- a/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
@@ -542,16 +542,66 @@ TEST_P(TlsExtensionTest12, SignatureAlgo
        i < PR_ARRAY_SIZE(schemes) && cursor < ext.len(); ++i) {
     uint32_t v = 0;
     EXPECT_TRUE(ext.Read(cursor, 2, &v));
     cursor += 2;
     EXPECT_EQ(schemes[i], static_cast<SSLSignatureScheme>(v));
   }
 }
 
+// This only works on TLS 1.2, since it relies on DSA.
+TEST_P(TlsExtensionTest12, SignatureAlgorithmDisableDSA) {
+  const std::vector<SSLSignatureScheme> schemes = {
+      ssl_sig_dsa_sha1, ssl_sig_dsa_sha256, ssl_sig_dsa_sha384,
+      ssl_sig_dsa_sha512, ssl_sig_rsa_pss_rsae_sha256};
+
+  // Connect with DSA enabled by policy.
+  SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_ANSIX9_DSA_SIGNATURE,
+                                        NSS_USE_ALG_IN_SSL_KX, 0);
+  ASSERT_EQ(SECSuccess, rv);
+  rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
+                              0);
+  ASSERT_EQ(SECSuccess, rv);
+
+  Reset(TlsAgent::kServerDsa);
+  auto capture1 =
+      MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
+  client_->SetSignatureSchemes(schemes.data(), schemes.size());
+  Connect();
+
+  // Check if all the signature algorithms are advertised.
+  EXPECT_TRUE(capture1->captured());
+  const DataBuffer& ext1 = capture1->extension();
+  EXPECT_EQ(2U + 2U * schemes.size(), ext1.len());
+
+  // Connect with DSA disabled by policy.
+  rv = NSS_SetAlgorithmPolicy(SEC_OID_ANSIX9_DSA_SIGNATURE, 0,
+                              NSS_USE_ALG_IN_SSL_KX);
+  ASSERT_EQ(SECSuccess, rv);
+  rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
+                              0);
+  ASSERT_EQ(SECSuccess, rv);
+
+  Reset(TlsAgent::kServerDsa);
+  auto capture2 =
+      MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
+  client_->SetSignatureSchemes(schemes.data(), schemes.size());
+  ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
+  server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
+  client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
+
+  // Check if no DSA algorithms are advertised.
+  EXPECT_TRUE(capture2->captured());
+  const DataBuffer& ext2 = capture2->extension();
+  EXPECT_EQ(2U + 2U, ext2.len());
+  uint32_t v = 0;
+  EXPECT_TRUE(ext2.Read(2, 2, &v));
+  EXPECT_EQ(ssl_sig_rsa_pss_rsae_sha256, v);
+}
+
 // Temporary test to verify that we choke on an empty ClientKeyShare.
 // This test will fail when we implement HelloRetryRequest.
 TEST_P(TlsExtensionTest13, EmptyClientKeyShare) {
   ClientHelloErrorTest(std::make_shared<TlsExtensionTruncator>(
                            client_, ssl_tls13_key_share_xtn, 2),
                        kTlsAlertHandshakeFailure);
 }
 
@@ -1116,16 +1166,20 @@ INSTANTIATE_TEST_CASE_P(
                        TlsConnectTestBase::kTlsVAll));
 INSTANTIATE_TEST_CASE_P(
     ExtensionDatagram, TlsExtensionTestGeneric,
     ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
                        TlsConnectTestBase::kTlsV11Plus));
 INSTANTIATE_TEST_CASE_P(ExtensionDatagramOnly, TlsExtensionTestDtls,
                         TlsConnectTestBase::kTlsV11Plus);
 
+INSTANTIATE_TEST_CASE_P(ExtensionTls12, TlsExtensionTest12,
+                        ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
+                                           TlsConnectTestBase::kTlsV12));
+
 INSTANTIATE_TEST_CASE_P(ExtensionTls12Plus, TlsExtensionTest12Plus,
                         ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
                                            TlsConnectTestBase::kTlsV12Plus));
 
 INSTANTIATE_TEST_CASE_P(
     ExtensionPre13Stream, TlsExtensionTestPre13,
     ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
                        TlsConnectTestBase::kTlsV10ToV12));
--- a/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
+++ b/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
@@ -31,16 +31,17 @@
         'ssl_fragment_unittest.cc',
         'ssl_gather_unittest.cc',
         'ssl_gtest.cc',
         'ssl_hrr_unittest.cc',
         'ssl_keylog_unittest.cc',
         'ssl_keyupdate_unittest.cc',
         'ssl_loopback_unittest.cc',
         'ssl_misc_unittest.cc',
+        'ssl_primitive_unittest.cc',
         'ssl_record_unittest.cc',
         'ssl_recordsep_unittest.cc',
         'ssl_recordsize_unittest.cc',
         'ssl_resumption_unittest.cc',
         'ssl_renegotiation_unittest.cc',
         'ssl_skip_unittest.cc',
         'ssl_staticrsa_unittest.cc',
         'ssl_tls13compat_unittest.cc',
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/ssl_primitive_unittest.cc
@@ -0,0 +1,217 @@
+/* -*- 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 <memory>
+
+#include "keyhi.h"
+#include "pk11pub.h"
+#include "secerr.h"
+#include "ssl.h"
+#include "sslerr.h"
+#include "sslexp.h"
+#include "sslproto.h"
+
+#include "gtest_utils.h"
+#include "nss_scoped_ptrs.h"
+#include "scoped_ptrs_ssl.h"
+#include "tls_connect.h"
+
+namespace nss_test {
+
+// From tls_hkdf_unittest.cc:
+extern size_t GetHashLength(SSLHashType ht);
+
+class AeadTest : public ::testing::Test {
+ public:
+  AeadTest() : slot_(PK11_GetInternalSlot()) {}
+
+  void InitSecret(SSLHashType hash_type) {
+    static const uint8_t kData[64] = {'s', 'e', 'c', 'r', 'e', 't'};
+    SECItem key_item = {siBuffer, const_cast<uint8_t *>(kData),
+                        static_cast<unsigned int>(GetHashLength(hash_type))};
+    PK11SymKey *s =
+        PK11_ImportSymKey(slot_.get(), CKM_SSL3_MASTER_KEY_DERIVE,
+                          PK11_OriginUnwrap, CKA_DERIVE, &key_item, NULL);
+    ASSERT_NE(nullptr, s);
+    secret_.reset(s);
+  }
+
+  void SetUp() override {
+    InitSecret(ssl_hash_sha256);
+    PORT_SetError(0);
+  }
+
+ protected:
+  static void EncryptDecrypt(const ScopedSSLAeadContext &ctx,
+                             const uint8_t *ciphertext, size_t ciphertext_len) {
+    static const uint8_t kAad[] = {'a', 'a', 'd'};
+    static const uint8_t kPlaintext[] = {'t', 'e', 'x', 't'};
+    static const size_t kMaxSize = 32;
+
+    ASSERT_GE(kMaxSize, ciphertext_len);
+
+    uint8_t output[kMaxSize];
+    unsigned int output_len = 0;
+    EXPECT_EQ(SECSuccess, SSL_AeadEncrypt(ctx.get(), 0, kAad, sizeof(kAad),
+                                          kPlaintext, sizeof(kPlaintext),
+                                          output, &output_len, sizeof(output)));
+    ASSERT_EQ(ciphertext_len, static_cast<size_t>(output_len));
+    EXPECT_EQ(0, memcmp(ciphertext, output, ciphertext_len));
+
+    memset(output, 0, sizeof(output));
+    EXPECT_EQ(SECSuccess, SSL_AeadDecrypt(ctx.get(), 0, kAad, sizeof(kAad),
+                                          ciphertext, ciphertext_len, output,
+                                          &output_len, sizeof(output)));
+    ASSERT_EQ(sizeof(kPlaintext), static_cast<size_t>(output_len));
+    EXPECT_EQ(0, memcmp(kPlaintext, output, sizeof(kPlaintext)));
+
+    // Now for some tests of decryption failure.
+    // Truncate the input.
+    EXPECT_EQ(SECFailure, SSL_AeadDecrypt(ctx.get(), 0, kAad, sizeof(kAad),
+                                          ciphertext, ciphertext_len - 1,
+                                          output, &output_len, sizeof(output)));
+    EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
+
+    // Skip the first byte of the AAD.
+    EXPECT_EQ(
+        SECFailure,
+        SSL_AeadDecrypt(ctx.get(), 0, kAad + 1, sizeof(kAad) - 1, ciphertext,
+                        ciphertext_len, output, &output_len, sizeof(output)));
+    EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
+
+    uint8_t input[kMaxSize] = {0};
+    // Toggle a byte of the input.
+    memcpy(input, ciphertext, ciphertext_len);
+    input[0] ^= 9;
+    EXPECT_EQ(SECFailure, SSL_AeadDecrypt(ctx.get(), 0, kAad, sizeof(kAad),
+                                          input, ciphertext_len, output,
+                                          &output_len, sizeof(output)));
+    EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
+
+    // Toggle the last byte (the auth tag).
+    memcpy(input, ciphertext, ciphertext_len);
+    input[ciphertext_len - 1] ^= 77;
+    EXPECT_EQ(SECFailure, SSL_AeadDecrypt(ctx.get(), 0, kAad, sizeof(kAad),
+                                          input, ciphertext_len, output,
+                                          &output_len, sizeof(output)));
+    EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
+
+    // Toggle some of the AAD.
+    memcpy(input, kAad, sizeof(kAad));
+    input[1] ^= 23;
+    EXPECT_EQ(SECFailure, SSL_AeadDecrypt(ctx.get(), 0, input, sizeof(kAad),
+                                          ciphertext, ciphertext_len, output,
+                                          &output_len, sizeof(output)));
+    EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
+  }
+
+ protected:
+  ScopedPK11SymKey secret_;
+
+ private:
+  ScopedPK11SlotInfo slot_;
+};
+
+// These tests all use fixed inputs: a fixed secret, a fixed label, and fixed
+// inputs.  So they have fixed outputs.
+static const char *kLabel = "test ";
+static const uint8_t kCiphertextAes128Gcm[] = {
+    0x11, 0x14, 0xfc, 0x58, 0x4f, 0x44, 0xff, 0x8c, 0xb6, 0xd8,
+    0x20, 0xb3, 0xfb, 0x50, 0xd9, 0x3b, 0xd4, 0xc6, 0xe1, 0x14};
+static const uint8_t kCiphertextAes256Gcm[] = {
+    0xf7, 0x27, 0x35, 0x80, 0x88, 0xaf, 0x99, 0x85, 0xf2, 0x83,
+    0xca, 0xbb, 0x95, 0x42, 0x09, 0x3f, 0x9c, 0xf3, 0x29, 0xf0};
+static const uint8_t kCiphertextChaCha20Poly1305[] = {
+    0x4e, 0x89, 0x2c, 0xfa, 0xfc, 0x8c, 0x40, 0x55, 0x6d, 0x7e,
+    0x99, 0xac, 0x8e, 0x54, 0x58, 0xb1, 0x18, 0xd2, 0x66, 0x22};
+
+TEST_F(AeadTest, AeadBadVersion) {
+  SSLAeadContext *ctx = nullptr;
+  ASSERT_EQ(SECFailure,
+            SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_2, TLS_AES_128_GCM_SHA256,
+                         secret_.get(), kLabel, strlen(kLabel), &ctx));
+  EXPECT_EQ(nullptr, ctx);
+}
+
+TEST_F(AeadTest, AeadUnsupportedCipher) {
+  SSLAeadContext *ctx = nullptr;
+  ASSERT_EQ(SECFailure,
+            SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_RSA_WITH_NULL_MD5,
+                         secret_.get(), kLabel, strlen(kLabel), &ctx));
+  EXPECT_EQ(nullptr, ctx);
+}
+
+TEST_F(AeadTest, AeadOlderCipher) {
+  SSLAeadContext *ctx = nullptr;
+  ASSERT_EQ(
+      SECFailure,
+      SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_RSA_WITH_AES_128_CBC_SHA,
+                   secret_.get(), kLabel, strlen(kLabel), &ctx));
+  EXPECT_EQ(nullptr, ctx);
+}
+
+TEST_F(AeadTest, AeadNoLabel) {
+  SSLAeadContext *ctx = nullptr;
+  ASSERT_EQ(SECFailure,
+            SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_128_GCM_SHA256,
+                         secret_.get(), nullptr, 12, &ctx));
+  EXPECT_EQ(nullptr, ctx);
+}
+
+TEST_F(AeadTest, AeadLongLabel) {
+  SSLAeadContext *ctx = nullptr;
+  ASSERT_EQ(SECFailure,
+            SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_128_GCM_SHA256,
+                         secret_.get(), "", 254, &ctx));
+  EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+  EXPECT_EQ(nullptr, ctx);
+}
+
+TEST_F(AeadTest, AeadNoPointer) {
+  SSLAeadContext *ctx = nullptr;
+  ASSERT_EQ(SECFailure,
+            SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_128_GCM_SHA256,
+                         secret_.get(), kLabel, strlen(kLabel), nullptr));
+  EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+  EXPECT_EQ(nullptr, ctx);
+}
+
+TEST_F(AeadTest, AeadAes128Gcm) {
+  SSLAeadContext *ctxInit;
+  ASSERT_EQ(SECSuccess,
+            SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_128_GCM_SHA256,
+                         secret_.get(), kLabel, strlen(kLabel), &ctxInit));
+  ScopedSSLAeadContext ctx(ctxInit);
+  EXPECT_NE(nullptr, ctx);
+
+  EncryptDecrypt(ctx, kCiphertextAes128Gcm, sizeof(kCiphertextAes128Gcm));
+}
+
+TEST_F(AeadTest, AeadAes256Gcm) {
+  SSLAeadContext *ctxInit;
+  ASSERT_EQ(SECSuccess,
+            SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_256_GCM_SHA384,
+                         secret_.get(), kLabel, strlen(kLabel), &ctxInit));
+  ScopedSSLAeadContext ctx(ctxInit);
+  EXPECT_NE(nullptr, ctx);
+
+  EncryptDecrypt(ctx, kCiphertextAes256Gcm, sizeof(kCiphertextAes256Gcm));
+}
+
+TEST_F(AeadTest, AeadChaCha20Poly1305) {
+  SSLAeadContext *ctxInit;
+  ASSERT_EQ(
+      SECSuccess,
+      SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_CHACHA20_POLY1305_SHA256,
+                   secret_.get(), kLabel, strlen(kLabel), &ctxInit));
+  ScopedSSLAeadContext ctx(ctxInit);
+  EXPECT_NE(nullptr, ctx);
+
+  EncryptDecrypt(ctx, kCiphertextChaCha20Poly1305,
+                 sizeof(kCiphertextChaCha20Poly1305));
+}
+
+}  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/ssl_recordsep_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_recordsep_unittest.cc
@@ -219,18 +219,36 @@ class StagedRecords {
     }
     records_.clear();
   }
 
   // This forwards all saved data and checks the resulting state.
   void ForwardAll(std::shared_ptr<TlsAgent>& peer,
                   TlsAgent::State expected_state) {
     ForwardAll(peer);
-    peer->Handshake();
-    EXPECT_EQ(expected_state, peer->state());
+    switch (expected_state) {
+      case TlsAgent::STATE_CONNECTED:
+        // The handshake callback should have been called, so check that before
+        // checking that SSL_ForceHandshake succeeds.
+        EXPECT_EQ(expected_state, peer->state());
+        EXPECT_EQ(SECSuccess, SSL_ForceHandshake(peer->ssl_fd()));
+        break;
+
+      case TlsAgent::STATE_CONNECTING:
+        // Check that SSL_ForceHandshake() blocks.
+        EXPECT_EQ(SECFailure, SSL_ForceHandshake(peer->ssl_fd()));
+        EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
+        // Update and check the state.
+        peer->Handshake();
+        EXPECT_EQ(TlsAgent::STATE_CONNECTING, peer->state());
+        break;
+
+      default:
+        ADD_FAILURE() << "No idea how to handle this state";
+    }
   }
 
   void ForwardPartial(std::shared_ptr<TlsAgent>& peer) {
     if (records_.empty()) {
       ADD_FAILURE() << "No records to slice";
       return;
     }
     auto& last = records_.back();
@@ -255,22 +273,20 @@ class StagedRecords {
 
     // This forwards staged data to the identified agent.
     void Forward(std::shared_ptr<TlsAgent>& peer) {
       // Now there should be staged data.
       EXPECT_FALSE(data_.empty());
       if (g_ssl_gtest_verbose) {
         std::cerr << role_ << ": forward " << data_ << std::endl;
       }
-      SECStatus rv = SSL_RecordLayerData(
-          peer->ssl_fd(), epoch_, content_type_, data_.data(),
-          static_cast<unsigned int>(data_.len()));
-      if (rv != SECSuccess) {
-        EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
-      }
+      EXPECT_EQ(SECSuccess,
+                SSL_RecordLayerData(peer->ssl_fd(), epoch_, content_type_,
+                                    data_.data(),
+                                    static_cast<unsigned int>(data_.len())));
     }
 
     // Slices the tail off this record and returns it.
     StagedRecord SliceTail() {
       size_t slice = 1;
       if (data_.len() <= slice) {
         ADD_FAILURE() << "record too small to slice in two";
         slice = 0;
--- a/security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_versionpolicy_unittest.cc
@@ -209,45 +209,35 @@ class TestPolicyVersionRange
       rv = NSS_OptionSet(NSS_TLS_VERSION_MIN_POLICY, saved_min_tls_);
       ASSERT_EQ(SECSuccess, rv);
       rv = NSS_OptionSet(NSS_TLS_VERSION_MAX_POLICY, saved_max_tls_);
       ASSERT_EQ(SECSuccess, rv);
       rv = NSS_OptionSet(NSS_DTLS_VERSION_MIN_POLICY, saved_min_dtls_);
       ASSERT_EQ(SECSuccess, rv);
       rv = NSS_OptionSet(NSS_DTLS_VERSION_MAX_POLICY, saved_max_dtls_);
       ASSERT_EQ(SECSuccess, rv);
-      // If it wasn't set initially, clear the bit that we set.
-      if (!(saved_algorithm_policy_ & NSS_USE_POLICY_IN_SSL)) {
-        rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, 0,
-                                    NSS_USE_POLICY_IN_SSL);
-        ASSERT_EQ(SECSuccess, rv);
-      }
     }
 
    private:
     void SaveOriginalPolicy() {
       SECStatus rv;
       rv = NSS_OptionGet(NSS_TLS_VERSION_MIN_POLICY, &saved_min_tls_);
       ASSERT_EQ(SECSuccess, rv);
       rv = NSS_OptionGet(NSS_TLS_VERSION_MAX_POLICY, &saved_max_tls_);
       ASSERT_EQ(SECSuccess, rv);
       rv = NSS_OptionGet(NSS_DTLS_VERSION_MIN_POLICY, &saved_min_dtls_);
       ASSERT_EQ(SECSuccess, rv);
       rv = NSS_OptionGet(NSS_DTLS_VERSION_MAX_POLICY, &saved_max_dtls_);
       ASSERT_EQ(SECSuccess, rv);
-      rv = NSS_GetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY,
-                                  &saved_algorithm_policy_);
-      ASSERT_EQ(SECSuccess, rv);
     }
 
     int32_t saved_min_tls_;
     int32_t saved_max_tls_;
     int32_t saved_min_dtls_;
     int32_t saved_max_dtls_;
-    uint32_t saved_algorithm_policy_;
   };
 
   VersionPolicy saved_version_policy_;
 
   SSLProtocolVariant variant_;
   const VersionRangeWithLabel policy_;
   const VersionRangeWithLabel input_;
   const VersionRangeWithLabel library_;
--- a/security/nss/gtests/ssl_gtest/tls_connect.cc
+++ b/security/nss/gtests/ssl_gtest/tls_connect.cc
@@ -178,32 +178,54 @@ void TlsConnectTestBase::ClearStats() {
 }
 
 void TlsConnectTestBase::ClearServerCache() {
   SSL_ShutdownServerSessionIDCache();
   SSLInt_ClearSelfEncryptKey();
   SSL_ConfigServerSessionIDCache(1024, 0, 0, g_working_dir_path.c_str());
 }
 
+void TlsConnectTestBase::SaveAlgorithmPolicy() {
+  saved_policies_.clear();
+  for (auto it = algorithms_.begin(); it != algorithms_.end(); ++it) {
+    uint32_t policy;
+    SECStatus rv = NSS_GetAlgorithmPolicy(*it, &policy);
+    ASSERT_EQ(SECSuccess, rv);
+    saved_policies_.push_back(std::make_tuple(*it, policy));
+  }
+}
+
+void TlsConnectTestBase::RestoreAlgorithmPolicy() {
+  for (auto it = saved_policies_.begin(); it != saved_policies_.end(); ++it) {
+    auto algorithm = std::get<0>(*it);
+    auto policy = std::get<1>(*it);
+    SECStatus rv = NSS_SetAlgorithmPolicy(
+        algorithm, policy, NSS_USE_POLICY_IN_SSL | NSS_USE_ALG_IN_SSL_KX);
+    ASSERT_EQ(SECSuccess, rv);
+  }
+}
+
 void TlsConnectTestBase::SetUp() {
   SSL_ConfigServerSessionIDCache(1024, 0, 0, g_working_dir_path.c_str());
   SSLInt_ClearSelfEncryptKey();
   SSLInt_SetTicketLifetime(30);
   SSL_SetupAntiReplay(1 * PR_USEC_PER_SEC, 1, 3);
   ClearStats();
+  SaveAlgorithmPolicy();
   Init();
 }
 
 void TlsConnectTestBase::TearDown() {
   client_ = nullptr;
   server_ = nullptr;
 
   SSL_ClearSessionCache();
   SSLInt_ClearSelfEncryptKey();
   SSL_ShutdownServerSessionIDCache();
+  RestoreAlgorithmPolicy();
 }
 
 void TlsConnectTestBase::Init() {
   client_->SetPeer(server_);
   server_->SetPeer(client_);
 
   if (version_) {
     ConfigureVersion(version_);
--- a/security/nss/gtests/ssl_gtest/tls_connect.h
+++ b/security/nss/gtests/ssl_gtest/tls_connect.h
@@ -127,16 +127,19 @@ class TlsConnectTestBase : public ::test
   void ExpectExtendedMasterSecret(bool expected);
   void ExpectEarlyDataAccepted(bool expected);
   void DisableECDHEServerKeyReuse();
   void SkipVersionChecks();
 
   // Move the DTLS timers for both endpoints to pop the next timer.
   void ShiftDtlsTimers();
 
+  void SaveAlgorithmPolicy();
+  void RestoreAlgorithmPolicy();
+
  protected:
   SSLProtocolVariant variant_;
   std::shared_ptr<TlsAgent> client_;
   std::shared_ptr<TlsAgent> server_;
   std::unique_ptr<TlsAgent> client_model_;
   std::unique_ptr<TlsAgent> server_model_;
   uint16_t version_;
   SessionResumptionMode expected_resumption_mode_;
@@ -144,16 +147,23 @@ class TlsConnectTestBase : public ::test
   std::vector<std::vector<uint8_t>> session_ids_;
 
   // 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.
   // NSS will move this final entry to the front when used with ALPN.
   const uint8_t alpn_dummy_val_[4] = {0x01, 0x62, 0x01, 0x61};
 
+  // A list of algorithm IDs whose policies need to be preserved
+  // around test cases.  In particular, DSA is checked in
+  // ssl_extension_unittest.cc.
+  const std::vector<SECOidTag> algorithms_ = {SEC_OID_APPLY_SSL_POLICY,
+                                              SEC_OID_ANSIX9_DSA_SIGNATURE};
+  std::vector<std::tuple<SECOidTag, uint32_t>> saved_policies_;
+
  private:
   void CheckResumption(SessionResumptionMode expected);
   void CheckExtendedMasterSecret();
   void CheckEarlyDataAccepted();
 
   bool expect_extended_master_secret_;
   bool expect_early_data_accepted_;
   bool skip_version_checks_;
--- a/security/nss/gtests/ssl_gtest/tls_hkdf_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/tls_hkdf_unittest.cc
@@ -2,16 +2,19 @@
 /* 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 <memory>
 #include "nss.h"
 #include "pk11pub.h"
+#include "secerr.h"
+#include "sslproto.h"
+#include "sslexp.h"
 #include "tls13hkdf.h"
 
 #include "databuffer.h"
 #include "gtest_utils.h"
 #include "nss_scoped_ptrs.h"
 
 namespace nss_test {
 
@@ -51,25 +54,46 @@ const size_t kHashLength[] = {
     16, /* ssl_hash_md5    */
     20, /* ssl_hash_sha1   */
     28, /* ssl_hash_sha224 */
     32, /* ssl_hash_sha256 */
     48, /* ssl_hash_sha384 */
     64, /* ssl_hash_sha512 */
 };
 
+size_t GetHashLength(SSLHashType hash) {
+  size_t i = static_cast<size_t>(hash);
+  if (i < PR_ARRAY_SIZE(kHashLength)) {
+    return kHashLength[i];
+  }
+  ADD_FAILURE() << "Unknown hash: " << hash;
+  return 0;
+}
+
+PRUint16 GetSomeCipherSuiteForHash(SSLHashType hash) {
+  switch (hash) {
+    case ssl_hash_sha256:
+      return TLS_AES_128_GCM_SHA256;
+    case ssl_hash_sha384:
+      return TLS_AES_256_GCM_SHA384;
+    default:
+      ADD_FAILURE() << "Unknown hash: " << hash;
+  }
+  return 0;
+}
+
 const std::string kHashName[] = {"None",    "MD5",     "SHA-1",  "SHA-224",
                                  "SHA-256", "SHA-384", "SHA-512"};
 
 static void ImportKey(ScopedPK11SymKey* to, const DataBuffer& key,
                       SSLHashType hash_type, PK11SlotInfo* slot) {
   ASSERT_LT(hash_type, sizeof(kHashLength));
   ASSERT_LE(kHashLength[hash_type], key.len());
   SECItem key_item = {siBuffer, const_cast<uint8_t*>(key.data()),
-                      static_cast<unsigned int>(kHashLength[hash_type])};
+                      static_cast<unsigned int>(GetHashLength(hash_type))};
 
   PK11SymKey* inner =
       PK11_ImportSymKey(slot, CKM_SSL3_MASTER_KEY_DERIVE, PK11_OriginUnwrap,
                         CKA_DERIVE, &key_item, NULL);
   ASSERT_NE(nullptr, inner);
   to->reset(inner);
 }
 
@@ -129,32 +153,53 @@ class TlsHkdfTest : public ::testing::Te
 
     PK11SymKey* prk = nullptr;
     SECStatus rv = tls13_HkdfExtract(ikmk1.get(), ikmk2.get(), base_hash, &prk);
     ASSERT_EQ(SECSuccess, rv);
     ScopedPK11SymKey prkk(prk);
 
     DumpKey("Output", prkk);
     VerifyKey(prkk, expected);
+
+    // Now test the public wrapper.
+    PRUint16 cs = GetSomeCipherSuiteForHash(base_hash);
+    rv = SSL_HkdfExtract(SSL_LIBRARY_VERSION_TLS_1_3, cs, ikmk1.get(),
+                         ikmk2.get(), &prk);
+    ASSERT_EQ(SECSuccess, rv);
+    ASSERT_NE(nullptr, prk);
+    VerifyKey(ScopedPK11SymKey(prk), expected);
   }
 
   void HkdfExpandLabel(ScopedPK11SymKey* prk, SSLHashType base_hash,
                        const uint8_t* session_hash, size_t session_hash_len,
                        const char* label, size_t label_len,
                        const DataBuffer& expected) {
     std::cerr << "Hash = " << kHashName[base_hash] << std::endl;
 
     std::vector<uint8_t> output(expected.len());
 
     SECStatus rv = tls13_HkdfExpandLabelRaw(prk->get(), base_hash, session_hash,
                                             session_hash_len, label, label_len,
                                             &output[0], output.size());
     ASSERT_EQ(SECSuccess, rv);
     DumpData("Output", &output[0], output.size());
     EXPECT_EQ(0, memcmp(expected.data(), &output[0], expected.len()));
+
+    if (session_hash_len > 0) {
+      return;
+    }
+
+    // Verify that the public API produces the same result.
+    PRUint16 cs = GetSomeCipherSuiteForHash(base_hash);
+    PK11SymKey* secret;
+    rv = SSL_HkdfDeriveSecret(SSL_LIBRARY_VERSION_TLS_1_3, cs, prk->get(),
+                              label, label_len, &secret);
+    EXPECT_EQ(SECSuccess, rv);
+    ASSERT_NE(nullptr, prk);
+    VerifyKey(ScopedPK11SymKey(secret), expected);
   }
 
  protected:
   ScopedPK11SymKey k1_;
   ScopedPK11SymKey k2_;
   SSLHashType hash_type_;
 
  private:
@@ -170,17 +215,17 @@ TEST_P(TlsHkdfTest, HkdfNullNull) {
       {0x33, 0xad, 0x0a, 0x1c, 0x60, 0x7e, 0xc0, 0x3b, 0x09, 0xe6, 0xcd,
        0x98, 0x93, 0x68, 0x0c, 0xe2, 0x10, 0xad, 0xf3, 0x00, 0xaa, 0x1f,
        0x26, 0x60, 0xe1, 0xb2, 0x2e, 0x10, 0xf1, 0x70, 0xf9, 0x2a},
       {0x7e, 0xe8, 0x20, 0x6f, 0x55, 0x70, 0x02, 0x3e, 0x6d, 0xc7, 0x51, 0x9e,
        0xb1, 0x07, 0x3b, 0xc4, 0xe7, 0x91, 0xad, 0x37, 0xb5, 0xc3, 0x82, 0xaa,
        0x10, 0xba, 0x18, 0xe2, 0x35, 0x7e, 0x71, 0x69, 0x71, 0xf9, 0x36, 0x2f,
        0x2c, 0x2f, 0xe2, 0xa7, 0x6b, 0xfd, 0x78, 0xdf, 0xec, 0x4e, 0xa9, 0xb5}};
 
-  const DataBuffer expected_data(tv[hash_type_], kHashLength[hash_type_]);
+  const DataBuffer expected_data(tv[hash_type_], GetHashLength(hash_type_));
   HkdfExtract(nullptr, nullptr, hash_type_, expected_data);
 }
 
 TEST_P(TlsHkdfTest, HkdfKey1Only) {
   const uint8_t tv[][48] = {
       {/* ssl_hash_none   */},
       {/* ssl_hash_md5    */},
       {/* ssl_hash_sha1   */},
@@ -188,17 +233,17 @@ TEST_P(TlsHkdfTest, HkdfKey1Only) {
       {0x41, 0x6c, 0x53, 0x92, 0xb9, 0xf3, 0x6d, 0xf1, 0x88, 0xe9, 0x0e,
        0xb1, 0x4d, 0x17, 0xbf, 0x0d, 0xa1, 0x90, 0xbf, 0xdb, 0x7f, 0x1f,
        0x49, 0x56, 0xe6, 0xe5, 0x66, 0xa5, 0x69, 0xc8, 0xb1, 0x5c},
       {0x51, 0xb1, 0xd5, 0xb4, 0x59, 0x79, 0x79, 0x08, 0x4a, 0x15, 0xb2, 0xdb,
        0x84, 0xd3, 0xd6, 0xbc, 0xfc, 0x93, 0x45, 0xd9, 0xdc, 0x74, 0xda, 0x1a,
        0x57, 0xc2, 0x76, 0x9f, 0x3f, 0x83, 0x45, 0x2f, 0xf6, 0xf3, 0x56, 0x1f,
        0x58, 0x63, 0xdb, 0x88, 0xda, 0x40, 0xce, 0x63, 0x7d, 0x24, 0x37, 0xf3}};
 
-  const DataBuffer expected_data(tv[hash_type_], kHashLength[hash_type_]);
+  const DataBuffer expected_data(tv[hash_type_], GetHashLength(hash_type_));
   HkdfExtract(k1_, nullptr, hash_type_, expected_data);
 }
 
 TEST_P(TlsHkdfTest, HkdfKey2Only) {
   const uint8_t tv[][48] = {
       {/* ssl_hash_none   */},
       {/* ssl_hash_md5    */},
       {/* ssl_hash_sha1   */},
@@ -206,17 +251,17 @@ TEST_P(TlsHkdfTest, HkdfKey2Only) {
       {0x16, 0xaf, 0x00, 0x54, 0x3a, 0x56, 0xc8, 0x26, 0xa2, 0xa7, 0xfc,
        0xb6, 0x34, 0x66, 0x8a, 0xfd, 0x36, 0xdc, 0x8e, 0xce, 0xc4, 0xd2,
        0x6c, 0x7a, 0xdc, 0xe3, 0x70, 0x36, 0x3d, 0x60, 0xfa, 0x0b},
       {0x7b, 0x40, 0xf9, 0xef, 0x91, 0xff, 0xc9, 0xd1, 0x29, 0x24, 0x5c, 0xbf,
        0xf8, 0x82, 0x76, 0x68, 0xae, 0x4b, 0x63, 0xe8, 0x03, 0xdd, 0x39, 0xa8,
        0xd4, 0x6a, 0xf6, 0xe5, 0xec, 0xea, 0xf8, 0x7d, 0x91, 0x71, 0x81, 0xf1,
        0xdb, 0x3b, 0xaf, 0xbf, 0xde, 0x71, 0x61, 0x15, 0xeb, 0xb5, 0x5f, 0x68}};
 
-  const DataBuffer expected_data(tv[hash_type_], kHashLength[hash_type_]);
+  const DataBuffer expected_data(tv[hash_type_], GetHashLength(hash_type_));
   HkdfExtract(nullptr, k2_, hash_type_, expected_data);
 }
 
 TEST_P(TlsHkdfTest, HkdfKey1Key2) {
   const uint8_t tv[][48] = {
       {/* ssl_hash_none   */},
       {/* ssl_hash_md5    */},
       {/* ssl_hash_sha1   */},
@@ -224,17 +269,17 @@ TEST_P(TlsHkdfTest, HkdfKey1Key2) {
       {0xa5, 0x68, 0x02, 0x5a, 0x95, 0xc9, 0x7f, 0x55, 0x38, 0xbc, 0xf7,
        0x97, 0xcc, 0x0f, 0xd5, 0xf6, 0xa8, 0x8d, 0x15, 0xbc, 0x0e, 0x85,
        0x74, 0x70, 0x3c, 0xa3, 0x65, 0xbd, 0x76, 0xcf, 0x9f, 0xd3},
       {0x01, 0x93, 0xc0, 0x07, 0x3f, 0x6a, 0x83, 0x0e, 0x2e, 0x4f, 0xb2, 0x58,
        0xe4, 0x00, 0x08, 0x5c, 0x68, 0x9c, 0x37, 0x32, 0x00, 0x37, 0xff, 0xc3,
        0x1c, 0x5b, 0x98, 0x0b, 0x02, 0x92, 0x3f, 0xfd, 0x73, 0x5a, 0x6f, 0x2a,
        0x95, 0xa3, 0xee, 0xf6, 0xd6, 0x8e, 0x6f, 0x86, 0xea, 0x63, 0xf8, 0x33}};
 
-  const DataBuffer expected_data(tv[hash_type_], kHashLength[hash_type_]);
+  const DataBuffer expected_data(tv[hash_type_], GetHashLength(hash_type_));
   HkdfExtract(k1_, k2_, hash_type_, expected_data);
 }
 
 TEST_P(TlsHkdfTest, HkdfExpandLabel) {
   const uint8_t tv[][48] = {
       {/* ssl_hash_none   */},
       {/* ssl_hash_md5    */},
       {/* ssl_hash_sha1   */},
@@ -242,19 +287,118 @@ TEST_P(TlsHkdfTest, HkdfExpandLabel) {
       {0x3e, 0x4e, 0x6e, 0xd0, 0xbc, 0xc4, 0xf4, 0xff, 0xf0, 0xf5, 0x69,
        0xd0, 0x6c, 0x1e, 0x0e, 0x10, 0x32, 0xaa, 0xd7, 0xa3, 0xef, 0xf6,
        0xa8, 0x65, 0x8e, 0xbe, 0xee, 0xc7, 0x1f, 0x01, 0x6d, 0x3c},
       {0x41, 0xea, 0x77, 0x09, 0x8c, 0x90, 0x04, 0x10, 0xec, 0xbc, 0x37, 0xd8,
        0x5b, 0x54, 0xcd, 0x7b, 0x08, 0x15, 0x13, 0x20, 0xed, 0x1e, 0x3f, 0x54,
        0x74, 0xf7, 0x8b, 0x06, 0x38, 0x28, 0x06, 0x37, 0x75, 0x23, 0xa2, 0xb7,
        0x34, 0xb1, 0x72, 0x2e, 0x59, 0x6d, 0x5a, 0x31, 0xf5, 0x53, 0xab, 0x99}};
 
-  const DataBuffer expected_data(tv[hash_type_], kHashLength[hash_type_]);
-  HkdfExpandLabel(&k1_, hash_type_, kSessionHash, kHashLength[hash_type_],
+  const DataBuffer expected_data(tv[hash_type_], GetHashLength(hash_type_));
+  HkdfExpandLabel(&k1_, hash_type_, kSessionHash, GetHashLength(hash_type_),
                   kLabelMasterSecret, strlen(kLabelMasterSecret),
                   expected_data);
 }
 
+TEST_P(TlsHkdfTest, HkdfExpandLabelNoHash) {
+  const uint8_t tv[][48] = {
+      {/* ssl_hash_none   */},
+      {/* ssl_hash_md5    */},
+      {/* ssl_hash_sha1   */},
+      {/* ssl_hash_sha224 */},
+      {0xb7, 0x08, 0x00, 0xe3, 0x8e, 0x48, 0x68, 0x91, 0xb1, 0x0f, 0x5e,
+       0x6f, 0x22, 0x53, 0x6b, 0x84, 0x69, 0x75, 0xaa, 0xa3, 0x2a, 0xe7,
+       0xde, 0xaa, 0xc3, 0xd1, 0xb4, 0x05, 0x22, 0x5c, 0x68, 0xf5},
+      {0x13, 0xd3, 0x36, 0x9f, 0x3c, 0x78, 0xa0, 0x32, 0x40, 0xee, 0x16, 0xe9,
+       0x11, 0x12, 0x66, 0xc7, 0x51, 0xad, 0xd8, 0x3c, 0xa1, 0xa3, 0x97, 0x74,
+       0xd7, 0x45, 0xff, 0xa7, 0x88, 0x9e, 0x52, 0x17, 0x2e, 0xaa, 0x3a, 0xd2,
+       0x35, 0xd8, 0xd5, 0x35, 0xfd, 0x65, 0x70, 0x9f, 0xa9, 0xf9, 0xfa, 0x23}};
+
+  const DataBuffer expected_data(tv[hash_type_], GetHashLength(hash_type_));
+  HkdfExpandLabel(&k1_, hash_type_, nullptr, 0, kLabelMasterSecret,
+                  strlen(kLabelMasterSecret), expected_data);
+}
+
+TEST_P(TlsHkdfTest, BadExtractWrapperInput) {
+  PK11SymKey* key = nullptr;
+
+  // Bad version.
+  EXPECT_EQ(SECFailure,
+            SSL_HkdfExtract(SSL_LIBRARY_VERSION_TLS_1_2, TLS_AES_128_GCM_SHA256,
+                            k1_.get(), k2_.get(), &key));
+  EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+
+  // Bad ciphersuite.
+  EXPECT_EQ(SECFailure,
+            SSL_HkdfExtract(SSL_LIBRARY_VERSION_TLS_1_3, TLS_RSA_WITH_NULL_SHA,
+                            k1_.get(), k2_.get(), &key));
+  EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+
+  // Old ciphersuite.
+  EXPECT_EQ(SECFailure, SSL_HkdfExtract(SSL_LIBRARY_VERSION_TLS_1_3,
+                                        TLS_RSA_WITH_AES_128_CBC_SHA, k1_.get(),
+                                        k2_.get(), &key));
+  EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+
+  // NULL outparam..
+  EXPECT_EQ(SECFailure, SSL_HkdfExtract(SSL_LIBRARY_VERSION_TLS_1_3,
+                                        TLS_RSA_WITH_AES_128_CBC_SHA, k1_.get(),
+                                        k2_.get(), nullptr));
+  EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+
+  EXPECT_EQ(nullptr, key);
+}
+
+TEST_P(TlsHkdfTest, BadDeriveSecretWrapperInput) {
+  PK11SymKey* key = nullptr;
+  static const char* kLabel = "label";
+
+  // Bad version.
+  EXPECT_EQ(SECFailure, SSL_HkdfDeriveSecret(SSL_LIBRARY_VERSION_TLS_1_2,
+                                             TLS_AES_128_GCM_SHA256, k1_.get(),
+                                             kLabel, strlen(kLabel), &key));
+  EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+
+  // Bad ciphersuite.
+  EXPECT_EQ(SECFailure, SSL_HkdfDeriveSecret(SSL_LIBRARY_VERSION_TLS_1_3,
+                                             TLS_RSA_WITH_NULL_MD5, k1_.get(),
+                                             kLabel, strlen(kLabel), &key));
+  EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+
+  // Old ciphersuite.
+  EXPECT_EQ(SECFailure,
+            SSL_HkdfDeriveSecret(SSL_LIBRARY_VERSION_TLS_1_3,
+                                 TLS_RSA_WITH_AES_128_CBC_SHA, k1_.get(),
+                                 kLabel, strlen(kLabel), &key));
+  EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+
+  // Null PRK.
+  EXPECT_EQ(SECFailure, SSL_HkdfDeriveSecret(SSL_LIBRARY_VERSION_TLS_1_2,
+                                             TLS_AES_128_GCM_SHA256, nullptr,
+                                             kLabel, strlen(kLabel), &key));
+  EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+
+  // Null, non-zero-length label.
+  EXPECT_EQ(SECFailure, SSL_HkdfDeriveSecret(SSL_LIBRARY_VERSION_TLS_1_3,
+                                             TLS_AES_128_GCM_SHA256, k1_.get(),
+                                             nullptr, strlen(kLabel), &key));
+  EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+
+  // Null, empty label.
+  EXPECT_EQ(SECFailure, SSL_HkdfDeriveSecret(SSL_LIBRARY_VERSION_TLS_1_3,
+                                             TLS_AES_128_GCM_SHA256, k1_.get(),
+                                             nullptr, 0, &key));
+  EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+
+  // Null key pointer..
+  EXPECT_EQ(SECFailure, SSL_HkdfDeriveSecret(SSL_LIBRARY_VERSION_TLS_1_3,
+                                             TLS_AES_128_GCM_SHA256, k1_.get(),
+                                             kLabel, strlen(kLabel), nullptr));
+  EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+
+  EXPECT_EQ(nullptr, key);
+}
+
 static const SSLHashType kHashTypes[] = {ssl_hash_sha256, ssl_hash_sha384};
 INSTANTIATE_TEST_CASE_P(AllHashFuncs, TlsHkdfTest,
                         ::testing::ValuesIn(kHashTypes));
 
 }  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/tls_protect.cc
+++ b/security/nss/gtests/ssl_gtest/tls_protect.cc
@@ -1,217 +1,103 @@
 /* -*- 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 "tls_protect.h"
+#include "sslproto.h"
 #include "tls_filter.h"
 
-// Do this to avoid having to re-implement HKDF.
-#include "tls13hkdf.h"
-
 namespace nss_test {
 
-AeadCipher::~AeadCipher() {
-  if (key_) {
-    PK11_FreeSymKey(key_);
-  }
-}
-
-bool AeadCipher::Init(PK11SymKey* key, const uint8_t* iv) {
-  key_ = key;
-  if (!key_) return false;
-
-  memcpy(iv_, iv, sizeof(iv_));
-  if (g_ssl_gtest_verbose) {
-    EXPECT_EQ(SECSuccess, PK11_ExtractKeyValue(key_));
-    SECItem* raw_key = PK11_GetKeyData(key_);
-    std::cerr << "key: " << DataBuffer(raw_key->data, raw_key->len)
-              << std::endl;
-    std::cerr << "iv: " << DataBuffer(iv_, 12) << std::endl;
-  }
-  return true;
-}
-
-void AeadCipher::FormatNonce(uint64_t seq, uint8_t* nonce) {
-  memcpy(nonce, iv_, 12);
-
-  for (size_t i = 0; i < 8; ++i) {
-    nonce[12 - (i + 1)] ^= seq & 0xff;
-    seq >>= 8;
-  }
-}
-
-bool AeadCipher::AeadInner(bool decrypt, void* params, size_t param_length,
-                           const uint8_t* in, size_t inlen, uint8_t* out,
-                           size_t* outlen, size_t maxlen) {
-  SECStatus rv;
-  unsigned int uoutlen = 0;
-  SECItem param = {
-      siBuffer, static_cast<unsigned char*>(params),
-      static_cast<unsigned int>(param_length),
-  };
-
-  if (decrypt) {
-    rv = PK11_Decrypt(key_, mech_, &param, out, &uoutlen, maxlen, in, inlen);
-  } else {
-    rv = PK11_Encrypt(key_, mech_, &param, out, &uoutlen, maxlen, in, inlen);
-  }
-  *outlen = (int)uoutlen;
-
-  return rv == SECSuccess;
-}
-
-bool AeadCipherAesGcm::Aead(bool decrypt, const uint8_t* hdr, size_t hdr_len,
-                            uint64_t seq, const uint8_t* in, size_t inlen,
-                            uint8_t* out, size_t* outlen, size_t maxlen) {
-  CK_GCM_PARAMS aeadParams;
-  unsigned char nonce[12];
-
-  memset(&aeadParams, 0, sizeof(aeadParams));
-  aeadParams.pIv = nonce;
-  aeadParams.ulIvLen = sizeof(nonce);
-  aeadParams.pAAD = const_cast<uint8_t*>(hdr);
-  aeadParams.ulAADLen = hdr_len;
-  aeadParams.ulTagBits = 128;
-
-  FormatNonce(seq, nonce);
-  return AeadInner(decrypt, (unsigned char*)&aeadParams, sizeof(aeadParams), in,
-                   inlen, out, outlen, maxlen);
-}
-
-bool AeadCipherChacha20Poly1305::Aead(bool decrypt, const uint8_t* hdr,
-                                      size_t hdr_len, uint64_t seq,
-                                      const uint8_t* in, size_t inlen,
-                                      uint8_t* out, size_t* outlen,
-                                      size_t maxlen) {
-  CK_NSS_AEAD_PARAMS aeadParams;
-  unsigned char nonce[12];
-
-  memset(&aeadParams, 0, sizeof(aeadParams));
-  aeadParams.pNonce = nonce;
-  aeadParams.ulNonceLen = sizeof(nonce);
-  aeadParams.pAAD = const_cast<uint8_t*>(hdr);
-  aeadParams.ulAADLen = hdr_len;
-  aeadParams.ulTagLen = 16;
-
-  FormatNonce(seq, nonce);
-  return AeadInner(decrypt, (unsigned char*)&aeadParams, sizeof(aeadParams), in,
-                   inlen, out, outlen, maxlen);
-}
-
 static uint64_t FirstSeqno(bool dtls, uint16_t epoc) {
   if (dtls) {
     return static_cast<uint64_t>(epoc) << 48;
   }
   return 0;
 }
 
 TlsCipherSpec::TlsCipherSpec(bool dtls, uint16_t epoc)
     : dtls_(dtls),
       epoch_(epoc),
       in_seqno_(FirstSeqno(dtls, epoc)),
       out_seqno_(FirstSeqno(dtls, epoc)) {}
 
 bool TlsCipherSpec::SetKeys(SSLCipherSuiteInfo* cipherinfo,
                             PK11SymKey* secret) {
-  CK_MECHANISM_TYPE mech;
-  switch (cipherinfo->symCipher) {
-    case ssl_calg_aes_gcm:
-      aead_.reset(new AeadCipherAesGcm());
-      mech = CKM_AES_GCM;
-      break;
-    case ssl_calg_chacha20:
-      aead_.reset(new AeadCipherChacha20Poly1305());
-      mech = CKM_NSS_CHACHA20_POLY1305;
-      break;
-    default:
-      return false;
-  }
-
-  PK11SymKey* key;
-  const std::string kPurposeKey = "key";
-  SECStatus rv = tls13_HkdfExpandLabel(
-      secret, cipherinfo->kdfHash, NULL, 0, kPurposeKey.c_str(),
-      kPurposeKey.length(), mech, cipherinfo->symKeyBits / 8, &key);
+  SSLAeadContext* ctx;
+  SECStatus rv = SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3,
+                              cipherinfo->cipherSuite, secret, "",
+                              0,  // Use the default labels.
+                              &ctx);
   if (rv != SECSuccess) {
-    ADD_FAILURE() << "unable to derive key for epoch " << epoch_;
     return false;
   }
-
-  // No constant for IV length, but everything we know of uses 12.
-  uint8_t iv[12];
-  const std::string kPurposeIv = "iv";
-  rv = tls13_HkdfExpandLabelRaw(secret, cipherinfo->kdfHash, NULL, 0,
-                                kPurposeIv.c_str(), kPurposeIv.length(), iv,
-                                sizeof(iv));
-  if (rv != SECSuccess) {
-    ADD_FAILURE() << "unable to derive IV for epoch " << epoch_;
-    return false;
-  }
-
-  return aead_->Init(key, iv);
+  aead_.reset(ctx);
+  return true;
 }
 
 bool TlsCipherSpec::Unprotect(const TlsRecordHeader& header,
                               const DataBuffer& ciphertext,
                               DataBuffer* plaintext) {
   if (aead_ == nullptr) {
     return false;
   }
   // Make space.
   plaintext->Allocate(ciphertext.len());
 
   auto header_bytes = header.header();
-  size_t len;
+  unsigned int len;
   uint64_t seqno;
   if (dtls_) {
     seqno = header.sequence_number();
   } else {
     seqno = in_seqno_;
   }
-  bool ret = aead_->Aead(true, header_bytes.data(), header_bytes.len(), seqno,
-                         ciphertext.data(), ciphertext.len(), plaintext->data(),
-                         &len, plaintext->len());
-  if (!ret) {
+  SECStatus rv =
+      SSL_AeadDecrypt(aead_.get(), seqno, header_bytes.data(),
+                      header_bytes.len(), ciphertext.data(), ciphertext.len(),
+                      plaintext->data(), &len, plaintext->len());
+  if (rv != SECSuccess) {
     return false;
   }
 
   RecordUnprotected(seqno);
-  plaintext->Truncate(len);
+  plaintext->Truncate(static_cast<size_t>(len));
 
   return true;
 }
 
 bool TlsCipherSpec::Protect(const TlsRecordHeader& header,
                             const DataBuffer& plaintext,
                             DataBuffer* ciphertext) {
   if (aead_ == nullptr) {
     return false;
   }
   // Make a padded buffer.
   ciphertext->Allocate(plaintext.len() +
                        32);  // Room for any plausible auth tag
-  size_t len;
+  unsigned int len;
 
   DataBuffer header_bytes;
   (void)header.WriteHeader(&header_bytes, 0, plaintext.len() + 16);
   uint64_t seqno;
   if (dtls_) {
     seqno = header.sequence_number();
   } else {
     seqno = out_seqno_;
   }
 
-  bool ret = aead_->Aead(false, header_bytes.data(), header_bytes.len(), seqno,
-                         plaintext.data(), plaintext.len(), ciphertext->data(),
-                         &len, ciphertext->len());
-  if (!ret) {
+  SECStatus rv =
+      SSL_AeadEncrypt(aead_.get(), seqno, header_bytes.data(),
+                      header_bytes.len(), plaintext.data(), plaintext.len(),
+                      ciphertext->data(), &len, ciphertext->len());
+  if (rv != SECSuccess) {
     return false;
   }
 
   RecordProtected();
   ciphertext->Truncate(len);
 
   return true;
 }
--- a/security/nss/gtests/ssl_gtest/tls_protect.h
+++ b/security/nss/gtests/ssl_gtest/tls_protect.h
@@ -5,64 +5,26 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef tls_protection_h_
 #define tls_protection_h_
 
 #include <cstdint>
 #include <memory>
 
-#include "databuffer.h"
 #include "pk11pub.h"
 #include "sslt.h"
+#include "sslexp.h"
+
+#include "databuffer.h"
+#include "scoped_ptrs_ssl.h"
 
 namespace nss_test {
 class TlsRecordHeader;
 
-class AeadCipher {
- public:
-  AeadCipher(CK_MECHANISM_TYPE mech) : mech_(mech), key_(nullptr) {}
-  virtual ~AeadCipher();
-
-  bool Init(PK11SymKey* key, const uint8_t* iv);
-  virtual bool Aead(bool decrypt, const uint8_t* hdr, size_t hdr_len,
-                    uint64_t seq, const uint8_t* in, size_t inlen, uint8_t* out,
-                    size_t* outlen, size_t maxlen) = 0;
-
- protected:
-  void FormatNonce(uint64_t seq, uint8_t* nonce);
-  bool AeadInner(bool decrypt, void* params, size_t param_length,
-                 const uint8_t* in, size_t inlen, uint8_t* out, size_t* outlen,
-                 size_t maxlen);
-
-  CK_MECHANISM_TYPE mech_;
-  PK11SymKey* key_;
-  uint8_t iv_[12];
-};
-
-class AeadCipherChacha20Poly1305 : public AeadCipher {
- public:
-  AeadCipherChacha20Poly1305() : AeadCipher(CKM_NSS_CHACHA20_POLY1305) {}
-
- protected:
-  bool Aead(bool decrypt, const uint8_t* hdr, size_t hdr_len, uint64_t seq,
-            const uint8_t* in, size_t inlen, uint8_t* out, size_t* outlen,
-            size_t maxlen);
-};
-
-class AeadCipherAesGcm : public AeadCipher {
- public:
-  AeadCipherAesGcm() : AeadCipher(CKM_AES_GCM) {}
-
- protected:
-  bool Aead(bool decrypt, const uint8_t* hdr, size_t hdr_len, uint64_t seq,
-            const uint8_t* in, size_t inlen, uint8_t* out, size_t* outlen,
-            size_t maxlen);
-};
-
 // Our analog of ssl3CipherSpec
 class TlsCipherSpec {
  public:
   TlsCipherSpec(bool dtls, uint16_t epoc);
   bool SetKeys(SSLCipherSuiteInfo* cipherinfo, PK11SymKey* secret);
 
   bool Protect(const TlsRecordHeader& header, const DataBuffer& plaintext,
                DataBuffer* ciphertext);
@@ -84,14 +46,14 @@ class TlsCipherSpec {
   bool is_protected() const { return aead_ != nullptr; }
 
  private:
   bool dtls_;
   uint16_t epoch_;
   uint64_t in_seqno_;
   uint64_t out_seqno_;
   bool record_dropped_ = false;
-  std::unique_ptr<AeadCipher> aead_;
+  ScopedSSLAeadContext aead_;
 };
 
 }  // namespace nss_test
 
 #endif
--- a/security/nss/lib/certhigh/certvfy.c
+++ b/security/nss/lib/certhigh/certvfy.c
@@ -32,26 +32,32 @@
  */
 SECStatus
 CERT_CertTimesValid(CERTCertificate *c)
 {
     SECCertTimeValidity valid = CERT_CheckCertValidTimes(c, PR_Now(), PR_TRUE);
     return (valid == secCertTimeValid) ? SECSuccess : SECFailure;
 }
 
-SECStatus
+static SECStatus
 checkKeyParams(const SECAlgorithmID *sigAlgorithm, const SECKEYPublicKey *key)
 {
     SECStatus rv;
     SECOidTag sigAlg;
     SECOidTag curve;
     PRUint32 policyFlags = 0;
     PRInt32 minLen, len;
 
     sigAlg = SECOID_GetAlgorithmTag(sigAlgorithm);
+    rv = NSS_GetAlgorithmPolicy(sigAlg, &policyFlags);
+    if (rv == SECSuccess &&
+        !(policyFlags & NSS_USE_ALG_IN_CERT_SIGNATURE)) {
+        PORT_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+        return SECFailure;
+    }
 
     switch (sigAlg) {
         case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
         case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE:
         case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
         case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
         case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
             if (key->keyType != ecKey) {
--- a/security/nss/lib/freebl/unix_urandom.c
+++ b/security/nss/lib/freebl/unix_urandom.c
@@ -27,17 +27,17 @@ RNG_SystemInfoForRNG(void)
 size_t
 RNG_SystemRNG(void *dest, size_t maxLen)
 {
     int fd;
     int bytes;
     size_t fileBytes = 0;
     unsigned char *buffer = dest;
 
-#if defined(__OpenBSD__) || (defined(LINUX) && defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 25))))
+#if defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD_version >= 1200000) || (defined(LINUX) && defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 25))))
     int result;
 
     while (fileBytes < maxLen) {
         size_t getBytes = maxLen - fileBytes;
         if (getBytes > GETENTROPY_MAX_BYTES) {
             getBytes = GETENTROPY_MAX_BYTES;
         }
         result = getentropy(buffer, getBytes);
--- a/security/nss/lib/pk11wrap/pk11pars.c
+++ b/security/nss/lib/pk11wrap/pk11pars.c
@@ -379,28 +379,36 @@ static const oidValDef kxOptList[] = {
     { CIPHER_NAME("DH-RSA"), SEC_OID_TLS_DH_RSA, NSS_USE_ALG_IN_SSL_KX },
     { CIPHER_NAME("DH-DSS"), SEC_OID_TLS_DH_DSS, NSS_USE_ALG_IN_SSL_KX },
     { CIPHER_NAME("ECDHE-ECDSA"), SEC_OID_TLS_ECDHE_ECDSA, NSS_USE_ALG_IN_SSL_KX },
     { CIPHER_NAME("ECDHE-RSA"), SEC_OID_TLS_ECDHE_RSA, NSS_USE_ALG_IN_SSL_KX },
     { CIPHER_NAME("ECDH-ECDSA"), SEC_OID_TLS_ECDH_ECDSA, NSS_USE_ALG_IN_SSL_KX },
     { CIPHER_NAME("ECDH-RSA"), SEC_OID_TLS_ECDH_RSA, NSS_USE_ALG_IN_SSL_KX },
 };
 
+static const oidValDef signOptList[] = {
+    /* Signatures */
+    { CIPHER_NAME("DSA"), SEC_OID_ANSIX9_DSA_SIGNATURE,
+      NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
+};
+
 typedef struct {
     const oidValDef *list;
     PRUint32 entries;
     const char *description;
+    PRBool allowEmpty;
 } algListsDef;
 
 static const algListsDef algOptLists[] = {
-    { curveOptList, PR_ARRAY_SIZE(curveOptList), "ECC" },
-    { hashOptList, PR_ARRAY_SIZE(hashOptList), "HASH" },
-    { macOptList, PR_ARRAY_SIZE(macOptList), "MAC" },
-    { cipherOptList, PR_ARRAY_SIZE(cipherOptList), "CIPHER" },
-    { kxOptList, PR_ARRAY_SIZE(kxOptList), "OTHER-KX" },
+    { curveOptList, PR_ARRAY_SIZE(curveOptList), "ECC", PR_FALSE },
+    { hashOptList, PR_ARRAY_SIZE(hashOptList), "HASH", PR_FALSE },
+    { macOptList, PR_ARRAY_SIZE(macOptList), "MAC", PR_FALSE },
+    { cipherOptList, PR_ARRAY_SIZE(cipherOptList), "CIPHER", PR_FALSE },
+    { kxOptList, PR_ARRAY_SIZE(kxOptList), "OTHER-KX", PR_FALSE },
+    { signOptList, PR_ARRAY_SIZE(signOptList), "OTHER-SIGN", PR_TRUE },
 };
 
 static const optionFreeDef sslOptList[] = {
     /* Versions */
     { CIPHER_NAME("SSL2.0"), 0x002 },
     { CIPHER_NAME("SSL3.0"), 0x300 },
     { CIPHER_NAME("SSL3.1"), 0x301 },
     { CIPHER_NAME("TLS1.0"), 0x301 },
@@ -713,17 +721,17 @@ secmod_sanityCheckCryptoPolicy(void)
     fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-SSL-ALG: %u\n", num_ssl_enabled ? sInfo : sWarn, num_ssl_enabled);
     fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-CERT-SIG: %u\n", num_sig_enabled ? sInfo : sWarn, num_sig_enabled);
     if (!num_kx_enabled || !num_ssl_enabled || !num_sig_enabled) {
         haveWarning = PR_TRUE;
     }
     for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
         const algListsDef *algOptList = &algOptLists[i];
         fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-%s: %u\n", enabledCount[i] ? sInfo : sWarn, algOptList->description, enabledCount[i]);
-        if (!enabledCount[i]) {
+        if (!enabledCount[i] && !algOptList->allowEmpty) {
             haveWarning = PR_TRUE;
         }
     }
     if (haveWarning) {
         PR_SetEnv("NSS_POLICY_WARN=1");
     }
 }
 
--- a/security/nss/lib/ssl/manifest.mn
+++ b/security/nss/lib/ssl/manifest.mn
@@ -50,16 +50,17 @@ CSRCS = \
         ssl3ecc.c \
         tls13con.c \
         tls13exthandle.c \
         tls13hashstate.c \
         tls13hkdf.c \
         tls13replay.c \
         sslcert.c \
         sslgrp.c \
+        sslprimitive.c \
         tls13esni.c \
         $(NULL)
 
 LIBRARY_NAME = ssl
 LIBRARY_VERSION = 3
 
 # This part of the code, including all sub-dirs, can be optimized for size
 export ALLOW_OPT_CODE_SIZE = 1
--- a/security/nss/lib/ssl/ssl.gyp
+++ b/security/nss/lib/ssl/ssl.gyp
@@ -30,16 +30,17 @@
         'sslenum.c',
         'sslerr.c',
         'sslerrstrs.c',
         'sslgrp.c',
         'sslinfo.c',
         'sslinit.c',
         'sslmutex.c',
         'sslnonce.c',
+        'sslprimitive.c',
         'sslreveal.c',
         'sslsecur.c',
         'sslsnce.c',
         'sslsock.c',
         'sslspec.c',
         'ssltrace.c',
         'sslver.c',
         'tls13con.c',
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -59,16 +59,17 @@ static SECStatus ssl3_HandleServerHelloP
 static SECStatus ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss,
                                                       PRUint8 *b,
                                                       PRUint32 length);
 static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags);
 
 static CK_MECHANISM_TYPE ssl3_GetHashMechanismByHashType(SSLHashType hashType);
 static CK_MECHANISM_TYPE ssl3_GetMgfMechanismByHashType(SSLHashType hash);
 PRBool ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme);
+PRBool ssl_IsDsaSignatureScheme(SSLSignatureScheme scheme);
 
 const PRUint8 ssl_hello_retry_random[] = {
     0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11,
     0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91,
     0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E,
     0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C
 };
 PR_STATIC_ASSERT(PR_ARRAY_SIZE(ssl_hello_retry_random) == SSL3_RANDOM_LENGTH);
@@ -548,20 +549,19 @@ SSL_AtomicIncrementLong(long *x)
         PR_ATOMIC_INCREMENT((PRInt32 *)x);
     } else {
         tooLong *tl = (tooLong *)x;
         if (PR_ATOMIC_INCREMENT(&tl->low) == 0)
             PR_ATOMIC_INCREMENT(&tl->high);
     }
 }
 
-static PRBool
-ssl3_CipherSuiteAllowedForVersionRange(
-    ssl3CipherSuite cipherSuite,
-    const SSLVersionRange *vrange)
+PRBool
+ssl3_CipherSuiteAllowedForVersionRange(ssl3CipherSuite cipherSuite,
+                                       const SSLVersionRange *vrange)
 {
     switch (cipherSuite) {
         case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
         case TLS_RSA_WITH_AES_256_CBC_SHA256:
         case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
         case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
         case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
         case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
@@ -907,18 +907,18 @@ count_cipher_suites(sslSocket *ss, PRUin
     }
     return count;
 }
 
 /*
  * Null compression, mac and encryption functions
  */
 SECStatus
-Null_Cipher(void *ctx, unsigned char *output, int *outputLen, int maxOutputLen,
-            const unsigned char *input, int inputLen)
+Null_Cipher(void *ctx, unsigned char *output, unsigned int *outputLen, unsigned int maxOutputLen,
+            const unsigned char *input, unsigned int inputLen)
 {
     if (inputLen > maxOutputLen) {
         *outputLen = 0; /* Match PK11_CipherOp in setting outputLen */
         PORT_SetError(SEC_ERROR_OUTPUT_LEN);
         return SECFailure;
     }
     *outputLen = inputLen;
     if (inputLen > 0 && input != output) {
@@ -1549,25 +1549,25 @@ ssl3_BuildRecordPseudoHeader(DTLSEpoch e
     if (rv != SECSuccess) {
         return SECFailure;
     }
 
     return SECSuccess;
 }
 
 static SECStatus
-ssl3_AESGCM(ssl3KeyMaterial *keys,
+ssl3_AESGCM(const ssl3KeyMaterial *keys,
             PRBool doDecrypt,
             unsigned char *out,
-            int *outlen,
-            int maxout,
+            unsigned int *outlen,
+            unsigned int maxout,
             const unsigned char *in,
-            int inlen,
+            unsigned int inlen,
             const unsigned char *additionalData,
-            int additionalDataLen)
+            unsigned int additionalDataLen)
 {
     SECItem param;
     SECStatus rv = SECFailure;
     unsigned char nonce[12];
     unsigned int uOutLen;
     CK_GCM_PARAMS gcmParams;
 
     const int tagSize = 16;
@@ -1611,21 +1611,21 @@ ssl3_AESGCM(ssl3KeyMaterial *keys,
                           maxout, in, inlen);
     }
     *outlen += (int)uOutLen;
 
     return rv;
 }
 
 static SECStatus
-ssl3_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt,
-                      unsigned char *out, int *outlen, int maxout,
-                      const unsigned char *in, int inlen,
+ssl3_ChaCha20Poly1305(const ssl3KeyMaterial *keys, PRBool doDecrypt,
+                      unsigned char *out, unsigned int *outlen, unsigned int maxout,
+                      const unsigned char *in, unsigned int inlen,
                       const unsigned char *additionalData,
-                      int additionalDataLen)
+                      unsigned int additionalDataLen)
 {
     size_t i;
     SECItem param;
     SECStatus rv = SECFailure;
     unsigned int uOutLen;
     unsigned char nonce[12];
     CK_NSS_AEAD_PARAMS aeadParams;
 
@@ -2007,17 +2007,17 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cw
 {
     SECStatus rv;
     PRUint32 macLen = 0;
     PRUint32 fragLen;
     PRUint32 p1Len, p2Len, oddLen = 0;
     unsigned int ivLen = 0;
     unsigned char pseudoHeaderBuf[13];
     sslBuffer pseudoHeader = SSL_BUFFER(pseudoHeaderBuf);
-    int len;
+    unsigned int len;
 
     if (cwSpec->cipherDef->type == type_block &&
         cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
         /* Prepend the per-record explicit IV using technique 2b from
          * RFC 4346 section 6.2.3.2: The IV is a cryptographically
          * strong random number XORed with the CBC residue from the previous
          * record.
          */
@@ -2125,41 +2125,41 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cw
         }
         if (oddLen) {
             p2Len += oddLen;
             PORT_Assert((blockSize < 2) ||
                         (p2Len % blockSize) == 0);
             memmove(SSL_BUFFER_NEXT(wrBuf) + p1Len, pIn + p1Len, oddLen);
         }
         if (p1Len > 0) {
-            int cipherBytesPart1 = -1;
+            unsigned int cipherBytesPart1 = 0;
             rv = cwSpec->cipher(cwSpec->cipherContext,
                                 SSL_BUFFER_NEXT(wrBuf), /* output */
                                 &cipherBytesPart1,      /* actual outlen */
                                 p1Len,                  /* max outlen */
                                 pIn,
                                 p1Len); /* input, and inputlen */
-            PORT_Assert(rv == SECSuccess && cipherBytesPart1 == (int)p1Len);
-            if (rv != SECSuccess || cipherBytesPart1 != (int)p1Len) {
+            PORT_Assert(rv == SECSuccess && cipherBytesPart1 == p1Len);
+            if (rv != SECSuccess || cipherBytesPart1 != p1Len) {
                 PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
                 return SECFailure;
             }
             rv = sslBuffer_Skip(wrBuf, p1Len, NULL);
             PORT_Assert(rv == SECSuccess);
         }
         if (p2Len > 0) {
-            int cipherBytesPart2 = -1;
+            unsigned int cipherBytesPart2 = 0;
             rv = cwSpec->cipher(cwSpec->cipherContext,
                                 SSL_BUFFER_NEXT(wrBuf),
                                 &cipherBytesPart2, /* output and actual outLen */
                                 p2Len,             /* max outlen */
                                 SSL_BUFFER_NEXT(wrBuf),
                                 p2Len); /* input and inputLen*/
-            PORT_Assert(rv == SECSuccess && cipherBytesPart2 == (int)p2Len);
-            if (rv != SECSuccess || cipherBytesPart2 != (int)p2Len) {
+            PORT_Assert(rv == SECSuccess && cipherBytesPart2 == p2Len);
+            if (rv != SECSuccess || cipherBytesPart2 != p2Len) {
                 PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
                 return SECFailure;
             }
             rv = sslBuffer_Skip(wrBuf, p2Len, NULL);
             PORT_Assert(rv == SECSuccess);
         }
     }
 
@@ -2236,17 +2236,17 @@ ssl_ProtectRecord(sslSocket *ss, ssl3Cip
         rv = sslBuffer_Skip(wrBuf, 2, &lenOffset);
         if (rv != SECSuccess) {
             return SECFailure;
         }
     }
 
 #ifdef UNSAFE_FUZZER_MODE
     {
-        int len;
+        unsigned int len;
         rv = Null_Cipher(NULL, SSL_BUFFER_NEXT(wrBuf), &len,
                          SSL_BUFFER_SPACE(wrBuf), pIn, contentLen);
         if (rv != SECSuccess) {
             return SECFailure; /* error was set */
         }
         rv = sslBuffer_Skip(wrBuf, len, NULL);
         PORT_Assert(rv == SECSuccess); /* Can't fail. */
     }
@@ -4315,16 +4315,32 @@ ssl_IsRsaPssSignatureScheme(SSLSignature
             return PR_TRUE;
 
         default:
             return PR_FALSE;
     }
     return PR_FALSE;
 }
 
+PRBool
+ssl_IsDsaSignatureScheme(SSLSignatureScheme scheme)
+{
+    switch (scheme) {
+        case ssl_sig_dsa_sha256:
+        case ssl_sig_dsa_sha384:
+        case ssl_sig_dsa_sha512:
+        case ssl_sig_dsa_sha1:
+            return PR_TRUE;
+
+        default:
+            return PR_FALSE;
+    }
+    return PR_FALSE;
+}
+
 SSLAuthType
 ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme)
 {
     switch (scheme) {
         case ssl_sig_rsa_pkcs1_sha1:
         case ssl_sig_rsa_pkcs1_sha1md5:
         case ssl_sig_rsa_pkcs1_sha256:
         case ssl_sig_rsa_pkcs1_sha384:
@@ -6027,16 +6043,23 @@ ssl_CanUseSignatureScheme(SSLSignatureSc
     unsigned int i;
 
     /* Skip RSA-PSS schemes when the certificate's private key slot does
      * not support this signature mechanism. */
     if (ssl_IsRsaPssSignatureScheme(scheme) && !slotDoesPss) {
         return PR_FALSE;
     }
 
+    if (ssl_IsDsaSignatureScheme(scheme) &&
+        (NSS_GetAlgorithmPolicy(SEC_OID_ANSIX9_DSA_SIGNATURE, &policy) ==
+         SECSuccess) &&
+        !(policy & NSS_USE_ALG_IN_SSL_KX)) {
+        return PR_FALSE;
+    }
+
     hashType = ssl_SignatureSchemeToHashType(scheme);
     if (requireSha1 && (hashType != ssl_hash_sha1)) {
         return PR_FALSE;
     }
     hashOID = ssl3_HashTypeToOID(hashType);
     if ((NSS_GetAlgorithmPolicy(hashOID, &policy) == SECSuccess) &&
         !(policy & NSS_USE_ALG_IN_SSL_KX)) {
         return PR_FALSE;
@@ -9505,16 +9528,24 @@ ssl3_EncodeSigAlgs(const sslSocket *ss, 
         SECOidTag hashOID = ssl3_HashTypeToOID(hashType);
 
         /* Skip RSA-PSS schemes if there are no tokens to verify them. */
         if (ssl_IsRsaPssSignatureScheme(ss->ssl3.signatureSchemes[i]) &&
             !PK11_TokenExists(auth_alg_defs[ssl_auth_rsa_pss])) {
             continue;
         }
 
+        /* Skip DSA scheme if it is disabled by policy. */
+        if (ssl_IsDsaSignatureScheme(ss->ssl3.signatureSchemes[i]) &&
+            (NSS_GetAlgorithmPolicy(SEC_OID_ANSIX9_DSA_SIGNATURE, &policy) ==
+             SECSuccess) &&
+            !(policy & NSS_USE_ALG_IN_SSL_KX)) {
+            continue;
+        }
+
         if ((NSS_GetAlgorithmPolicy(hashOID, &policy) != SECSuccess) ||
             (policy & NSS_USE_ALG_IN_SSL_KX)) {
             rv = sslBuffer_AppendNumber(buf, ss->ssl3.signatureSchemes[i], 2);
             if (rv != SECSuccess) {
                 return SECFailure;
             }
 
             found = PR_TRUE;
@@ -12195,17 +12226,17 @@ ssl3_UnprotectRecord(sslSocket *ss,
         spec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
         /* Consume the per-record explicit IV. RFC 4346 Section 6.2.3.2 states
          * "The receiver decrypts the entire GenericBlockCipher structure and
          * then discards the first cipher block corresponding to the IV
          * component." Instead, we decrypt the first cipher block and then
          * discard it before decrypting the rest.
          */
         PRUint8 iv[MAX_IV_LENGTH];
-        int decoded;
+        unsigned int decoded;
 
         ivLen = cipher_def->iv_size;
         if (ivLen < 8 || ivLen > sizeof(iv)) {
             *alert = internal_error;
             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
             return SECFailure;
         }
 
@@ -12243,35 +12274,35 @@ ssl3_UnprotectRecord(sslSocket *ss,
         unsigned int decryptedLen =
             cText->buf->len - cipher_def->explicit_nonce_size -
             cipher_def->tag_size;
         rv = ssl3_BuildRecordPseudoHeader(
             spec->epoch, cText->seqNum,
             rType, isTLS, rVersion, IS_DTLS(ss), decryptedLen, &header);
         PORT_Assert(rv == SECSuccess);
         rv = spec->aead(&spec->keyMaterial,
-                        PR_TRUE,                /* do decrypt */
-                        plaintext->buf,         /* out */
-                        (int *)&plaintext->len, /* outlen */
-                        plaintext->space,       /* maxout */
-                        cText->buf->buf,        /* in */
-                        cText->buf->len,        /* inlen */
+                        PR_TRUE,          /* do decrypt */
+                        plaintext->buf,   /* out */
+                        &plaintext->len,  /* outlen */
+                        plaintext->space, /* maxout */
+                        cText->buf->buf,  /* in */
+                        cText->buf->len,  /* inlen */
                         SSL_BUFFER_BASE(&header), SSL_BUFFER_LEN(&header));
         if (rv != SECSuccess) {
             good = 0;
         }
     } else {
         if (cipher_def->type == type_block &&
             ((cText->buf->len - ivLen) % cipher_def->block_size) != 0) {
             goto decrypt_loser;
         }
 
         /* decrypt from cText buf to plaintext. */
         rv = spec->cipher(
-            spec->cipherContext, plaintext->buf, (int *)&plaintext->len,
+            spec->cipherContext, plaintext->buf, &plaintext->len,
             plaintext->space, cText->buf->buf + ivLen, cText->buf->len - ivLen);
         if (rv != SECSuccess) {
             goto decrypt_loser;
         }
 
         PRINT_BUF(80, (ss, "cleartext:", plaintext->buf, plaintext->len));
 
         originalLen = plaintext->len;
@@ -12543,17 +12574,17 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Cip
      * completes in DTLS 1.3. These can look like valid TLS 1.2 application_data
      * records in epoch 0, which is never valid. Pretend they didn't decrypt. */
     if (spec->epoch == 0 && rType == ssl_ct_application_data) {
         PORT_SetError(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA);
         alert = unexpected_message;
         rv = SECFailure;
     } else {
 #ifdef UNSAFE_FUZZER_MODE
-        rv = Null_Cipher(NULL, plaintext->buf, (int *)&plaintext->len,
+        rv = Null_Cipher(NULL, plaintext->buf, &plaintext->len,
                          plaintext->space, cText->buf->buf, cText->buf->len);
 #else
         /* IMPORTANT: Unprotect functions MUST NOT send alerts
          * because we still hold the spec read lock. Instead, if they
          * return SECFailure, they set *alert to the alert to be sent. */
         if (spec->version < SSL_LIBRARY_VERSION_TLS_1_3 ||
             spec->epoch == 0) {
             rv = ssl3_UnprotectRecord(ss, spec, cText, plaintext, &alert);
--- a/security/nss/lib/ssl/ssl3gthr.c
+++ b/security/nss/lib/ssl/ssl3gthr.c
@@ -402,17 +402,17 @@ ssl3_GatherCompleteHandshake(sslSocket *
     int rv;
     SSL3Ciphertext cText;
     PRBool keepGoing = PR_TRUE;
 
     if (ss->ssl3.fatalAlertSent) {
         SSL_TRC(3, ("%d: SSL3[%d] Cannot gather data; fatal alert already sent",
                     SSL_GETPID(), ss->fd));
         PORT_SetError(SSL_ERROR_HANDSHAKE_FAILED);
-        return SECFailure;
+        return -1;
     }
 
     SSL_TRC(30, ("%d: SSL3[%d]: ssl3_GatherCompleteHandshake",
                  SSL_GETPID(), ss->fd));
 
     /* ssl3_HandleRecord may end up eventually calling ssl_FinishHandshake,
      * which requires the 1stHandshakeLock, which must be acquired before the
      * RecvBufLock.
@@ -422,31 +422,35 @@ ssl3_GatherCompleteHandshake(sslSocket *
 
     do {
         PRBool processingEarlyData;
 
         ssl_GetSSL3HandshakeLock(ss);
 
         processingEarlyData = ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted;
 
-        /* If we have a detached record layer, don't ever gather. */
-        if (ss->recordWriteCallback) {
-            ssl_ReleaseSSL3HandshakeLock(ss);
-            PORT_SetError(PR_WOULD_BLOCK_ERROR);
-            return (int)SECFailure;
-        }
-
         /* Without this, we may end up wrongly reporting
          * SSL_ERROR_RX_UNEXPECTED_* errors if we receive any records from the
          * peer while we are waiting to be restarted.
          */
         if (ss->ssl3.hs.restartTarget) {
             ssl_ReleaseSSL3HandshakeLock(ss);
             PORT_SetError(PR_WOULD_BLOCK_ERROR);
-            return (int)SECFailure;
+            return -1;
+        }
+
+        /* If we have a detached record layer, don't ever gather. */
+        if (ss->recordWriteCallback) {
+            PRBool done = ss->firstHsDone;
+            ssl_ReleaseSSL3HandshakeLock(ss);
+            if (done) {
+                return 1;
+            }
+            PORT_SetError(PR_WOULD_BLOCK_ERROR);
+            return -1;
         }
 
         ssl_ReleaseSSL3HandshakeLock(ss);
 
         /* State for SSLv2 client hello support. */
         ssl2Gather ssl2gs = { PR_FALSE, 0 };
         ssl2Gather *ssl2gs_ptr = NULL;
 
@@ -658,17 +662,18 @@ SSLExp_RecordLayerData(PRFileDesc *fd, P
     if (rv != SECSuccess) {
         goto loser;
     }
 
     /* ...and process it.  Just saving application data is enough for it to be
      * available to PR_Read(). */
     if (contentType != ssl_ct_application_data) {
         rv = ssl3_HandleNonApplicationData(ss, contentType, 0, 0, &ss->gs.buf);
-        if (rv != SECSuccess) {
+        /* This occasionally blocks, but that's OK here. */
+        if (rv != SECSuccess && PORT_GetError() != PR_WOULD_BLOCK_ERROR) {
             goto loser;
         }
     }
 
     ssl_ReleaseRecvBufLock(ss);
     ssl_Release1stHandshakeLock(ss);
     return SECSuccess;
 
--- a/security/nss/lib/ssl/sslexp.h
+++ b/security/nss/lib/ssl/sslexp.h
@@ -621,14 +621,88 @@ typedef SECStatus(PR_CALLBACK *SSLRecord
  * See SSL_RecordLayerWriteCallback() for details on epochs.
  */
 #define SSL_GetCurrentEpoch(fd, readEpoch, writeEpoch)             \
     SSL_EXPERIMENTAL_API("SSL_GetCurrentEpoch",                    \
                          (PRFileDesc * _fd, PRUint16 * _readEpoch, \
                           PRUint16 * _writeEpoch),                 \
                          (fd, readEpoch, writeEpoch))
 
+/*
+ * The following AEAD functions expose an AEAD primitive that uses a ciphersuite
+ * to set parameters.  The ciphersuite determines the Hash function used by
+ * HKDF, the AEAD function, and the size of key and IV.  This is only supported
+ * for TLS 1.3.
+ *
+ * The key and IV are generated using the TLS KDF with a custom label.  That is
+ * HKDF-Expand-Label(secret, labelPrefix + " key" or " iv", "", L).
+ *
+ * The encrypt and decrypt functions use a nonce construction identical to that
+ * used in TLS.  The lower bits of the IV are XORed with the 64-bit counter to
+ * produce the nonce.  Otherwise, this is an AEAD interface similar to that
+ * described in RFC 5116.
+ */
+typedef struct SSLAeadContextStr SSLAeadContext;
+
+#define SSL_MakeAead(version, cipherSuite, secret,                  \
+                     labelPrefix, labelPrefixLen, ctx)              \
+    SSL_EXPERIMENTAL_API("SSL_MakeAead",                            \
+                         (PRUint16 _version, PRUint16 _cipherSuite, \
+                          PK11SymKey * _secret,                     \
+                          const char *_labelPrefix,                 \
+                          unsigned int _labelPrefixLen,             \
+                          SSLAeadContext **_ctx),                   \
+                         (version, cipherSuite, secret,             \
+                          labelPrefix, labelPrefixLen, ctx))
+
+#define SSL_AeadEncrypt(ctx, counter, aad, aadLen, in, inLen,            \
+                        output, outputLen, maxOutputLen)                 \
+    SSL_EXPERIMENTAL_API("SSL_AeadEncrypt",                              \
+                         (const SSLAeadContext *_ctx, PRUint64 _counter, \
+                          const PRUint8 *_aad, unsigned int _aadLen,     \
+                          const PRUint8 *_in, unsigned int _inLen,       \
+                          PRUint8 *_out, unsigned int *_outLen,          \
+                          unsigned int _maxOut),                         \
+                         (ctx, counter, aad, aadLen, in, inLen,          \
+                          output, outputLen, maxOutputLen))
+
+#define SSL_AeadDecrypt(ctx, counter, aad, aadLen, in, inLen,            \
+                        output, outputLen, maxOutputLen)                 \
+    SSL_EXPERIMENTAL_API("SSL_AeadDecrypt",                              \
+                         (const SSLAeadContext *_ctx, PRUint64 _counter, \
+                          const PRUint8 *_aad, unsigned int _aadLen,     \
+                          const PRUint8 *_in, unsigned int _inLen,       \
+                          PRUint8 *_output, unsigned int *_outLen,       \
+                          unsigned int _maxOut),                         \
+                         (ctx, counter, aad, aadLen, in, inLen,          \
+                          output, outputLen, maxOutputLen))
+
+#define SSL_DestroyAead(ctx)                      \
+    SSL_EXPERIMENTAL_API("SSL_DestroyAead",       \
+                         (SSLAeadContext * _ctx), \
+                         (ctx))
+
+/* SSL_HkdfExtract and SSL_HkdfExpandLabel implement the functions from TLS,
+ * using the version and ciphersuite to set parameters. This allows callers to
+ * use these TLS functions as a KDF. This is only supported for TLS 1.3. */
+#define SSL_HkdfExtract(version, cipherSuite, salt, ikm, keyp)      \
+    SSL_EXPERIMENTAL_API("SSL_HkdfExtract",                         \
+                         (PRUint16 _version, PRUint16 _cipherSuite, \
+                          PK11SymKey * _salt, PK11SymKey * _ikm,    \
+                          PK11SymKey * *_keyp),                     \
+                         (version, cipherSuite, salt, ikm, keyp))
+
+#define SSL_HkdfDeriveSecret(version, cipherSuite, prk,               \
+                             label, labelLen, keyp)                   \
+    SSL_EXPERIMENTAL_API("SSL_HkdfDeriveSecret",                      \
+                         (PRUint16 _version, PRUint16 _cipherSuite,   \
+                          PK11SymKey * _prk,                          \
+                          const char *_label, unsigned int _labelLen, \
+                          PK11SymKey **_keyp),                        \
+                         (version, cipherSuite, prk,                  \
+                          label, labelLen, keyp))
+
 /* Deprecated experimental APIs */
 #define SSL_UseAltServerHelloType(fd, enable) SSL_DEPRECATED_EXPERIMENTAL_API
 
 SEC_END_PROTOS
 
 #endif /* __sslexp_h_ */
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -1204,19 +1204,19 @@ extern void ssl_FinishHandshake(sslSocke
 
 extern SECStatus ssl_CipherPolicySet(PRInt32 which, PRInt32 policy);
 
 extern SECStatus ssl_CipherPrefSetDefault(PRInt32 which, PRBool enabled);
 
 extern SECStatus ssl3_ConstrainRangeByPolicy(void);
 
 extern SECStatus ssl3_InitState(sslSocket *ss);
-extern SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen,
-                             int maxOutputLen, const unsigned char *input,
-                             int inputLen);
+extern SECStatus Null_Cipher(void *ctx, unsigned char *output, unsigned int *outputLen,
+                             unsigned int maxOutputLen, const unsigned char *input,
+                             unsigned int inputLen);
 extern void ssl3_RestartHandshakeHashes(sslSocket *ss);
 extern SECStatus ssl3_UpdateHandshakeHashes(sslSocket *ss,
                                             const unsigned char *b,
                                             unsigned int l);
 SECStatus
 ssl_HashHandshakeMessageInt(sslSocket *ss, SSLHandshakeType type,
                             PRUint32 dtlsSeq,
                             const PRUint8 *b, PRUint32 length);
@@ -1658,16 +1658,18 @@ PK11SymKey *ssl3_GetWrappingKey(sslSocke
                                 PK11SlotInfo *masterSecretSlot,
                                 CK_MECHANISM_TYPE masterWrapMech,
                                 void *pwArg);
 SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid,
                                PK11SymKey *secret);
 const ssl3CipherSuiteDef *ssl_LookupCipherSuiteDef(ssl3CipherSuite suite);
 const ssl3CipherSuiteCfg *ssl_LookupCipherSuiteCfg(ssl3CipherSuite suite,
                                                    const ssl3CipherSuiteCfg *suites);
+PRBool ssl3_CipherSuiteAllowedForVersionRange(ssl3CipherSuite cipherSuite,
+                                              const SSLVersionRange *vrange);
 
 SECStatus ssl3_SelectServerCert(sslSocket *ss);
 SECStatus ssl_PickSignatureScheme(sslSocket *ss,
                                   CERTCertificate *cert,
                                   SECKEYPublicKey *pubKey,
                                   SECKEYPrivateKey *privKey,
                                   const SSLSignatureScheme *peerSchemes,
                                   unsigned int peerSchemeCount,
@@ -1753,16 +1755,35 @@ SECStatus SSLExp_RecordLayerWriteCallbac
 SECStatus SSLExp_RecordLayerData(PRFileDesc *fd, PRUint16 epoch,
                                  SSLContentType contentType,
                                  const PRUint8 *data, unsigned int len);
 SECStatus SSLExp_GetCurrentEpoch(PRFileDesc *fd, PRUint16 *readEpoch,
                                  PRUint16 *writeEpoch);
 
 #define SSLResumptionTokenVersion 2
 
+SECStatus SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret,
+                          const char *labelPrefix, unsigned int labelPrefixLen,
+                          SSLAeadContext **ctx);
+SECStatus SSLExp_DestroyAead(SSLAeadContext *ctx);
+SECStatus SSLExp_AeadEncrypt(const SSLAeadContext *ctx, PRUint64 counter,
+                             const PRUint8 *aad, unsigned int aadLen,
+                             const PRUint8 *plaintext, unsigned int plaintextLen,
+                             PRUint8 *out, unsigned int *outLen, unsigned int maxOut);
+SECStatus SSLExp_AeadDecrypt(const SSLAeadContext *ctx, PRUint64 counter,
+                             const PRUint8 *aad, unsigned int aadLen,
+                             const PRUint8 *plaintext, unsigned int plaintextLen,
+                             PRUint8 *out, unsigned int *outLen, unsigned int maxOut);
+
+SECStatus SSLExp_HkdfExtract(PRUint16 version, PRUint16 cipherSuite,
+                             PK11SymKey *salt, PK11SymKey *ikm, PK11SymKey **keyp);
+SECStatus SSLExp_HkdfDeriveSecret(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
+                                  const char *label, unsigned int labelLen,
+                                  PK11SymKey **key);
+
 SEC_END_PROTOS
 
 #if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
 #define SSL_GETPID getpid
 #elif defined(WIN32)
 extern int __cdecl _getpid(void);
 #define SSL_GETPID _getpid
 #else
new file mode 100644
--- /dev/null
+++ b/security/nss/lib/ssl/sslprimitive.c
@@ -0,0 +1,249 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * SSL Primitives: Public HKDF and AEAD Functions
+ *
+ * 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 "keyhi.h"
+#include "pk11pub.h"
+#include "sechash.h"
+#include "ssl.h"
+#include "sslexp.h"
+#include "sslerr.h"
+#include "sslproto.h"
+
+#include "sslimpl.h"
+#include "tls13con.h"
+#include "tls13hkdf.h"
+
+struct SSLAeadContextStr {
+    CK_MECHANISM_TYPE mech;
+    ssl3KeyMaterial keys;
+};
+
+static SECStatus
+tls13_GetHashAndCipher(PRUint16 version, PRUint16 cipherSuite,
+                       SSLHashType *hash, const ssl3BulkCipherDef **cipher)
+{
+    if (version < SSL_LIBRARY_VERSION_TLS_1_3) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    // Lookup and check the suite.
+    SSLVersionRange vrange = { version, version };
+    if (!ssl3_CipherSuiteAllowedForVersionRange(cipherSuite, &vrange)) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    const ssl3CipherSuiteDef *suiteDef = ssl_LookupCipherSuiteDef(cipherSuite);
+    const ssl3BulkCipherDef *cipherDef = ssl_GetBulkCipherDef(suiteDef);
+    if (cipherDef->type != type_aead) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+    *hash = suiteDef->prf_hash;
+    *cipher = cipherDef;
+    return SECSuccess;
+}
+
+SECStatus
+SSLExp_MakeAead(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *secret,
+                const char *labelPrefix, unsigned int labelPrefixLen,
+                SSLAeadContext **ctx)
+{
+    SSLAeadContext *out = NULL;
+    char label[255]; // Maximum length label.
+    static const char *const keySuffix = "key";
+    static const char *const ivSuffix = "iv";
+
+    PORT_Assert(strlen(keySuffix) >= strlen(ivSuffix));
+    if (secret == NULL || ctx == NULL ||
+        (labelPrefix == NULL && labelPrefixLen > 0) ||
+        labelPrefixLen + strlen(keySuffix) > sizeof(label)) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        goto loser;
+    }
+
+    SSLHashType hash;
+    const ssl3BulkCipherDef *cipher;
+    SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
+                                          &hash, &cipher);
+    if (rv != SECSuccess) {
+        goto loser; /* Code already set. */
+    }
+
+    out = PORT_ZNew(SSLAeadContext);
+    if (out == NULL) {
+        goto loser;
+    }
+    out->mech = ssl3_Alg2Mech(cipher->calg);
+
+    memcpy(label, labelPrefix, labelPrefixLen);
+    memcpy(label + labelPrefixLen, ivSuffix, strlen(ivSuffix));
+    unsigned int labelLen = labelPrefixLen + strlen(ivSuffix);
+    unsigned int ivLen = cipher->iv_size + cipher->explicit_nonce_size;
+    rv = tls13_HkdfExpandLabelRaw(secret, hash,
+                                  NULL, 0, // Handshake hash.
+                                  label, labelLen,
+                                  out->keys.iv, ivLen);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    memcpy(label + labelPrefixLen, keySuffix, strlen(keySuffix));
+    labelLen = labelPrefixLen + strlen(keySuffix);
+    rv = tls13_HkdfExpandLabel(secret, hash,
+                               NULL, 0, // Handshake hash.
+                               label, labelLen,
+                               out->mech, cipher->key_size, &out->keys.key);
+    if (rv != SECSuccess) {
+        goto loser;
+    }
+
+    *ctx = out;
+    return SECSuccess;
+
+loser:
+    SSLExp_DestroyAead(out);
+    return SECFailure;
+}
+
+SECStatus
+SSLExp_DestroyAead(SSLAeadContext *ctx)
+{
+    if (!ctx) {
+        return SECSuccess;
+    }
+
+    PK11_FreeSymKey(ctx->keys.key);
+    PORT_ZFree(ctx, sizeof(*ctx));
+    return SECSuccess;
+}
+
+/* Bug 1529440 exists to refactor this and the other AEAD uses. */
+static SECStatus
+ssl_AeadInner(const SSLAeadContext *ctx, PRBool decrypt, PRUint64 counter,
+              const PRUint8 *aad, unsigned int aadLen,
+              const PRUint8 *plaintext, unsigned int plaintextLen,
+              PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
+{
+    if (ctx == NULL || (aad == NULL && aadLen > 0) || plaintext == NULL ||
+        out == NULL || outLen == NULL) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    // Setup the nonce.
+    PRUint8 nonce[12] = { 0 };
+    sslBuffer nonceBuf = SSL_BUFFER_FIXED(nonce + sizeof(nonce) - sizeof(counter),
+                                          sizeof(counter));
+    SECStatus rv = sslBuffer_AppendNumber(&nonceBuf, counter, sizeof(counter));
+    if (rv != SECSuccess) {
+        PORT_Assert(0);
+        return SECFailure;
+    }
+    for (int i = 0; i < sizeof(nonce); ++i) {
+        nonce[i] ^= ctx->keys.iv[i];
+    }
+
+    // Build AEAD parameters.
+    CK_GCM_PARAMS gcmParams = { 0 };
+    CK_NSS_AEAD_PARAMS aeadParams = { 0 };
+    unsigned char *params;
+    unsigned int paramsLen;
+    switch (ctx->mech) {
+        case CKM_AES_GCM:
+            gcmParams.pIv = nonce;
+            gcmParams.ulIvLen = sizeof(nonce);
+            gcmParams.pAAD = (unsigned char *)aad; // const cast :(
+            gcmParams.ulAADLen = aadLen;
+            gcmParams.ulTagBits = 128; // GCM measures in bits.
+            params = (unsigned char *)&gcmParams;
+            paramsLen = sizeof(gcmParams);
+            break;
+
+        case CKM_NSS_CHACHA20_POLY1305:
+            aeadParams.pNonce = nonce;
+            aeadParams.ulNonceLen = sizeof(nonce);
+            aeadParams.pAAD = (unsigned char *)aad; // const cast :(
+            aeadParams.ulAADLen = aadLen;
+            aeadParams.ulTagLen = 16; // AEAD measures in octets.
+            params = (unsigned char *)&aeadParams;
+            paramsLen = sizeof(aeadParams);
+            break;
+
+        default:
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            return SECFailure;
+    }
+
+    return tls13_AEAD(&ctx->keys, decrypt, out, outLen, maxOut,
+                      plaintext, plaintextLen, ctx->mech, params, paramsLen);
+}
+
+SECStatus
+SSLExp_AeadEncrypt(const SSLAeadContext *ctx, PRUint64 counter,
+                   const PRUint8 *aad, unsigned int aadLen,
+                   const PRUint8 *plaintext, unsigned int plaintextLen,
+                   PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
+{
+    // false == encrypt
+    return ssl_AeadInner(ctx, PR_FALSE, counter, aad, aadLen,
+                         plaintext, plaintextLen, out, outLen, maxOut);
+}
+
+SECStatus
+SSLExp_AeadDecrypt(const SSLAeadContext *ctx, PRUint64 counter,
+                   const PRUint8 *aad, unsigned int aadLen,
+                   const PRUint8 *plaintext, unsigned int plaintextLen,
+                   PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
+{
+    // true == decrypt
+    return ssl_AeadInner(ctx, PR_TRUE, counter, aad, aadLen,
+                         plaintext, plaintextLen, out, outLen, maxOut);
+}
+
+SECStatus
+SSLExp_HkdfExtract(PRUint16 version, PRUint16 cipherSuite,
+                   PK11SymKey *salt, PK11SymKey *ikm, PK11SymKey **keyp)
+{
+    if (keyp == NULL) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    SSLHashType hash;
+    const ssl3BulkCipherDef *cipher; /* Unused here. */
+    SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
+                                          &hash, &cipher);
+    if (rv != SECSuccess) {
+        return SECFailure; /* Code already set. */
+    }
+    return tls13_HkdfExtract(salt, ikm, hash, keyp);
+}
+
+SECStatus
+SSLExp_HkdfDeriveSecret(PRUint16 version, PRUint16 cipherSuite, PK11SymKey *prk,
+                        const char *label, unsigned int labelLen,
+                        PK11SymKey **keyp)
+{
+    if (prk == NULL || keyp == NULL ||
+        label == NULL || labelLen == 0) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
+    SSLHashType hash;
+    const ssl3BulkCipherDef *cipher; /* Unused here. */
+    SECStatus rv = tls13_GetHashAndCipher(version, cipherSuite,
+                                          &hash, &cipher);
+    if (rv != SECSuccess) {
+        return SECFailure; /* Code already set. */
+    }
+    return tls13_HkdfExpandLabel(prk, hash, NULL, 0, label, labelLen,
+                                 tls13_GetHkdfMechanismForHash(hash),
+                                 tls13_GetHashSizeForHash(hash), keyp);
+}
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -4036,25 +4036,31 @@ SSL_CanBypass(CERTCertificate *cert, SEC
     {                      \
         "SSL_" #n, SSL_##n \
     }
 struct {
     const char *const name;
     void *function;
 } ssl_experimental_functions[] = {
 #ifndef SSL_DISABLE_EXPERIMENTAL_API
+    EXP(AeadDecrypt),
+    EXP(AeadEncrypt),
+    EXP(DestroyAead),
     EXP(DestroyResumptionTokenInfo),
     EXP(EnableESNI),
     EXP(EncodeESNIKeys),
     EXP(GetCurrentEpoch),
     EXP(GetExtensionSupport),
     EXP(GetResumptionTokenInfo),
     EXP(HelloRetryRequestCallback),
     EXP(InstallExtensionHooks),
+    EXP(HkdfExtract),
+    EXP(HkdfDeriveSecret),
     EXP(KeyUpdate),
+    EXP(MakeAead),
     EXP(RecordLayerData),
     EXP(RecordLayerWriteCallback),
     EXP(SecretCallback),
     EXP(SendCertificateRequest),
     EXP(SendSessionTicket),
     EXP(SetESNIKeyPair),
     EXP(SetMaxEarlyDataSize),
     EXP(SetResumptionTokenCallback),
--- a/security/nss/lib/ssl/sslspec.h
+++ b/security/nss/lib/ssl/sslspec.h
@@ -96,30 +96,30 @@ typedef struct {
     PK11SymKey *key;
     PK11SymKey *macKey;
     PK11Context *macContext;
     PRUint8 iv[MAX_IV_LENGTH];
 } ssl3KeyMaterial;
 
 typedef SECStatus (*SSLCipher)(void *context,
                                unsigned char *out,
-                               int *outlen,
-                               int maxout,
+                               unsigned int *outlen,
+                               unsigned int maxout,
                                const unsigned char *in,
-                               int inlen);
+                               unsigned int inlen);
 typedef SECStatus (*SSLAEADCipher)(
-    ssl3KeyMaterial *keys,
+    const ssl3KeyMaterial *keys,
     PRBool doDecrypt,
     unsigned char *out,
-    int *outlen,
-    int maxout,
+    unsigned int *outlen,
+    unsigned int maxout,
     const unsigned char *in,
-    int inlen,
+    unsigned int inlen,
     const unsigned char *additionalData,
-    int additionalDataLen);
+    unsigned int additionalDataLen);
 
 /* The DTLS anti-replay window in number of packets. Defined here because we
  * need it in the cipher spec. Note that this is a ring buffer but left and
  * right represent the true window, with modular arithmetic used to map them
  * onto the buffer.
  */
 #define DTLS_RECVD_RECORDS_WINDOW 1024
 #define RECORD_SEQ_MASK ((1ULL << 48) - 1)
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -23,28 +23,34 @@
 #include "tls13err.h"
 #include "tls13esni.h"
 #include "tls13exthandle.h"
 #include "tls13hashstate.h"
 
 static SECStatus tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
                                      SSLSecretDirection install,
                                      PRBool deleteSecret);
-static SECStatus tls13_AESGCM(
-    ssl3KeyMaterial *keys,
-    PRBool doDecrypt,
-    unsigned char *out, int *outlen, int maxout,
-    const unsigned char *in, int inlen,
-    const unsigned char *additionalData, int additionalDataLen);
-static SECStatus tls13_ChaCha20Poly1305(
-    ssl3KeyMaterial *keys,
-    PRBool doDecrypt,
-    unsigned char *out, int *outlen, int maxout,
-    const unsigned char *in, int inlen,
-    const unsigned char *additionalData, int additionalDataLen);
+static SECStatus tls13_AESGCM(const ssl3KeyMaterial *keys,
+                              PRBool doDecrypt,
+                              unsigned char *out,
+                              unsigned int *outlen,
+                              unsigned int maxout,
+                              const unsigned char *in,
+                              unsigned int inlen,
+                              const unsigned char *additionalData,
+                              unsigned int additionalDataLen);
+static SECStatus tls13_ChaCha20Poly1305(const ssl3KeyMaterial *keys,
+                                        PRBool doDecrypt,
+                                        unsigned char *out,
+                                        unsigned int *outlen,
+                                        unsigned int maxout,
+                                        const unsigned char *in,
+                                        unsigned int inlen,
+                                        const unsigned char *additionalData,
+                                        unsigned int additionalDataLen);
 static SECStatus tls13_SendServerHelloSequence(sslSocket *ss);
 static SECStatus tls13_SendEncryptedExtensions(sslSocket *ss);
 static void tls13_SetKeyExchangeType(sslSocket *ss, const sslNamedGroupDef *group);
 static SECStatus tls13_HandleClientKeyShare(sslSocket *ss,
                                             TLS13KeyShareEntry *peerShare);
 static SECStatus tls13_SendHelloRetryRequest(
     sslSocket *ss, const sslNamedGroupDef *selectedGroup,
     const PRUint8 *token, unsigned int tokenLen);
@@ -288,17 +294,17 @@ tls13_GetHashSizeForHash(SSLHashType has
 }
 
 unsigned int
 tls13_GetHashSize(const sslSocket *ss)
 {
     return tls13_GetHashSizeForHash(tls13_GetHash(ss));
 }
 
-static CK_MECHANISM_TYPE
+CK_MECHANISM_TYPE
 tls13_GetHkdfMechanismForHash(SSLHashType hash)
 {
     switch (hash) {
         case ssl_hash_sha256:
             return CKM_NSS_HKDF_SHA256;
         case ssl_hash_sha384:
             return CKM_NSS_HKDF_SHA384;
         default:
@@ -3706,17 +3712,17 @@ tls13_DestroyEarlyData(PRCList *list)
  * The resulting quantity (of length iv_length) is used as the per-
  * record nonce.
  *
  * Existing suites have the same nonce size: N_MIN = N_MAX = 12 bytes
  *
  * See RFC 5288 and https://tools.ietf.org/html/draft-ietf-tls-chacha20-poly1305-04#section-2
  */
 static void
-tls13_WriteNonce(ssl3KeyMaterial *keys,
+tls13_WriteNonce(const ssl3KeyMaterial *keys,
                  const unsigned char *seqNumBuf, unsigned int seqNumLen,
                  unsigned char *nonce, unsigned int nonceLen)
 {
     size_t i;
 
     PORT_Assert(nonceLen == 12);
     memcpy(nonce, keys->iv, 12);
 
@@ -3729,51 +3735,45 @@ tls13_WriteNonce(ssl3KeyMaterial *keys,
 }
 
 /* Implement the SSLAEADCipher interface defined in sslimpl.h.
  *
  * That interface takes the additional data (see below) and reinterprets that as
  * a sequence number. In TLS 1.3 there is no additional data so this value is
  * just the encoded sequence number.
  */
-static SECStatus
-tls13_AEAD(ssl3KeyMaterial *keys, PRBool doDecrypt,
-           unsigned char *out, int *outlen, int maxout,
-           const unsigned char *in, int inlen,
+SECStatus
+tls13_AEAD(const ssl3KeyMaterial *keys, PRBool doDecrypt,
+           unsigned char *out, unsigned int *outlen, unsigned int maxout,
+           const unsigned char *in, unsigned int inlen,
            CK_MECHANISM_TYPE mechanism,
            unsigned char *aeadParams, unsigned int aeadParamLength)
 {
-    SECStatus rv;
-    unsigned int uOutLen = 0;
     SECItem param = {
         siBuffer, aeadParams, aeadParamLength
     };
 
     if (doDecrypt) {
-        rv = PK11_Decrypt(keys->key, mechanism, &param,
-                          out, &uOutLen, maxout, in, inlen);
-    } else {
-        rv = PK11_Encrypt(keys->key, mechanism, &param,
-                          out, &uOutLen, maxout, in, inlen);
-    }
-    *outlen = (int)uOutLen;
-
-    return rv;
+        return PK11_Decrypt(keys->key, mechanism, &param,
+                            out, outlen, maxout, in, inlen);
+    }
+    return PK11_Encrypt(keys->key, mechanism, &param,
+                        out, outlen, maxout, in, inlen);
 }
 
 static SECStatus
-tls13_AESGCM(ssl3KeyMaterial *keys,
+tls13_AESGCM(const ssl3KeyMaterial *keys,
              PRBool doDecrypt,
              unsigned char *out,
-             int *outlen,
-             int maxout,
+             unsigned int *outlen,
+             unsigned int maxout,
              const unsigned char *in,
-             int inlen,
+             unsigned int inlen,
              const unsigned char *additionalData,
-             int additionalDataLen)
+             unsigned int additionalDataLen)
 {
     CK_GCM_PARAMS gcmParams;
     unsigned char nonce[12];
 
     PORT_Assert(additionalDataLen >= 8);
     memset(&gcmParams, 0, sizeof(gcmParams));
     gcmParams.pIv = nonce;
     gcmParams.ulIvLen = sizeof(nonce);
@@ -3784,21 +3784,21 @@ tls13_AESGCM(ssl3KeyMaterial *keys,
     tls13_WriteNonce(keys, additionalData, 8,
                      nonce, sizeof(nonce));
     return tls13_AEAD(keys, doDecrypt, out, outlen, maxout, in, inlen,
                       CKM_AES_GCM,
                       (unsigned char *)&gcmParams, sizeof(gcmParams));
 }
 
 static SECStatus
-tls13_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt,
-                       unsigned char *out, int *outlen, int maxout,
-                       const unsigned char *in, int inlen,
+tls13_ChaCha20Poly1305(const ssl3KeyMaterial *keys, PRBool doDecrypt,
+                       unsigned char *out, unsigned int *outlen, unsigned int maxout,
+                       const unsigned char *in, unsigned int inlen,
                        const unsigned char *additionalData,
-                       int additionalDataLen)
+                       unsigned int additionalDataLen)
 {
     CK_NSS_AEAD_PARAMS aeadParams;
     unsigned char nonce[12];
 
     PORT_Assert(additionalDataLen > 8);
     memset(&aeadParams, 0, sizeof(aeadParams));
     aeadParams.pNonce = nonce;
     aeadParams.ulNonceLen = sizeof(nonce);
@@ -5140,17 +5140,17 @@ tls13_ProtectRecord(sslSocket *ss,
         rv = sslBuffer_Skip(wrBuf, contentLen, NULL);
         PORT_Assert(rv == SECSuccess);
     } else {
         PRUint8 hdr[13];
         sslBuffer buf = SSL_BUFFER_FIXED(hdr, sizeof(hdr));
         PRBool needsLength;
         PRUint8 aad[21];
         unsigned int aadLen;
-        int len;
+        unsigned int len;
 
         PORT_Assert(cipher_def->type == type_aead);
 
         /* Add the content type at the end. */
         *(SSL_BUFFER_NEXT(wrBuf) + contentLen) = type;
 
         /* Create the header (ugly that we have to do it twice). */
         rv = ssl_InsertRecordHeader(ss, cwSpec, ssl_ct_application_data,
@@ -5261,22 +5261,22 @@ tls13_UnprotectRecord(sslSocket *ss,
     PORT_Assert(cipher_def->type == type_aead);
     rv = tls13_FormatAdditionalData(ss, cText->hdr, cText->hdrLen,
                                     spec->epoch, cText->seqNum,
                                     aad, &aadLen, sizeof(aad));
     if (rv != SECSuccess) {
         return SECFailure;
     }
     rv = spec->aead(&spec->keyMaterial,
-                    PR_TRUE,                /* do decrypt */
-                    plaintext->buf,         /* out */
-                    (int *)&plaintext->len, /* outlen */
-                    plaintext->space,       /* maxout */
-                    cText->buf->buf,        /* in */
-                    cText->buf->len,        /* inlen */
+                    PR_TRUE,          /* do decrypt */
+                    plaintext->buf,   /* out */
+                    &plaintext->len,  /* outlen */
+                    plaintext->space, /* maxout */
+                    cText->buf->buf,  /* in */
+                    cText->buf->len,  /* inlen */
                     aad, aadLen);
     if (rv != SECSuccess) {
         SSL_TRC(3,
                 ("%d: TLS13[%d]: record has bogus MAC",
                  SSL_GETPID(), ss->fd));
         PORT_SetError(SSL_ERROR_BAD_MAC_READ);
         return SECFailure;
     }
--- a/security/nss/lib/ssl/tls13con.h
+++ b/security/nss/lib/ssl/tls13con.h
@@ -47,16 +47,17 @@ PRBool tls13_InHsState(sslSocket *ss, ..
 #define TLS13_IN_HS_STATE(ss, ...) \
     tls13_InHsState(ss, __VA_ARGS__, wait_invalid)
 
 SSLHashType tls13_GetHashForCipherSuite(ssl3CipherSuite suite);
 SSLHashType tls13_GetHash(const sslSocket *ss);
 unsigned int tls13_GetHashSizeForHash(SSLHashType hash);
 unsigned int tls13_GetHashSize(const sslSocket *ss);
 CK_MECHANISM_TYPE tls13_GetHkdfMechanism(sslSocket *ss);
+CK_MECHANISM_TYPE tls13_GetHkdfMechanismForHash(SSLHashType hash);
 SECStatus tls13_ComputeHash(sslSocket *ss, SSL3Hashes *hashes,
                             const PRUint8 *buf, unsigned int len);
 SECStatus tls13_ComputeHandshakeHashes(sslSocket *ss,
                                        SSL3Hashes *hashes);
 SECStatus tls13_DeriveSecretNullHash(sslSocket *ss, PK11SymKey *key,
                                      const char *label,
                                      unsigned int labelLen,
                                      PK11SymKey **dest);
@@ -125,16 +126,21 @@ SECStatus SSLExp_SetupAntiReplay(PRTime 
 SECStatus SSLExp_HelloRetryRequestCallback(PRFileDesc *fd,
                                            SSLHelloRetryRequestCallback cb,
                                            void *arg);
 SECStatus tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request,
                               PRBool buffer);
 SECStatus SSLExp_KeyUpdate(PRFileDesc *fd, PRBool requestUpdate);
 PRBool tls13_MaybeTls13(sslSocket *ss);
 SSLAEADCipher tls13_GetAead(const ssl3BulkCipherDef *cipherDef);
+SECStatus tls13_AEAD(const ssl3KeyMaterial *keys, PRBool doDecrypt,
+                     unsigned char *out, unsigned int *outlen, unsigned int maxout,
+                     const unsigned char *in, unsigned int inlen,
+                     CK_MECHANISM_TYPE mechanism,
+                     unsigned char *aeadParams, unsigned int aeadParamLength);
 void tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec);
 SECStatus SSLExp_SendCertificateRequest(PRFileDesc *fd);
 
 /* Use this instead of FATAL_ERROR when no alert shall be sent. */
 #define LOG_ERROR(ss, prError)                                                     \
     do {                                                                           \
         SSL_TRC(3, ("%d: TLS13[%d]: fatal error %d in %s (%s:%d)",                 \
                     SSL_GETPID(), ss->fd, prError, __func__, __FILE__, __LINE__)); \
--- a/security/nss/lib/ssl/tls13esni.c
+++ b/security/nss/lib/ssl/tls13esni.c
@@ -716,18 +716,18 @@ tls13_ServerGetEsniAEAD(const sslSocket 
     }
 
     *suiteDefp = suiteDef;
     *aeadp = aead;
     return SECSuccess;
 }
 
 SECStatus
-tls13_ServerDecryptEsniXtn(const sslSocket *ss, PRUint8 *in, unsigned int inLen,
-                           PRUint8 *out, int *outLen, int maxLen)
+tls13_ServerDecryptEsniXtn(const sslSocket *ss, const PRUint8 *in, unsigned int inLen,
+                           PRUint8 *out, unsigned int *outLen, unsigned int maxLen)
 {
     sslReader rdr = SSL_READER(in, inLen);
     PRUint64 suite;
     const ssl3CipherSuiteDef *suiteDef;
     SSLAEADCipher aead = NULL;
     TLSExtension *keyShareExtension;
     TLS13KeyShareEntry *entry = NULL;
     ssl3KeyMaterial keyMat = { NULL };
--- a/security/nss/lib/ssl/tls13esni.h
+++ b/security/nss/lib/ssl/tls13esni.h
@@ -40,12 +40,12 @@ SECStatus tls13_ComputeESNIKeys(const ss
                                 const PRUint8 *esniKeysHash,
                                 const PRUint8 *keyShareBuf,
                                 unsigned int keyShareBufLen,
                                 const PRUint8 *clientRandom,
                                 ssl3KeyMaterial *keyMat);
 SECStatus tls13_FormatEsniAADInput(sslBuffer *aadInput,
                                    PRUint8 *keyShare, unsigned int keyShareLen);
 
-SECStatus tls13_ServerDecryptEsniXtn(const sslSocket *ss, PRUint8 *in, unsigned int inLen,
-                                     PRUint8 *out, int *outLen, int maxLen);
+SECStatus tls13_ServerDecryptEsniXtn(const sslSocket *ss, const PRUint8 *in, unsigned int inLen,
+                                     PRUint8 *out, unsigned int *outLen, unsigned int maxLen);
 
 #endif
--- a/security/nss/lib/ssl/tls13exthandle.c
+++ b/security/nss/lib/ssl/tls13exthandle.c
@@ -1135,17 +1135,17 @@ tls13_ClientSendEsniXtn(const sslSocket 
     SECStatus rv;
     PRUint8 sniBuf[1024];
     PRUint8 hash[64];
     sslBuffer sni = SSL_BUFFER(sniBuf);
     const ssl3CipherSuiteDef *suiteDef;
     ssl3KeyMaterial keyMat;
     SSLAEADCipher aead;
     PRUint8 outBuf[1024];
-    int outLen;
+    unsigned int outLen;
     unsigned int sniStart;
     unsigned int sniLen;
     sslBuffer aadInput = SSL_BUFFER_EMPTY;
     unsigned int keyShareBufStart;
     unsigned int keyShareBufLen;
 
     PORT_Memset(&keyMat, 0, sizeof(keyMat));
 
@@ -1289,17 +1289,17 @@ tls13_ServerSendEsniXtn(const sslSocket 
 }
 
 SECStatus
 tls13_ServerHandleEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
                           SECItem *data)
 {
     sslReadBuffer buf;
     PRUint8 *plainText = NULL;
-    int ptLen;
+    unsigned int ptLen;
     SECStatus rv;
 
     /* If we are doing < TLS 1.3, then ignore this. */
     if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
         return SECSuccess;
     }
 
     if (!ss->esniKeys) {
--- a/security/nss/lib/ssl/tls13hkdf.c
+++ b/security/nss/lib/ssl/tls13hkdf.c
@@ -135,24 +135,23 @@ tls13_HkdfExpandLabel(PK11SymKey *prk, S
      */
     PRUint8 info[256];
     sslBuffer infoBuf = SSL_BUFFER(info);
     PK11SymKey *derived;
     SECStatus rv;
     const char *kLabelPrefix = "tls13 ";
     const unsigned int kLabelPrefixLen = strlen(kLabelPrefix);
 
-    if (handshakeHash) {
-        if (handshakeHashLen > 255) {
-            PORT_Assert(0);
-            PORT_SetError(SEC_ERROR_INVALID_ARGS);
-            return SECFailure;
-        }
-    } else {
-        PORT_Assert(!handshakeHashLen);
+    PORT_Assert(prk);
+    PORT_Assert(keyp);
+    if ((handshakeHashLen > 255) ||
+        (handshakeHash == NULL && handshakeHashLen > 0) ||
+        (labelLen + kLabelPrefixLen > 255)) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
     }
 
     /*
      *  [draft-ietf-tls-tls13-11] Section 7.1:
      *
      *  HKDF-Expand-Label(Secret, Label, HashValue, Length) =
      *       HKDF-Expand(Secret, HkdfLabel, Length)
      *
--- a/security/nss/tests/smime/alice.txt
+++ b/security/nss/tests/smime/alice.txt
@@ -1,6 +1,1 @@
-Date: Wed, 20 Sep 2000 00:00:01 -0700 (PDT)
-From: alice@bogus.com
-Subject: message Alice --> Bob
-To: bob@bogus.com
-
 This is a test message from Alice to Bob.
--- a/security/nss/tests/smime/smime.sh
+++ b/security/nss/tests/smime/smime.sh
@@ -46,22 +46,24 @@ smime_init()
       Exit 11 "Fatal - S/MIME of cert.sh needs to pass first"
   }
 
   SMIMEDIR=${HOSTDIR}/smime
   R_SMIMEDIR=../smime
   mkdir -p ${SMIMEDIR}
   cd ${SMIMEDIR}
   cp ${QADIR}/smime/alice.txt ${SMIMEDIR}
+
+  mkdir tb
 }
 
-smime_sign()
+cms_sign()
 {
-  HASH_CMD="-H ${HASH}"
-  SIG=sig.${HASH}
+  HASH_CMD="-H SHA${HASH}"
+  SIG=sig.SHA${HASH}
 
   echo "$SCRIPTNAME: Signing Detached Message {$HASH} ------------------"
   echo "cmsutil -S -T -N Alice ${HASH_CMD} -i alice.txt -d ${P_R_ALICEDIR} -p nss -o alice.d${SIG}"
   ${PROFTOOL} ${BINDIR}/cmsutil -S -T -N Alice ${HASH_CMD} -i alice.txt -d ${P_R_ALICEDIR} -p nss -o alice.d${SIG}
   html_msg $? 0 "Create Detached Signature Alice (${HASH})" "."
 
   echo "cmsutil -D -i alice.d${SIG} -c alice.txt -d ${P_R_BOBDIR} "
   ${PROFTOOL} ${BINDIR}/cmsutil -D -i alice.d${SIG} -c alice.txt -d ${P_R_BOBDIR} 
@@ -97,33 +99,176 @@ smime_sign()
 
   echo "cmsutil -D -i alice-ec.${SIG} -d ${P_R_BOBDIR} -o alice-ec.data.${HASH}"
   ${PROFTOOL} ${BINDIR}/cmsutil -D -i alice-ec.${SIG} -d ${P_R_BOBDIR} -o alice-ec.data.${HASH}
   html_msg $? 0 "Decode Alice's Attached Signature (ECDSA w/ ${HASH})" "."
 
   echo "diff alice.txt alice-ec.data.${HASH}"
   diff alice.txt alice-ec.data.${HASH}
   html_msg $? 0 "Compare Attached Signed Data and Original (ECDSA w/ ${HASH})" "."
+}
 
+header_mime_from_to_subject="MIME-Version: 1.0
+From: Alice@bogus.com
+To: Bob@bogus.com
+Subject: "
+
+header_opaque_signed="Content-Type: application/pkcs7-mime; name=smime.p7m;
+    smime-type=signed-data
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename=smime.p7m
+Content-Description: S/MIME Cryptographic Signature
+"
+
+header_enveloped="Content-Type: application/pkcs7-mime; name=smime.p7m;
+    smime-type=enveloped-data
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename=smime.p7m
+Content-Description: S/MIME Encrypted Message
+"
+
+header_clearsigned="Content-Type: text/plain; charset=utf-8; format=flowed
+Content-Transfer-Encoding: quoted-printable
+Content-Language: en-US
+"
+
+multipart_start="Content-Type: multipart/signed; protocol=\"application/pkcs7-signature\"; micalg=sha-HASHHASH; boundary=\"------------ms030903020902020502030404\"
+
+This is a cryptographically signed message in MIME format.
+
+--------------ms030903020902020502030404"
+
+multipart_middle="
+--------------ms030903020902020502030404
+Content-Type: application/pkcs7-signature; name=smime.p7s
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename=smime.p7s
+Content-Description: S/MIME Cryptographic Signature
+"
+
+multipart_end="--------------ms030903020902020502030404--
+"
+
+header_plaintext="Content-Type: text/plain
+"
+
+CR=$(printf '\r')
+
+mime_init()
+{
+  OUT="tb/alice.mime"
+  echo "${header_clearsigned}" >>${OUT}
+  cat alice.txt >>${OUT}
+  sed -i"" "s/\$/${CR}/" ${OUT}
+
+  OUT="tb/alice.textplain"
+  echo "${header_plaintext}" >>${OUT}
+  cat alice.txt >>${OUT}
+  sed -i"" "s/\$/${CR}/" ${OUT}
+}
+
+smime_enveloped()
+{
+  ${PROFTOOL} ${BINDIR}/cmsutil -E -r bob@bogus.com -i tb/alice.mime -d ${P_R_ALICEDIR} -p nss -o tb/alice.mime.env
+
+  OUT="tb/alice.env.eml"
+  echo -n "${header_mime_from_to_subject}" >>${OUT}
+  echo "enveloped ${SIG}" >>${OUT}
+  echo "${header_enveloped}" >>${OUT}
+  cat "tb/alice.mime.env" | ${BINDIR}/btoa | sed 's/\r$//' >>${OUT}
+  echo >>${OUT}
+  sed -i"" "s/\$/${CR}/" ${OUT}
 }
 
+smime_signed_enveloped()
+{
+  SIG=sig.SHA${HASH}
 
+  ${PROFTOOL} ${BINDIR}/cmsutil -S -T -N Alice ${HASH_CMD} -i tb/alice.mime -d ${P_R_ALICEDIR} -p nss -o tb/alice.mime.d${SIG}
+
+  OUT="tb/alice.d${SIG}.multipart"
+  echo "${multipart_start}" | sed "s/HASHHASH/${HASH}/" >>${OUT}
+  cat tb/alice.mime | sed 's/\r$//' >>${OUT}
+  echo "${multipart_middle}" >>${OUT}
+  cat tb/alice.mime.d${SIG} | ${BINDIR}/btoa | sed 's/\r$//' >>${OUT}
+  echo "${multipart_end}" >>${OUT}
+
+  ${PROFTOOL} ${BINDIR}/cmsutil -E -r bob@bogus.com -i ${OUT} -d ${P_R_ALICEDIR} -p nss -o ${OUT}.env
+
+  OUT="tb/alice.d${SIG}.multipart.eml"
+  echo -n "${header_mime_from_to_subject}" >>${OUT}
+  echo "clear-signed ${SIG}" >>${OUT}
+  cat "tb/alice.d${SIG}.multipart" >>${OUT}
+  sed -i"" "s/\$/$CR/" ${OUT}
+
+  OUT="tb/alice.d${SIG}.multipart.env.eml"
+  echo -n "${header_mime_from_to_subject}" >>${OUT}
+  echo "enveloped clear-signed $SIG" >>${OUT}
+  echo "$header_enveloped" >>${OUT}
+  cat "tb/alice.d${SIG}.multipart.env" | ${BINDIR}/btoa | sed 's/\r$//' >>${OUT}
+  echo >>${OUT}
+  sed -i"" "s/\$/$CR/" ${OUT}
+
+  ${PROFTOOL} ${BINDIR}/cmsutil -S -N Alice ${HASH_CMD} -i tb/alice.textplain -d ${P_R_ALICEDIR} -p nss -o tb/alice.textplain.${SIG}
+
+  OUT="tb/alice.${SIG}.opaque"
+  echo "$header_opaque_signed" >>${OUT}
+  cat tb/alice.textplain.${SIG} | ${BINDIR}/btoa | sed 's/\r$//' >>${OUT}
+
+  ${PROFTOOL} ${BINDIR}/cmsutil -E -r bob@bogus.com -i ${OUT} -d ${P_R_ALICEDIR} -p nss -o ${OUT}.env
+
+  OUT="tb/alice.${SIG}.opaque.eml"
+  echo -n "${header_mime_from_to_subject}" >>${OUT}
+  echo "opaque-signed $SIG" >>${OUT}
+  cat "tb/alice.${SIG}.opaque" >>${OUT}
+  echo >>${OUT}
+  sed -i"" "s/\$/$CR/" ${OUT}
+
+  OUT="tb/alice.${SIG}.opaque.env.eml"
+  echo -n "${header_mime_from_to_subject}" >>${OUT}
+  echo "enveloped opaque-signed $SIG" >>${OUT}
+  echo "$header_enveloped" >>$OUT
+  cat "tb/alice.${SIG}.opaque.env" | ${BINDIR}/btoa | sed 's/\r$//' >>${OUT}
+  echo >>${OUT}
+  sed -i"" "s/\$/$CR/" ${OUT}
+
+  # bad messages below
+
+  OUT="tb/alice.d${SIG}.multipart.bad.eml"
+  echo -n "${header_mime_from_to_subject}" >>${OUT}
+  echo "BAD clear-signed $SIG" >>${OUT}
+  cat "tb/alice.d${SIG}.multipart" | sed 's/test message from Alice/FAKE message NOT from Alice/' >>${OUT}
+  sed -i"" "s/\$/$CR/" ${OUT}
+
+  OUT="tb/alice.d${SIG}.multipart.mismatch-econtent"
+  echo "${multipart_start}" | sed "s/HASHHASH/$HASH/" >>${OUT}
+  cat tb/alice.mime | sed 's/test message from Alice/FAKE message NOT from Alice/' | sed 's/\r$//' >>${OUT}
+  echo "${multipart_middle}" >>${OUT}
+  cat tb/alice.textplain.${SIG} | ${BINDIR}/btoa | sed 's/\r$//' >>${OUT}
+  echo "${multipart_end}" >>${OUT}
+
+  OUT="tb/alice.d${SIG}.multipart.mismatch-econtent.eml"
+  echo -n "${header_mime_from_to_subject}" >>${OUT}
+  echo "BAD mismatch-econtent $SIG" >>${OUT}
+  cat "tb/alice.d${SIG}.multipart.mismatch-econtent" >>${OUT}
+  sed -i"" "s/\$/$CR/" ${OUT}
+}
 
 smime_p7()
 {
   echo "$SCRIPTNAME: p7 util Data Tests ------------------------------"
   echo "p7env -d ${P_R_ALICEDIR} -r Alice -i alice.txt -o alice_p7.env"
-  ${PROFTOOL} ${BINDIR}/p7env -d ${P_R_ALICEDIR} -r Alice -i alice.txt -o alice.env
+  ${PROFTOOL} ${BINDIR}/p7env -d ${P_R_ALICEDIR} -r Alice -i alice.txt -o alice_p7.env
   html_msg $? 0 "Creating envelope for user Alice" "."
 
-  echo "p7content -d ${P_R_ALICEDIR} -i alice.env -o alice_p7.data"
-  ${PROFTOOL} ${BINDIR}/p7content -d ${P_R_ALICEDIR} -i alice.env -o alice_p7.data -p nss
+  echo "p7content -d ${P_R_ALICEDIR} -i alice_p7.env -o alice_p7.data"
+  ${PROFTOOL} ${BINDIR}/p7content -d ${P_R_ALICEDIR} -i alice_p7.env -o alice_p7.data -p nss
   html_msg $? 0 "Verifying file delivered to user Alice" "."
 
-  sed -e '3,8p' -n alice_p7.data > alice_p7.data.sed
+  sed -e '3,3p' -n alice_p7.data > alice_p7.data.sed
 
   echo "diff alice.txt alice_p7.data.sed"
   diff alice.txt alice_p7.data.sed
   html_msg $? 0 "Compare Decoded Enveloped Data and Original" "."
 
   echo "p7sign -d ${P_R_ALICEDIR} -k Alice -i alice.txt -o alice.sig -p nss -e"
   ${PROFTOOL} ${BINDIR}/p7sign -d ${P_R_ALICEDIR} -k Alice -i alice.txt -o alice.sig -p nss -e
   html_msg $? 0 "Signing file for user Alice" "."
@@ -134,25 +279,31 @@ smime_p7()
 }
 
 ############################## smime_main ##############################
 # local shell function to test basic signed and enveloped messages 
 # from 1 --> 2"
 ########################################################################
 smime_main()
 {
+  mime_init
+  smime_enveloped
 
-  HASH=SHA1
-  smime_sign
-  HASH=SHA256
-  smime_sign
-  HASH=SHA384
-  smime_sign
-  HASH=SHA512
-  smime_sign
+  HASH="1"
+  cms_sign
+  smime_signed_enveloped
+  HASH="256"
+  cms_sign
+  smime_signed_enveloped
+  HASH="384"
+  cms_sign
+  smime_signed_enveloped
+  HASH="512"
+  cms_sign
+  smime_signed_enveloped
 
   echo "$SCRIPTNAME: Enveloped Data Tests ------------------------------"
   echo "cmsutil -E -r bob@bogus.com -i alice.txt -d ${P_R_ALICEDIR} -p nss \\"
   echo "        -o alice.env"
   ${PROFTOOL} ${BINDIR}/cmsutil -E -r bob@bogus.com -i alice.txt -d ${P_R_ALICEDIR} -p nss -o alice.env
   html_msg $? 0 "Create Enveloped Data Alice" "."
 
   echo "cmsutil -D -i alice.env -d ${P_R_BOBDIR} -p nss -o alice.data1"
@@ -227,27 +378,38 @@ smime_main()
   echo "cmsutil -D -i alice.enc -d ${P_R_BOBDIR} -e alicehello.env -p nss \\"
   echo "        -o alice.data2"
   ${PROFTOOL} ${BINDIR}/cmsutil -D -i alice.enc -d ${P_R_BOBDIR} -e alicehello.env -p nss -o alice.data2
   html_msg $? 0 "Decode Encrypted-Data" "."
 
   diff alice.txt alice.data2
   html_msg $? 0 "Compare Decoded and Original Data" "."
 }
+
+smime_data_tb()
+{
+  ${BINDIR}/pk12util -d ${P_R_ALICEDIR} -o tb/Alice.p12 -n Alice -K nss -W ""
+  ${BINDIR}/pk12util -d ${P_R_BOBDIR} -o tb/Bob.p12 -n Bob -K nss -W ""
+  ${BINDIR}/pk12util -d ${P_R_DAVEDIR} -o tb/Dave.p12 -n Dave -K nss -W ""
+  ${BINDIR}/pk12util -d ${P_R_EVEDIR} -o tb/Eve.p12 -n Eve -K nss -W ""
+  CAOUT=tb/TestCA.pem
+  cat ${P_R_CADIR}/TestCA.ca.cert | sed 's/\r$//' | ${BINDIR}/btoa -w c >> ${CAOUT}
+}
   
 ############################## smime_cleanup ###########################
 # local shell function to finish this script (no exit since it might be
 # sourced)
 ########################################################################
 smime_cleanup()
 {
   html "</TABLE><BR>"
   cd ${QADIR}
   . common/cleanup.sh
 }
 
 ################## main #################################################
 
 smime_init
 smime_main
+smime_data_tb
 smime_p7
 smime_cleanup
 
--- a/security/nss/tests/ssl/sslpolicy.txt
+++ b/security/nss/tests/ssl/sslpolicy.txt
@@ -69,16 +69,18 @@
 #	SECT233R1
 #	SECT239K1
 #	SECT283K1
 #	SECT283R1
 #	SECT409K1
 #	SECT409R1
 #	SECT571K1
 #	SECT571R1
+# Signatures:
+#	DSA
 # Hashes:
 #	MD2
 #	MD4
 #	MD5
 #	SHA1
 #	SHA224
 #	SHA256
 #	SHA384
@@ -167,8 +169,9 @@
 # turn off key exchange 
   1 noECC  SSL3   d    disallow=rsa/ssl-key-exchange Disallow Key Exchange Explicitly.
   1 noECC  SSL3   d    disallow=all_allow=hmac-sha1:sha256:dh-dss:des-ede3-cbc:tls-version-min=ssl3.0:tls-version-max=ssl3.0 Disallow Key Exchange Implicitly Narrow.
   1 noECC  SSL3   d    disallow=all_allow=md2/all:md4/all:md5/all:sha1/all:sha256/all:sha384/all:sha512/all:hmac-sha1/all:hmac-sha224/all:hmac-sha256/all:hmac-sha384/all:hmac-sha512/all:hmac-md5/all:camellia128-cbc/all:camellia192-cbc/all:camellia256-cbc/all:seed-cbc/all:des-ede3-cbc/all:des-40-cbc/all:des-cbc/all:null-cipher/all:rc2/all:rc4/all:idea/all:rsa-export/all:dhe-rsa/all:dhe-dss/all:ecdhe-ecdsa/all:ecdhe-rsa/all:ecdh-ecdsa/all:ecdh-rsa/all:tls-version-min=ssl2.0:tls-version-max=tls1.2 Disallow Key Exchnage Signatures Implicitly.
 # turn off  version
   1 noECC  SSL3   d    allow=tls-version-min=tls1.0:tls-version-max=tls1.2 Disallow Version Exlicitly
   1 noECC  SSL3   d    disallow=all_allow=hmac-sha1:sha256:rsa:des-ede3-cbc:tls-version-min=tls1.0:tls-version-max=tls1.2 Disallow Version Implicitly Narrow.
   1 noECC  SSL3   d    disallow=all_allow=md2/all:md4/all:md5/all:sha1/all:sha256/all:sha384/all:sha512/all:hmac-sha1/all:hmac-sha224/all:hmac-sha256/all:hmac-sha384/all:hmac-sha512/all:hmac-md5/all:camellia128-cbc/all:camellia192-cbc/all:camellia256-cbc/all:seed-cbc/all:des-ede3-cbc/all:des-40-cbc/all:des-cbc/all:null-cipher/all:rc2/all:rc4/all:idea/all:rsa/all:rsa-export/all:dhe-rsa/all:dhe-dss/all:ecdhe-ecdsa/all:ecdhe-rsa/all:ecdh-ecdsa/all:ecdh-rsa/all:tls-version-min=tls1.0:tls-version-max=tls1.2 Disallow Version Implicitly.
+  0 noECC  SSL3   d    disallow=dsa Disallow DSA Signatures Explicitly.