Bug 1577822 - land NSS be9c48ad76cb UPGRADE_NSS_RELEASE, r=kjacobs
authorJ.C. Jones <jc@mozilla.com>
Fri, 27 Sep 2019 20:31:22 +0000
changeset 495462 9b944cc72cdc1e4bca644b5275d71e87b2533439
parent 495461 4338e87a88886959506bf6bd3fc42df8bf69e54e
child 495463 825800449ce7309bfea3b997e0f4900ad6940392
push id96637
push userjjones@mozilla.com
push dateFri, 27 Sep 2019 22:02:45 +0000
treeherderautoland@9b944cc72cdc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskjacobs
bugs1577822, 1494063, 1515342, 1581024, 1582343, 1578238, 1576295
milestone71.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 1577822 - land NSS be9c48ad76cb UPGRADE_NSS_RELEASE, r=kjacobs 2019-09-27 Daiki Ueno <dueno@redhat.com> * cmd/lib/Makefile, cmd/lib/lib.gyp, cmd/lib/manifest.mn, cmd/lib/secutil.c, cmd/lib/secutil.h, cmd/platlibs.mk, cmd/selfserv/selfserv.c, cmd/tstclnt/tstclnt.c, tests/ssl/ssl.sh: Bug 1494063, add -x option to tstclnt/selfserv to export keying material, r=mt Reviewers: rrelyea, mt Reviewed By: mt Subscribers: HubertKario Bug #: 1494063 [be9c48ad76cb] [tip] 2019-02-25 Martin Thomson <martin.thomson@gmail.com> * gtests/pk11_gtest/manifest.mn, gtests/pk11_gtest/pk11_gtest.gyp, gtests/pk11_gtest/pk11_import_unittest.cc, gtests/pk11_gtest/pk11_key_unittest.cc, gtests/pk11_gtest/pk11_keygen.cc, gtests/pk11_gtest/pk11_keygen.h: Bug 1515342 - Tests for invalid DH public keys, r=jcj Summary: This prevents crashes on invalid, particularly NULL, keys for DH and ECDH. I factored out test code already landed for this. [7e3476b7a912] 2019-09-27 Martin Thomson <martin.thomson@gmail.com> * cpputil/nss_scoped_ptrs.h, cpputil/scoped_ptrs_util.h, gtests/common/testvectors/curve25519-vectors.h, gtests/der_gtest/der_quickder_unittest.cc, lib/util/quickder.c: Bug 1515342 - Checks for invalid bit strings, r=jcj [f4fe0da73446] 2019-09-27 Martin Thomson <mt@lowentropy.net> * cmd/lib/derprint.c: Bug 1581024 - Fix pointer comparisons, a=bustage [062bc5e9859a] 2019-09-24 Kevin Jacobs <kjacobs@mozilla.com> * cmd/lib/derprint.c: Bug 1581024 - fixup pointer wrap check to prevent it from being optimized out. r=jcj [f7fef2487a60] 2019-09-26 Deian Stefan <deian@cs.ucsd.edu> * lib/softoken/pkcs11c.c, lib/softoken/tlsprf.c: Bug 1582343 - Use constant time memcmp in more places r=kjacobs,jcj [86ef6ba1f1d7] 2019-09-26 Marcus Burghardt <mburghardt@mozilla.com> * gtests/pk11_gtest/pk11_aes_gcm_unittest.cc, lib/freebl/gcm.c, lib/freebl/intel-gcm-wrap.c: Bug 1578238 - Validate tag size in AES_GCM. r=kjacobs,jcj Validate tag size in AES_GCM. [4e3971fd992c] * gtests/pk11_gtest/manifest.mn, gtests/pk11_gtest/pk11_gtest.gyp, gtests/pk11_gtest/pk11_seed_cbc_unittest.cc, lib/freebl/seed.c: Bug 1576295 - SEED_CBC encryption check input arguments. r=kjacobs,jcj,mt Ensure the arguments passed to these functions are valid. [7580a5a212c7] Differential Revision: https://phabricator.services.mozilla.com/D47494
security/nss/TAG-INFO
security/nss/cmd/lib/Makefile
security/nss/cmd/lib/derprint.c
security/nss/cmd/lib/lib.gyp
security/nss/cmd/lib/manifest.mn
security/nss/cmd/lib/secutil.c
security/nss/cmd/lib/secutil.h
security/nss/cmd/platlibs.mk
security/nss/cmd/selfserv/selfserv.c
security/nss/cmd/tstclnt/tstclnt.c
security/nss/coreconf/coreconf.dep
security/nss/cpputil/nss_scoped_ptrs.h
security/nss/cpputil/scoped_ptrs_util.h
security/nss/gtests/common/testvectors/curve25519-vectors.h
security/nss/gtests/der_gtest/der_quickder_unittest.cc
security/nss/gtests/pk11_gtest/manifest.mn
security/nss/gtests/pk11_gtest/pk11_aes_gcm_unittest.cc
security/nss/gtests/pk11_gtest/pk11_gtest.gyp
security/nss/gtests/pk11_gtest/pk11_import_unittest.cc
security/nss/gtests/pk11_gtest/pk11_key_unittest.cc
security/nss/gtests/pk11_gtest/pk11_keygen.cc
security/nss/gtests/pk11_gtest/pk11_keygen.h
security/nss/gtests/pk11_gtest/pk11_seed_cbc_unittest.cc
security/nss/lib/freebl/gcm.c
security/nss/lib/freebl/intel-gcm-wrap.c
security/nss/lib/freebl/seed.c
security/nss/lib/softoken/pkcs11c.c
security/nss/lib/softoken/tlsprf.c
security/nss/lib/util/quickder.c
security/nss/tests/ssl/ssl.sh
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-03039d4fad57
\ No newline at end of file
+be9c48ad76cb
\ No newline at end of file
--- a/security/nss/cmd/lib/Makefile
+++ b/security/nss/cmd/lib/Makefile
@@ -22,16 +22,17 @@ include $(CORE_DEPTH)/coreconf/config.mk
 
 
 
 #######################################################################
 # (4) Include "local" platform-dependent assignments (OPTIONAL).      #
 #######################################################################
 
 include config.mk
+include ../platlibs.mk
 
 #######################################################################
 # (5) Execute "global" rules. (OPTIONAL)                              #
 #######################################################################
 
 include $(CORE_DEPTH)/coreconf/rules.mk
 
 #######################################################################
--- a/security/nss/cmd/lib/derprint.c
+++ b/security/nss/cmd/lib/derprint.c
@@ -1,14 +1,16 @@
 /* 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 "secutil.h"
 #include "secoid.h"
 
+#include <stdint.h>
+
 #ifdef __sun
 extern int fprintf(FILE *strm, const char *format, ... /* args */);
 extern int fflush(FILE *stream);
 #endif
 
 #define RIGHT_MARGIN 24
 /*#define RAW_BYTES 1 */
 
@@ -504,17 +506,17 @@ prettyPrintItem(FILE *out, const unsigne
         lenLen = prettyPrintLength(out, data, end, &slen, &indefinite, lv, raw);
         if (lenLen < 0)
             return lenLen;
         data += lenLen;
 
         /*
          * Just quit now if slen more bytes puts us off the end.
          */
-        if ((data + slen) < data || (data + slen) > end) {
+        if (data > end || slen > (end - data)) {
             PORT_SetError(SEC_ERROR_BAD_DER);
             return -1;
         }
 
         if (code & SEC_ASN1_CONSTRUCTED) {
             if (slen > 0 || indefinite) {
                 slen = prettyPrintItem(out, data,
                                        slen == 0 ? end : data + slen,
--- a/security/nss/cmd/lib/lib.gyp
+++ b/security/nss/cmd/lib/lib.gyp
@@ -22,15 +22,16 @@
       ],
       'dependencies': [
         '<(DEPTH)/exports.gyp:nss_exports'
       ]
     }
   ],
   'target_defaults': {
     'defines': [
-      'NSPR20'
+      'NSPR20',
+      'NSS_USE_STATIC_LIBS'
     ]
   },
   'variables': {
     'module': 'nss'
   }
 }
\ No newline at end of file
--- a/security/nss/cmd/lib/manifest.mn
+++ b/security/nss/cmd/lib/manifest.mn
@@ -32,8 +32,10 @@ CSRCS	= basicutil.c \
 		moreoids.c \
 		pppolicy.c \
 		ffs.c \
 		pk11table.c \
 		$(NULL)
 endif
 
 NO_MD_RELEASE	= 1
+
+USE_STATIC_LIBS = 1
--- a/security/nss/cmd/lib/secutil.c
+++ b/security/nss/cmd/lib/secutil.c
@@ -17,16 +17,17 @@
 
 #include "cryptohi.h"
 #include "secutil.h"
 #include "secpkcs7.h"
 #include "secpkcs5.h"
 #include <stdarg.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <limits.h>
 
 #ifdef XP_UNIX
 #include <unistd.h>
 #endif
 
 /* for SEC_TraverseNames */
 #include "cert.h"
 #include "certt.h"
@@ -3974,8 +3975,169 @@ done:
         PORT_Free(schemes);
         return SECFailure;
     }
 
     *enabledSigSchemeCount = count;
     *enabledSigSchemes = schemes;
     return SECSuccess;
 }
+
+/* Parse the exporter spec in the form: LABEL[:OUTPUT-LENGTH[:CONTEXT]] */
+static SECStatus
+parseExporter(const char *arg,
+              secuExporter *exporter)
+{
+    SECStatus rv = SECSuccess;
+
+    char *str = PORT_Strdup(arg);
+    if (!str) {
+        rv = SECFailure;
+        goto done;
+    }
+
+    char *labelEnd = strchr(str, ':');
+    if (labelEnd) {
+        *labelEnd = '\0';
+        labelEnd++;
+
+        /* To extract CONTEXT, first skip OUTPUT-LENGTH */
+        char *outputEnd = strchr(labelEnd, ':');
+        if (outputEnd) {
+            *outputEnd = '\0';
+            outputEnd++;
+
+            exporter->hasContext = PR_TRUE;
+            exporter->context.data = (unsigned char *)PORT_Strdup(outputEnd);
+            exporter->context.len = strlen(outputEnd);
+            if (PORT_Strncasecmp((char *)exporter->context.data, "0x", 2) == 0) {
+                rv = SECU_SECItemHexStringToBinary(&exporter->context);
+                if (rv != SECSuccess) {
+                    goto done;
+                }
+            }
+        }
+    }
+
+    if (labelEnd && *labelEnd != '\0') {
+        long int outputLength = strtol(labelEnd, NULL, 10);
+        if (!(outputLength > 0 && outputLength <= UINT_MAX)) {
+            PORT_SetError(SEC_ERROR_INVALID_ARGS);
+            rv = SECFailure;
+            goto done;
+        }
+        exporter->outputLength = outputLength;
+    } else {
+        exporter->outputLength = 20;
+    }
+
+    char *label = PORT_Strdup(str);
+    exporter->label.data = (unsigned char *)label;
+    exporter->label.len = strlen(label);
+    if (PORT_Strncasecmp((char *)exporter->label.data, "0x", 2) == 0) {
+        rv = SECU_SECItemHexStringToBinary(&exporter->label);
+        if (rv != SECSuccess) {
+            goto done;
+        }
+    }
+
+done:
+    PORT_Free(str);
+
+    return rv;
+}
+
+SECStatus
+parseExporters(const char *arg,
+               const secuExporter **enabledExporters,
+               unsigned int *enabledExporterCount)
+{
+    secuExporter *exporters;
+    unsigned int numValues = 0;
+    unsigned int count = 0;
+
+    if (countItems(arg, &numValues) != SECSuccess) {
+        return SECFailure;
+    }
+    exporters = PORT_ZNewArray(secuExporter, numValues);
+    if (!exporters) {
+        return SECFailure;
+    }
+
+    /* Get exporter definitions. */
+    char *str = PORT_Strdup(arg);
+    if (!str) {
+        goto done;
+    }
+    char *p = strtok(str, ",");
+    while (p) {
+        SECStatus rv = parseExporter(p, &exporters[count++]);
+        if (rv != SECSuccess) {
+            count = 0;
+            goto done;
+        }
+        p = strtok(NULL, ",");
+    }
+
+done:
+    PORT_Free(str);
+    if (!count) {
+        PORT_Free(exporters);
+        return SECFailure;
+    }
+
+    *enabledExporterCount = count;
+    *enabledExporters = exporters;
+    return SECSuccess;
+}
+
+static SECStatus
+exportKeyingMaterial(PRFileDesc *fd, const secuExporter *exporter)
+{
+    SECStatus rv = SECSuccess;
+    unsigned char *out = PORT_Alloc(exporter->outputLength);
+
+    if (!out) {
+        fprintf(stderr, "Unable to allocate buffer for keying material\n");
+        return SECFailure;
+    }
+    rv = SSL_ExportKeyingMaterial(fd,
+                                  (char *)exporter->label.data,
+                                  exporter->label.len,
+                                  exporter->hasContext,
+                                  exporter->context.data,
+                                  exporter->context.len,
+                                  out,
+                                  exporter->outputLength);
+    if (rv != SECSuccess) {
+        goto done;
+    }
+    fprintf(stdout, "Exported Keying Material:\n");
+    secu_PrintRawString(stdout, (SECItem *)&exporter->label, "Label", 1);
+    if (exporter->hasContext) {
+        SECU_PrintAsHex(stdout, &exporter->context, "Context", 1);
+    }
+    SECU_Indent(stdout, 1);
+    fprintf(stdout, "Length: %u\n", exporter->outputLength);
+    SECItem temp = { siBuffer, out, exporter->outputLength };
+    SECU_PrintAsHex(stdout, &temp, "Keying Material", 1);
+
+done:
+    PORT_Free(out);
+    return rv;
+}
+
+SECStatus
+exportKeyingMaterials(PRFileDesc *fd,
+                      const secuExporter *exporters,
+                      unsigned int exporterCount)
+{
+    unsigned int i;
+
+    for (i = 0; i < exporterCount; i++) {
+        SECStatus rv = exportKeyingMaterial(fd, &exporters[i]);
+        if (rv != SECSuccess) {
+            return rv;
+        }
+    }
+
+    return SECSuccess;
+}
--- a/security/nss/cmd/lib/secutil.h
+++ b/security/nss/cmd/lib/secutil.h
@@ -404,16 +404,30 @@ SECU_ParseSSLVersionRangeString(const ch
                                 const SSLVersionRange defaultVersionRange,
                                 SSLVersionRange *vrange);
 
 SECStatus parseGroupList(const char *arg, SSLNamedGroup **enabledGroups,
                          unsigned int *enabledGroupsCount);
 SECStatus parseSigSchemeList(const char *arg,
                              const SSLSignatureScheme **enabledSigSchemes,
                              unsigned int *enabledSigSchemeCount);
+typedef struct {
+    SECItem label;
+    PRBool hasContext;
+    SECItem context;
+    unsigned int outputLength;
+} secuExporter;
+
+SECStatus parseExporters(const char *arg,
+                         const secuExporter **enabledExporters,
+                         unsigned int *enabledExporterCount);
+
+SECStatus exportKeyingMaterials(PRFileDesc *fd,
+                                const secuExporter *exporters,
+                                unsigned int exporterCount);
 
 /*
  *
  *  Error messaging
  *
  */
 
 void printflags(char *trusts, unsigned int flags);
--- a/security/nss/cmd/platlibs.mk
+++ b/security/nss/cmd/platlibs.mk
@@ -139,35 +139,35 @@ NSS_LIBS_4 = \
 	$(NULL)
 endif
 endif
 
 # can't do this in manifest.mn because OS_ARCH isn't defined there.
 ifeq ($(OS_ARCH), WINNT)
 
 EXTRA_LIBS += \
+	$(SECTOOL_LIB) \
 	$(NSS_LIBS_1) \
-	$(SECTOOL_LIB) \
 	$(NSS_LIBS_2) \
 	$(SOFTOKENLIB) \
 	$(CRYPTOLIB) \
 	$(NSS_LIBS_3) \
 	$(NSS_LIBS_4) \
 	$(NULL)
 
 # $(PROGRAM) has NO explicit dependencies on $(OS_LIBS)
 #OS_LIBS += \
 	wsock32.lib \
 	winmm.lib \
 	$(NULL)
 else
 
 EXTRA_LIBS += \
+	$(SECTOOL_LIB) \
 	$(NSS_LIBS_1) \
-	$(SECTOOL_LIB) \
 	$(NSS_LIBS_2) \
 	$(SOFTOKENLIB) \
 	$(NSS_LIBS_3) \
 	$(CRYPTOLIB) \
 	$(NSS_LIBS_4) \
 	$(NULL)
 
 ifeq ($(OS_ARCH), AIX) 
--- a/security/nss/cmd/selfserv/selfserv.c
+++ b/security/nss/cmd/selfserv/selfserv.c
@@ -230,17 +230,23 @@ PrintParameterUsage()
         "   The following values are valid:\n"
         "     rsa_pkcs1_sha1, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,\n"
         "     ecdsa_sha1, ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384,\n"
         "     ecdsa_secp521r1_sha512,\n"
         "     rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512,\n"
         "     rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512,\n"
         "-Z enable 0-RTT (for TLS 1.3; also use -u)\n"
         "-E enable post-handshake authentication\n"
-        "   (for TLS 1.3; only has an effect with 3 or more -r options)\n",
+        "   (for TLS 1.3; only has an effect with 3 or more -r options)\n"
+        "-x Export and print keying material after successful handshake\n"
+        "   The argument is a comma separated list of exporters in the form:\n"
+        "     LABEL[:OUTPUT-LENGTH[:CONTEXT]]\n"
+        "   where LABEL and CONTEXT can be either a free-form string or\n"
+        "   a hex string if it is preceded by \"0x\"; OUTPUT-LENGTH\n"
+        "   is a decimal integer.\n",
         stderr);
 }
 
 static void
 Usage(const char *progName)
 {
     PrintUsageHeader(progName);
     PrintParameterUsage();
@@ -807,16 +813,18 @@ PRBool enableExtendedMasterSecret = PR_F
 PRBool zeroRTT = PR_FALSE;
 SSLAntiReplayContext *antiReplay = NULL;
 PRBool enableALPN = PR_FALSE;
 PRBool enablePostHandshakeAuth = PR_FALSE;
 SSLNamedGroup *enabledGroups = NULL;
 unsigned int enabledGroupsCount = 0;
 const SSLSignatureScheme *enabledSigSchemes = NULL;
 unsigned int enabledSigSchemeCount = 0;
+const secuExporter *enabledExporters = NULL;
+unsigned int enabledExporterCount = 0;
 
 static char *virtServerNameArray[MAX_VIRT_SERVER_NAME_ARRAY_INDEX];
 static int virtServerNameIndex = 1;
 
 static char *certNicknameArray[MAX_CERT_NICKNAME_ARRAY_INDEX];
 static int certNicknameIndex = 0;
 
 static const char stopCmd[] = { "GET /stop " };
@@ -1817,16 +1825,25 @@ handshakeCallback(PRFileDesc *fd, void *
         if (!hostInfo || PORT_Strncmp(handshakeName, (char *)hostInfo->data,
                                       hostInfo->len)) {
             failedToNegotiateName = PR_TRUE;
         }
         if (hostInfo) {
             SECITEM_FreeItem(hostInfo, PR_TRUE);
         }
     }
+    if (enabledExporters) {
+        SECStatus rv = exportKeyingMaterials(fd, enabledExporters, enabledExporterCount);
+        if (rv != SECSuccess) {
+            PRErrorCode err = PR_GetError();
+            fprintf(stderr,
+                    "couldn't export keying material: %s\n",
+                    SECU_Strerror(err));
+        }
+    }
 }
 
 void
 server_main(
     PRFileDesc *listen_sock,
     SECKEYPrivateKey **privKey,
     CERTCertificate **cert,
     const char *expectedHostNameVal)
@@ -2007,17 +2024,17 @@ server_main(
      * would like it to be. Turn this cipher on.
      */
 
     secStatus = SSL_CipherPrefSetDefault(TLS_RSA_WITH_NULL_MD5, PR_TRUE);
     if (secStatus != SECSuccess) {
         errExit("SSL_CipherPrefSetDefault:TLS_RSA_WITH_NULL_MD5");
     }
 
-    if (expectedHostNameVal) {
+    if (expectedHostNameVal || enabledExporters) {
         SSL_HandshakeCallback(model_sock, handshakeCallback,
                               (void *)expectedHostNameVal);
     }
 
     if (requestCert) {
         SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate,
                                 (void *)CERT_GetDefaultCertDB());
         if (requestCert <= 2) {
@@ -2241,21 +2258,21 @@ main(int argc, char **argv)
     progName = strrchr(tmp, '\\');
     progName = progName ? progName + 1 : tmp;
 
     PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
     SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions);
 
     /* please keep this list of options in ASCII collating sequence.
     ** numbers, then capital letters, then lower case, alphabetical.
-    ** XXX: 'B', 'E', 'q', and 'x' were used in the past but removed
+    ** XXX: 'B', and 'q' were used in the past but removed
     **      in 3.28, please leave some time before resuing those.
     **      'z' was removed in 3.39. */
     optstate = PL_CreateOptState(argc, argv,
-                                 "2:A:C:DEGH:I:J:L:M:NP:QRS:T:U:V:W:YZa:bc:d:e:f:g:hi:jk:lmn:op:rst:uvw:y");
+                                 "2:A:C:DEGH:I:J:L:M:NP:QRS:T:U:V:W:YZa:bc:d:e:f:g:hi:jk:lmn:op:rst:uvw:x:y");
     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
         ++optionsFound;
         switch (optstate->option) {
             case '2':
                 fileName = optstate->value;
                 break;
 
             case 'A':
@@ -2491,16 +2508,27 @@ main(int argc, char **argv)
                 if (rv != SECSuccess) {
                     PL_DestroyOptState(optstate);
                     fprintf(stderr, "Bad signature scheme specified.\n");
                     fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
                     exit(5);
                 }
                 break;
 
+            case 'x':
+                rv = parseExporters(optstate->value,
+                                    &enabledExporters, &enabledExporterCount);
+                if (rv != SECSuccess) {
+                    PL_DestroyOptState(optstate);
+                    fprintf(stderr, "Bad exporter specified.\n");
+                    fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
+                    exit(5);
+                }
+                break;
+
             default:
             case '?':
                 fprintf(stderr, "Unrecognized or bad option specified.\n");
                 fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
                 exit(4);
                 break;
         }
     }
--- a/security/nss/cmd/tstclnt/tstclnt.c
+++ b/security/nss/cmd/tstclnt/tstclnt.c
@@ -313,16 +313,23 @@ PrintParameterUsage()
             "-J", "", "", "", "", "", "", "");
     fprintf(stderr, "%-20s Enable alternative TLS 1.3 handshake\n", "-X alt-server-hello");
     fprintf(stderr, "%-20s Use DTLS\n", "-P {client, server}");
     fprintf(stderr, "%-20s Exit after handshake\n", "-Q");
     fprintf(stderr, "%-20s Encrypted SNI Keys\n", "-N");
     fprintf(stderr, "%-20s Enable post-handshake authentication\n"
                     "%-20s for TLS 1.3; need to specify -n\n",
             "-E", "");
+    fprintf(stderr, "%-20s Export and print keying material after successful handshake.\n"
+                    "%-20s The argument is a comma separated list of exporters in the form:\n"
+                    "%-20s   LABEL[:OUTPUT-LENGTH[:CONTEXT]]\n"
+                    "%-20s where LABEL and CONTEXT can be either a free-form string or\n"
+                    "%-20s a hex string if it is preceded by \"0x\"; OUTPUT-LENGTH\n"
+                    "%-20s is a decimal integer.\n",
+            "-x", "", "", "", "", "");
 }
 
 static void
 Usage()
 {
     PrintUsageHeader();
     PrintParameterUsage();
     exit(1);
@@ -993,16 +1000,18 @@ PRBool useDTLS = PR_FALSE;
 PRBool actAsServer = PR_FALSE;
 PRBool stopAfterHandshake = PR_FALSE;
 PRBool requestToExit = PR_FALSE;
 char *versionString = NULL;
 PRBool handshakeComplete = PR_FALSE;
 char *encryptedSNIKeys = NULL;
 PRBool enablePostHandshakeAuth = PR_FALSE;
 PRBool enableDelegatedCredentials = PR_FALSE;
+const secuExporter *enabledExporters = NULL;
+unsigned int enabledExporterCount = 0;
 
 static int
 writeBytesToServer(PRFileDesc *s, const PRUint8 *buf, int nb)
 {
     SECStatus rv;
     const PRUint8 *bufp = buf;
     PRPollDesc pollDesc;
 
@@ -1088,16 +1097,28 @@ handshakeCallback(PRFileDesc *fd, void *
             writeBytesToServer(fd, zeroRttData, zeroRttLen);
             zeroRttLen = 0;
         }
     }
     if (stopAfterHandshake) {
         requestToExit = PR_TRUE;
     }
     handshakeComplete = PR_TRUE;
+
+    if (enabledExporters) {
+        SECStatus rv;
+
+        rv = exportKeyingMaterials(fd, enabledExporters, enabledExporterCount);
+        if (rv != SECSuccess) {
+            PRErrorCode err = PR_GetError();
+            FPRINTF(stderr,
+                    "couldn't export keying material: %s\n",
+                    SECU_Strerror(err));
+        }
+    }
 }
 
 static SECStatus
 installServerCertificate(PRFileDesc *s, char *nick)
 {
     CERTCertificate *cert;
     SECKEYPrivateKey *privKey = NULL;
 
@@ -1730,17 +1751,17 @@ main(int argc, char **argv)
             maxInterval = PR_SecondsToInterval(sec);
         }
     }
 
     /* Note: 'z' was removed in 3.39
      * Please leave some time before reusing these.
      */
     optstate = PL_CreateOptState(argc, argv,
-                                 "46A:BCDEFGHI:J:KL:M:N:OP:QR:STUV:W:X:YZa:bc:d:fgh:m:n:op:qr:st:uvw:");
+                                 "46A:BCDEFGHI:J:KL:M:N:OP:QR:STUV:W:X:YZa:bc:d:fgh:m:n:op:qr:st:uvw:x:");
     while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
         switch (optstate->option) {
             case '?':
             default:
                 Usage();
                 break;
 
             case '4':
@@ -1978,16 +1999,27 @@ main(int argc, char **argv)
             case 'J':
                 rv = parseSigSchemeList(optstate->value, &enabledSigSchemes, &enabledSigSchemeCount);
                 if (rv != SECSuccess) {
                     PL_DestroyOptState(optstate);
                     fprintf(stderr, "Bad signature scheme specified.\n");
                     Usage();
                 }
                 break;
+
+            case 'x':
+                rv = parseExporters(optstate->value,
+                                    &enabledExporters,
+                                    &enabledExporterCount);
+                if (rv != SECSuccess) {
+                    PL_DestroyOptState(optstate);
+                    fprintf(stderr, "Bad exporter specified.\n");
+                    Usage();
+                }
+                break;
         }
     }
     PL_DestroyOptState(optstate);
 
     SSL_VersionRangeGetSupported(useDTLS ? ssl_variant_datagram : ssl_variant_stream, &enabledVersions);
 
     if (versionString) {
         if (SECU_ParseSSLVersionRangeString(versionString,
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/security/nss/cpputil/nss_scoped_ptrs.h
+++ b/security/nss/cpputil/nss_scoped_ptrs.h
@@ -16,80 +16,80 @@
 #include "pkcs11uri.h"
 #include "secmod.h"
 
 struct ScopedDelete {
   void operator()(CERTCertificate* cert) { CERT_DestroyCertificate(cert); }
   void operator()(CERTCertificateList* list) {
     CERT_DestroyCertificateList(list);
   }
+  void operator()(CERTDistNames* names) { CERT_FreeDistNames(names); }
   void operator()(CERTName* name) { CERT_DestroyName(name); }
   void operator()(CERTCertList* list) { CERT_DestroyCertList(list); }
   void operator()(CERTSubjectPublicKeyInfo* spki) {
     SECKEY_DestroySubjectPublicKeyInfo(spki);
   }
+  void operator()(PK11Context* context) { PK11_DestroyContext(context, true); }
+  void operator()(PK11GenericObject* obj) { PK11_DestroyGenericObject(obj); }
   void operator()(PK11SlotInfo* slot) { PK11_FreeSlot(slot); }
   void operator()(PK11SymKey* key) { PK11_FreeSymKey(key); }
+  void operator()(PK11URI* uri) { PK11URI_DestroyURI(uri); }
+  void operator()(PLArenaPool* arena) { PORT_FreeArena(arena, PR_FALSE); }
+  void operator()(PQGParams* pqg) { PK11_PQG_DestroyParams(pqg); }
   void operator()(PRFileDesc* fd) { PR_Close(fd); }
   void operator()(SECAlgorithmID* id) { SECOID_DestroyAlgorithmID(id, true); }
   void operator()(SECKEYEncryptedPrivateKeyInfo* e) {
     SECKEY_DestroyEncryptedPrivateKeyInfo(e, true);
   }
   void operator()(SECItem* item) { SECITEM_FreeItem(item, true); }
   void operator()(SECKEYPublicKey* key) { SECKEY_DestroyPublicKey(key); }
   void operator()(SECKEYPrivateKey* key) { SECKEY_DestroyPrivateKey(key); }
   void operator()(SECKEYPrivateKeyList* list) {
     SECKEY_DestroyPrivateKeyList(list);
   }
-  void operator()(PK11URI* uri) { PK11URI_DestroyURI(uri); }
-  void operator()(PLArenaPool* arena) { PORT_FreeArena(arena, PR_FALSE); }
-  void operator()(PK11Context* context) { PK11_DestroyContext(context, true); }
-  void operator()(PK11GenericObject* obj) { PK11_DestroyGenericObject(obj); }
-  void operator()(PQGParams* pqg) { PK11_PQG_DestroyParams(pqg); }
+  void operator()(SECMODModule* module) { SECMOD_DestroyModule(module); }
   void operator()(SEC_PKCS12DecoderContext* dcx) {
     SEC_PKCS12DecoderFinish(dcx);
   }
-  void operator()(CERTDistNames* names) { CERT_FreeDistNames(names); }
-  void operator()(SECMODModule* module) { SECMOD_DestroyModule(module); }
 };
 
 template <class T>
 struct ScopedMaybeDelete {
   void operator()(T* ptr) {
     if (ptr) {
       ScopedDelete del;
       del(ptr);
     }
   }
 };
 
 #define SCOPED(x) typedef std::unique_ptr<x, ScopedMaybeDelete<x> > Scoped##x
 
+SCOPED(CERTCertList);
 SCOPED(CERTCertificate);
 SCOPED(CERTCertificateList);
-SCOPED(CERTCertList);
+SCOPED(CERTDistNames);
 SCOPED(CERTName);
 SCOPED(CERTSubjectPublicKeyInfo);
+SCOPED(PK11Context);
+SCOPED(PK11GenericObject);
 SCOPED(PK11SlotInfo);
 SCOPED(PK11SymKey);
+SCOPED(PK11URI);
+SCOPED(PLArenaPool);
 SCOPED(PQGParams);
 SCOPED(PRFileDesc);
 SCOPED(SECAlgorithmID);
+SCOPED(SECItem);
 SCOPED(SECKEYEncryptedPrivateKeyInfo);
-SCOPED(SECItem);
-SCOPED(SECKEYPublicKey);
 SCOPED(SECKEYPrivateKey);
 SCOPED(SECKEYPrivateKeyList);
-SCOPED(PK11URI);
-SCOPED(PLArenaPool);
-SCOPED(PK11Context);
-SCOPED(PK11GenericObject);
+SCOPED(SECKEYPublicKey);
+SCOPED(SECMODModule);
 SCOPED(SEC_PKCS12DecoderContext);
-SCOPED(CERTDistNames);
-SCOPED(SECMODModule);
 
 #undef SCOPED
 
 struct StackSECItem : public SECItem {
   StackSECItem() : SECItem({siBuffer, nullptr, 0}) {}
   ~StackSECItem() { Reset(); }
   void Reset() { SECITEM_FreeItem(this, PR_FALSE); }
 };
--- a/security/nss/cpputil/scoped_ptrs_util.h
+++ b/security/nss/cpputil/scoped_ptrs_util.h
@@ -32,9 +32,14 @@ struct ScopedMaybeDelete {
 
 SCOPED(SECAlgorithmID);
 SCOPED(SECItem);
 SCOPED(PK11URI);
 SCOPED(PLArenaPool);
 
 #undef SCOPED
 
+struct StackSECItem : public SECItem {
+  StackSECItem() : SECItem({siBuffer, nullptr, 0}) {}
+  ~StackSECItem() { SECITEM_FreeItem(this, PR_FALSE); }
+};
+
 #endif  // scoped_ptrs_util_h__
--- a/security/nss/gtests/common/testvectors/curve25519-vectors.h
+++ b/security/nss/gtests/common/testvectors/curve25519-vectors.h
@@ -43,19 +43,19 @@ const curve25519_testvector kCurve25519V
       0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72,
       0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a,
       0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a, 0xa1, 0x23, 0x03, 0x21,
       0x00, 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d,
       0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a,
       0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a},
      {0x30, 0x38, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
       0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01,
-      0x03, 0x20, 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b,
-      0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78,
-      0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f},
+      0x03, 0x20, 0x00, 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3,
+      0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b,
+      0x78, 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b},
      {},
      false},
 
     // A public key that's too long (33 bytes).
     {{0x30, 0x67, 0x02, 0x01, 0x00, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48,
       0xce, 0x3d, 0x02, 0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda,
       0x47, 0x0f, 0x01, 0x04, 0x4c, 0x30, 0x4a, 0x02, 0x01, 0x01, 0x04, 0x20,
       0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72,
--- a/security/nss/gtests/der_gtest/der_quickder_unittest.cc
+++ b/security/nss/gtests/der_gtest/der_quickder_unittest.cc
@@ -11,27 +11,45 @@
 
 #include "nss.h"
 #include "prerror.h"
 #include "secasn1.h"
 #include "secder.h"
 #include "secerr.h"
 #include "secitem.h"
 
-const SEC_ASN1Template mySEC_NullTemplate[] = {
-    {SEC_ASN1_NULL, 0, NULL, sizeof(SECItem)}};
-
 namespace nss_test {
 
+struct TemplateAndInput {
+  const SEC_ASN1Template* t;
+  SECItem input;
+};
+
 class QuickDERTest : public ::testing::Test,
-                     public ::testing::WithParamInterface<SECItem> {};
+                     public ::testing::WithParamInterface<TemplateAndInput> {};
 
+static const uint8_t kBitstringTag = 0x03;
 static const uint8_t kNullTag = 0x05;
 static const uint8_t kLongLength = 0x80;
 
+const SEC_ASN1Template kBitstringTemplate[] = {
+    {SEC_ASN1_BIT_STRING, 0, NULL, sizeof(SECItem)}, {0}};
+
+// Empty bitstring with unused bits.
+static uint8_t kEmptyBitstringUnused[] = {kBitstringTag, 1, 1};
+
+// Bitstring with 8 unused bits.
+static uint8_t kBitstring8Unused[] = {kBitstringTag, 3, 8, 0xff, 0x00};
+
+// Bitstring with >8 unused bits.
+static uint8_t kBitstring9Unused[] = {kBitstringTag, 3, 9, 0xff, 0x80};
+
+const SEC_ASN1Template kNullTemplate[] = {
+    {SEC_ASN1_NULL, 0, NULL, sizeof(SECItem)}, {0}};
+
 // Length of zero wrongly encoded as 0x80 instead of 0x00.
 static uint8_t kOverlongLength_0_0[] = {kNullTag, kLongLength | 0};
 
 // Length of zero wrongly encoded as { 0x81, 0x00 } instead of 0x00.
 static uint8_t kOverlongLength_1_0[] = {kNullTag, kLongLength | 1, 0x00};
 
 // Length of zero wrongly encoded as:
 //
@@ -48,37 +66,44 @@ static uint8_t kOverlongLength_16_0[] = 
                                          0x33,     0x44,
                                          0x55,     0x66,
                                          0x77,     0x88,
                                          0x99,     0xAA,
                                          0xBB,     0xCC,
                                          0x00,     0x00,
                                          0x00,     0x00};
 
-static const SECItem kInvalidDER[] = {
-    {siBuffer, kOverlongLength_0_0, sizeof(kOverlongLength_0_0)},
-    {siBuffer, kOverlongLength_1_0, sizeof(kOverlongLength_1_0)},
-    {siBuffer, kOverlongLength_16_0, sizeof(kOverlongLength_16_0)},
+#define TI(t, x)                  \
+  {                               \
+    t, { siBuffer, x, sizeof(x) } \
+  }
+static const TemplateAndInput kInvalidDER[] = {
+    TI(kBitstringTemplate, kEmptyBitstringUnused),
+    TI(kBitstringTemplate, kBitstring8Unused),
+    TI(kBitstringTemplate, kBitstring9Unused),
+    TI(kNullTemplate, kOverlongLength_0_0),
+    TI(kNullTemplate, kOverlongLength_1_0),
+    TI(kNullTemplate, kOverlongLength_16_0),
 };
+#undef TI
 
 TEST_P(QuickDERTest, InvalidLengths) {
-  const SECItem& original_input(GetParam());
+  const SECItem& original_input(GetParam().input);
 
   ScopedSECItem copy_of_input(SECITEM_AllocItem(nullptr, nullptr, 0U));
   ASSERT_TRUE(copy_of_input);
   ASSERT_EQ(SECSuccess,
             SECITEM_CopyItem(nullptr, copy_of_input.get(), &original_input));
 
   PORTCheapArenaPool pool;
   PORT_InitCheapArena(&pool, DER_DEFAULT_CHUNKSIZE);
-  ScopedSECItem parsed_value(SECITEM_AllocItem(nullptr, nullptr, 0U));
-  ASSERT_TRUE(parsed_value);
+  StackSECItem parsed_value;
   ASSERT_EQ(SECFailure,
-            SEC_QuickDERDecodeItem(&pool.arena, parsed_value.get(),
-                                   mySEC_NullTemplate, copy_of_input.get()));
+            SEC_QuickDERDecodeItem(&pool.arena, &parsed_value, GetParam().t,
+                                   copy_of_input.get()));
   ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
   PORT_DestroyCheapArena(&pool);
 }
 
 INSTANTIATE_TEST_CASE_P(QuickderTestsInvalidLengths, QuickDERTest,
                         testing::ValuesIn(kInvalidDER));
 
 }  // namespace nss_test
--- a/security/nss/gtests/pk11_gtest/manifest.mn
+++ b/security/nss/gtests/pk11_gtest/manifest.mn
@@ -7,27 +7,30 @@ DEPTH      = ../..
 MODULE = nss
 
 CPPSRCS = \
       pk11_aes_gcm_unittest.cc \
       pk11_aeskeywrap_unittest.cc \
       pk11_cbc_unittest.cc \
       pk11_chacha20poly1305_unittest.cc \
       pk11_curve25519_unittest.cc \
+      pk11_der_private_key_import_unittest.cc \
       pk11_ecdsa_unittest.cc \
       pk11_encrypt_derive_unittest.cc \
       pk11_export_unittest.cc \
       pk11_find_certs_unittest.cc \
       pk11_import_unittest.cc \
+      pk11_keygen.cc \
+      pk11_key_unittest.cc \
       pk11_pbkdf2_unittest.cc \
       pk11_prf_unittest.cc \
       pk11_prng_unittest.cc \
       pk11_rsapkcs1_unittest.cc \
       pk11_rsapss_unittest.cc \
-      pk11_der_private_key_import_unittest.cc \
+      pk11_seed_cbc_unittest.cc \
       $(NULL)
 
 INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \
             -I$(CORE_DEPTH)/gtests/common \
             -I$(CORE_DEPTH)/cpputil
 
 REQUIRES = nspr nss libdbm gtest cpputil
 
--- a/security/nss/gtests/pk11_gtest/pk11_aes_gcm_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_aes_gcm_unittest.cc
@@ -32,129 +32,140 @@ class Pkcs11AesGcmTest : public ::testin
     s << "Test #" << val.test_id << " failed.";
     std::string msg = s.str();
     // Ignore GHASH-only vectors.
     if (key.empty()) {
       return;
     }
 
     // Prepare AEAD params.
-    CK_GCM_PARAMS gcmParams;
-    gcmParams.pIv = iv.data();
-    gcmParams.ulIvLen = iv.size();
-    gcmParams.pAAD = aad.data();
-    gcmParams.ulAADLen = aad.size();
-    gcmParams.ulTagBits = 128;
+    CK_GCM_PARAMS gcm_params;
+    gcm_params.pIv = iv.data();
+    gcm_params.ulIvLen = iv.size();
+    gcm_params.pAAD = aad.data();
+    gcm_params.ulAADLen = aad.size();
+    gcm_params.ulTagBits = 128;
 
-    SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&gcmParams),
-                      sizeof(gcmParams)};
+    SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&gcm_params),
+                      sizeof(gcm_params)};
 
     ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
-    SECItem keyItem = {siBuffer, key.data(),
-                       static_cast<unsigned int>(key.size())};
+    SECItem key_item = {siBuffer, key.data(),
+                        static_cast<unsigned int>(key.size())};
 
     // Import key.
-    ScopedPK11SymKey symKey(PK11_ImportSymKey(
-        slot.get(), mech, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr));
-    ASSERT_TRUE(!!symKey) << msg;
+    ScopedPK11SymKey sym_key(PK11_ImportSymKey(
+        slot.get(), mech, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, nullptr));
+    ASSERT_TRUE(!!sym_key) << msg;
 
     // Encrypt with bogus parameters.
-    unsigned int outputLen = 0;
-    std::vector<uint8_t> output(plaintext.size() + gcmParams.ulTagBits / 8);
-    gcmParams.ulTagBits = 159082344;
+    unsigned int output_len = 0;
+    std::vector<uint8_t> output(plaintext.size() + gcm_params.ulTagBits / 8);
+    // "maxout" must be at least "inlen + tagBytes", or, in this case:
+    // "output.size()" must be at least "plaintext.size() + tagBytes"
+    gcm_params.ulTagBits = 128;
     SECStatus rv =
-        PK11_Encrypt(symKey.get(), mech, &params, output.data(), &outputLen,
-                     output.size(), plaintext.data(), plaintext.size());
+        PK11_Encrypt(sym_key.get(), mech, &params, output.data(), &output_len,
+                     output.size() - 10, plaintext.data(), plaintext.size());
     EXPECT_EQ(SECFailure, rv);
-    EXPECT_EQ(0U, outputLen);
-    gcmParams.ulTagBits = 128;
+    EXPECT_EQ(0U, output_len);
+
+    // The valid values for tag size in AES_GCM are:
+    // 32, 64, 96, 104, 112, 120 and 128.
+    gcm_params.ulTagBits = 110;
+    rv = PK11_Encrypt(sym_key.get(), mech, &params, output.data(), &output_len,
+                      output.size(), plaintext.data(), plaintext.size());
+    EXPECT_EQ(SECFailure, rv);
+    EXPECT_EQ(0U, output_len);
 
     // Encrypt.
-    rv = PK11_Encrypt(symKey.get(), mech, &params, output.data(), &outputLen,
+    gcm_params.ulTagBits = 128;
+    rv = PK11_Encrypt(sym_key.get(), mech, &params, output.data(), &output_len,
                       output.size(), plaintext.data(), plaintext.size());
     if (invalid_iv) {
-      EXPECT_EQ(rv, SECFailure) << msg;
-      EXPECT_EQ(0U, outputLen);
+      EXPECT_EQ(SECFailure, rv) << msg;
+      EXPECT_EQ(0U, output_len);
       return;
     }
-    EXPECT_EQ(rv, SECSuccess) << msg;
+    EXPECT_EQ(SECSuccess, rv) << msg;
 
-    ASSERT_EQ(outputLen, output.size()) << msg;
+    ASSERT_EQ(output_len, output.size()) << msg;
 
     // Check ciphertext and tag.
     if (invalid_ct) {
       EXPECT_NE(result, output) << msg;
     } else {
       EXPECT_EQ(result, output) << msg;
     }
 
     // Decrypt.
-    unsigned int decryptedLen = 0;
+    unsigned int decrypted_len = 0;
     // The PK11 AES API is stupid, it expects an explicit IV and thus wants
     // a block more of available output memory.
     std::vector<uint8_t> decrypted(output.size());
-    rv =
-        PK11_Decrypt(symKey.get(), mech, &params, decrypted.data(),
-                     &decryptedLen, decrypted.size(), output.data(), outputLen);
-    EXPECT_EQ(rv, SECSuccess) << msg;
-    ASSERT_EQ(decryptedLen, plaintext.size()) << msg;
+    rv = PK11_Decrypt(sym_key.get(), mech, &params, decrypted.data(),
+                      &decrypted_len, decrypted.size(), output.data(),
+                      output_len);
+    EXPECT_EQ(SECSuccess, rv) << msg;
+    ASSERT_EQ(decrypted_len, plaintext.size()) << msg;
 
     // Check the plaintext.
-    EXPECT_EQ(plaintext, std::vector<uint8_t>(decrypted.begin(),
-                                              decrypted.begin() + decryptedLen))
+    EXPECT_EQ(plaintext,
+              std::vector<uint8_t>(decrypted.begin(),
+                                   decrypted.begin() + decrypted_len))
         << msg;
   }
 
   SECStatus EncryptWithIV(std::vector<uint8_t>& iv) {
     // Generate a random key.
     ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
-    ScopedPK11SymKey symKey(
+    ScopedPK11SymKey sym_key(
         PK11_KeyGen(slot.get(), mech, nullptr, 16, nullptr));
-    EXPECT_TRUE(!!symKey);
+    EXPECT_TRUE(!!sym_key);
 
     std::vector<uint8_t> data(17);
     std::vector<uint8_t> output(33);
     std::vector<uint8_t> aad(0);
 
     // Prepare AEAD params.
-    CK_GCM_PARAMS gcmParams;
-    gcmParams.pIv = iv.data();
-    gcmParams.ulIvLen = iv.size();
-    gcmParams.pAAD = aad.data();
-    gcmParams.ulAADLen = aad.size();
-    gcmParams.ulTagBits = 128;
+    CK_GCM_PARAMS gcm_params;
+    gcm_params.pIv = iv.data();
+    gcm_params.ulIvLen = iv.size();
+    gcm_params.pAAD = aad.data();
+    gcm_params.ulAADLen = aad.size();
+    gcm_params.ulTagBits = 128;
 
-    SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&gcmParams),
-                      sizeof(gcmParams)};
+    SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&gcm_params),
+                      sizeof(gcm_params)};
 
     // Try to encrypt.
-    unsigned int outputLen = 0;
-    return PK11_Encrypt(symKey.get(), mech, &params, output.data(), &outputLen,
-                        output.size(), data.data(), data.size());
+    unsigned int output_len = 0;
+    return PK11_Encrypt(sym_key.get(), mech, &params, output.data(),
+                        &output_len, output.size(), data.data(), data.size());
   }
 
   const CK_MECHANISM_TYPE mech = CKM_AES_GCM;
 };
 
 TEST_P(Pkcs11AesGcmTest, TestVectors) { RunTest(GetParam()); }
 
 INSTANTIATE_TEST_CASE_P(NISTTestVector, Pkcs11AesGcmTest,
                         ::testing::ValuesIn(kGcmKatValues));
 
 INSTANTIATE_TEST_CASE_P(WycheproofTestVector, Pkcs11AesGcmTest,
                         ::testing::ValuesIn(kGcmWycheproofVectors));
 
 TEST_F(Pkcs11AesGcmTest, ZeroLengthIV) {
   std::vector<uint8_t> iv(0);
-  EXPECT_EQ(EncryptWithIV(iv), SECFailure);
+  EXPECT_EQ(SECFailure, EncryptWithIV(iv));
 }
 
 TEST_F(Pkcs11AesGcmTest, AllZeroIV) {
   std::vector<uint8_t> iv(16, 0);
-  EXPECT_EQ(EncryptWithIV(iv), SECSuccess);
+  EXPECT_EQ(SECSuccess, EncryptWithIV(iv));
 }
 
 TEST_F(Pkcs11AesGcmTest, TwelveByteZeroIV) {
   std::vector<uint8_t> iv(12, 0);
-  EXPECT_EQ(EncryptWithIV(iv), SECSuccess);
+  EXPECT_EQ(SECSuccess, EncryptWithIV(iv));
 }
 
 }  // namespace nss_test
--- a/security/nss/gtests/pk11_gtest/pk11_gtest.gyp
+++ b/security/nss/gtests/pk11_gtest/pk11_gtest.gyp
@@ -6,33 +6,36 @@
     '../../coreconf/config.gypi',
     '../common/gtest.gypi',
   ],
   'targets': [
     {
       'target_name': 'pk11_gtest',
       'type': 'executable',
       'sources': [
-        'pk11_aeskeywrap_unittest.cc',
         'pk11_aes_cmac_unittest.cc',
         'pk11_aes_gcm_unittest.cc',
+        'pk11_aeskeywrap_unittest.cc',
         'pk11_cbc_unittest.cc',
         'pk11_chacha20poly1305_unittest.cc',
         'pk11_cipherop_unittest.cc',
         'pk11_curve25519_unittest.cc',
+        'pk11_der_private_key_import_unittest.cc',
         'pk11_ecdsa_unittest.cc',
         'pk11_encrypt_derive_unittest.cc',
         'pk11_find_certs_unittest.cc',
         'pk11_import_unittest.cc',
+        'pk11_keygen.cc',
+        'pk11_key_unittest.cc',
         'pk11_pbkdf2_unittest.cc',
         'pk11_prf_unittest.cc',
         'pk11_prng_unittest.cc',
         'pk11_rsapkcs1_unittest.cc',
         'pk11_rsapss_unittest.cc',
-        'pk11_der_private_key_import_unittest.cc',
+        'pk11_seed_cbc_unittest.cc',
         '<(DEPTH)/gtests/common/gtests.cc'
       ],
       'dependencies': [
         '<(DEPTH)/exports.gyp:nss_exports',
         '<(DEPTH)/cpputil/cpputil.gyp:cpputil',
         '<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
         '<(DEPTH)/lib/util/util.gyp:nssutil3',
       ],
--- a/security/nss/gtests/pk11_gtest/pk11_import_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_import_unittest.cc
@@ -10,57 +10,57 @@
 #include "pk11pqg.h"
 #include "prerror.h"
 #include "secoid.h"
 
 #include "cpputil.h"
 #include "nss_scoped_ptrs.h"
 #include "gtest/gtest.h"
 #include "databuffer.h"
+#include "pk11_keygen.h"
 
 namespace nss_test {
 
 // This deleter deletes a set of objects, unlike the deleter on
 // ScopedPK11GenericObject, which only deletes one.
 struct PK11GenericObjectsDeleter {
   void operator()(PK11GenericObject* objs) {
     if (objs) {
       PK11_DestroyGenericObjects(objs);
     }
   }
 };
 
 class Pk11KeyImportTestBase : public ::testing::Test {
  public:
-  Pk11KeyImportTestBase(CK_MECHANISM_TYPE mech) : mech_(mech) {}
+  Pk11KeyImportTestBase() = default;
   virtual ~Pk11KeyImportTestBase() = default;
 
   void SetUp() override {
     slot_.reset(PK11_GetInternalKeySlot());
     ASSERT_TRUE(slot_);
 
     static const uint8_t pw[] = "pw";
     SECItem pwItem = {siBuffer, toUcharPtr(pw), sizeof(pw)};
     password_.reset(SECITEM_DupItem(&pwItem));
   }
 
-  void Test() {
+  void Test(const Pkcs11KeyPairGenerator& generator) {
     // Generate a key and export it.
-    KeyType key_type;
+    KeyType key_type = nullKey;
     ScopedSECKEYEncryptedPrivateKeyInfo key_info;
     ScopedSECItem public_value;
-    GenerateAndExport(&key_type, &key_info, &public_value);
+    GenerateAndExport(generator, &key_type, &key_info, &public_value);
 
-    ASSERT_NE(nullptr, public_value);
     // Note: NSS is currently unable export wrapped DH keys, so this doesn't
-    // test
-    // CKM_DH_PKCS_KEY_PAIR_GEN beyond generate and verify
+    // test those beyond generate and verify.
     if (key_type == dhKey) {
       return;
     }
+    ASSERT_NE(nullptr, public_value);
     ASSERT_NE(nullptr, key_info);
 
     // Now import the encrypted key.
     static const uint8_t nick[] = "nick";
     SECItem nickname = {siBuffer, toUcharPtr(nick), sizeof(nick)};
     SECKEYPrivateKey* priv_tmp;
     SECStatus rv = PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(
         slot_.get(), key_info.get(), password_.get(), &nickname,
@@ -68,27 +68,16 @@ class Pk11KeyImportTestBase : public ::t
     ASSERT_EQ(SECSuccess, rv) << "PK11_ImportEncryptedPrivateKeyInfo failed "
                               << PORT_ErrorToName(PORT_GetError());
     ScopedSECKEYPrivateKey priv_key(priv_tmp);
     ASSERT_NE(nullptr, priv_key);
 
     CheckForPublicKey(priv_key, public_value.get());
   }
 
- protected:
-  class ParamHolder {
-   public:
-    virtual ~ParamHolder() = default;
-    virtual void* get() = 0;
-  };
-
-  virtual std::unique_ptr<ParamHolder> MakeParams() = 0;
-
-  CK_MECHANISM_TYPE mech_;
-
  private:
   SECItem GetPublicComponent(ScopedSECKEYPublicKey& pub_key) {
     SECItem null = {siBuffer, NULL, 0};
     switch (SECKEY_GetPublicKeyType(pub_key.get())) {
       case rsaKey:
       case rsaPssKey:
       case rsaOaepKey:
         return pub_key->u.rsa.modulus;
@@ -197,30 +186,24 @@ class Pk11KeyImportTestBase : public ::t
           << DataBuffer(expected_public->data, expected_public->len)
           << std::endl
           << "actual: "
           << DataBuffer(converted_public.data, converted_public.len)
           << std::endl;
     }
   }
 
-  void GenerateAndExport(KeyType* key_type,
+  void GenerateAndExport(const Pkcs11KeyPairGenerator& generator,
+                         KeyType* key_type,
                          ScopedSECKEYEncryptedPrivateKeyInfo* key_info,
                          ScopedSECItem* public_value) {
-    auto params = MakeParams();
-    ASSERT_NE(nullptr, params);
-
-    SECKEYPublicKey* pub_tmp;
-    ScopedSECKEYPrivateKey priv_key(
-        PK11_GenerateKeyPair(slot_.get(), mech_, params->get(), &pub_tmp,
-                             PR_FALSE, PR_TRUE, nullptr));
-    ASSERT_NE(nullptr, priv_key) << "PK11_GenerateKeyPair failed: "
-                                 << PORT_ErrorToName(PORT_GetError());
-    ScopedSECKEYPublicKey pub_key(pub_tmp);
-    ASSERT_NE(nullptr, pub_key);
+    ScopedSECKEYPrivateKey priv_key;
+    ScopedSECKEYPublicKey pub_key;
+    generator.GenerateKey(&priv_key, &pub_key);
+    ASSERT_TRUE(priv_key);
 
     // Save the public value, which we will need on import */
     SECItem* pub_val;
     KeyType t = SECKEY_GetPublicKeyType(pub_key.get());
     switch (t) {
       case rsaKey:
         pub_val = &pub_key->u.rsa.modulus;
         break;
@@ -235,24 +218,23 @@ class Pk11KeyImportTestBase : public ::t
         break;
       default:
         FAIL() << "Unknown key type";
     }
 
     CheckForPublicKey(priv_key, pub_val);
 
     *key_type = t;
+    // Note: NSS is currently unable export wrapped DH keys, so this doesn't
+    // test those beyond generate and verify.
+    if (t == dhKey) {
+      return;
+    }
     public_value->reset(SECITEM_DupItem(pub_val));
 
-    // Note: NSS is currently unable export wrapped DH keys, so this doesn't
-    // test
-    // CKM_DH_PKCS_KEY_PAIR_GEN beyond generate and verify
-    if (mech_ == CKM_DH_PKCS_KEY_PAIR_GEN) {
-      return;
-    }
     // Wrap and export the key.
     ScopedSECKEYEncryptedPrivateKeyInfo epki(PK11_ExportEncryptedPrivKeyInfo(
         slot_.get(), SEC_OID_AES_256_CBC, password_.get(), priv_key.get(), 1,
         nullptr));
     ASSERT_NE(nullptr, epki) << "PK11_ExportEncryptedPrivKeyInfo failed: "
                              << PORT_ErrorToName(PORT_GetError());
 
     key_info->swap(epki);
@@ -261,137 +243,39 @@ class Pk11KeyImportTestBase : public ::t
   ScopedPK11SlotInfo slot_;
   ScopedSECItem password_;
 };
 
 class Pk11KeyImportTest
     : public Pk11KeyImportTestBase,
       public ::testing::WithParamInterface<CK_MECHANISM_TYPE> {
  public:
-  Pk11KeyImportTest() : Pk11KeyImportTestBase(GetParam()) {}
+  Pk11KeyImportTest() = default;
   virtual ~Pk11KeyImportTest() = default;
-
- protected:
-  std::unique_ptr<ParamHolder> MakeParams() override {
-    switch (mech_) {
-      case CKM_RSA_PKCS_KEY_PAIR_GEN:
-        return std::unique_ptr<ParamHolder>(new RsaParamHolder());
-
-      case CKM_DSA_KEY_PAIR_GEN:
-      case CKM_DH_PKCS_KEY_PAIR_GEN: {
-        PQGParams* pqg_params = nullptr;
-        PQGVerify* pqg_verify = nullptr;
-        const unsigned int key_size = 1024;
-        SECStatus rv = PK11_PQG_ParamGenV2(key_size, 0, key_size / 16,
-                                           &pqg_params, &pqg_verify);
-        if (rv != SECSuccess) {
-          ADD_FAILURE() << "PK11_PQG_ParamGenV2 failed";
-          return nullptr;
-        }
-        EXPECT_NE(nullptr, pqg_verify);
-        EXPECT_NE(nullptr, pqg_params);
-        PK11_PQG_DestroyVerify(pqg_verify);
-        if (mech_ == CKM_DSA_KEY_PAIR_GEN) {
-          return std::unique_ptr<ParamHolder>(new PqgParamHolder(pqg_params));
-        }
-        return std::unique_ptr<ParamHolder>(new DhParamHolder(pqg_params));
-      }
-
-      default:
-        ADD_FAILURE() << "unknown OID " << mech_;
-    }
-    return nullptr;
-  }
-
- private:
-  class RsaParamHolder : public ParamHolder {
-   public:
-    RsaParamHolder()
-        : params_({/*.keySizeInBits = */ 1024, /*.pe = */ 0x010001}) {}
-    ~RsaParamHolder() = default;
-
-    void* get() override { return &params_; }
-
-   private:
-    PK11RSAGenParams params_;
-  };
-
-  class PqgParamHolder : public ParamHolder {
-   public:
-    PqgParamHolder(PQGParams* params) : params_(params) {}
-    ~PqgParamHolder() = default;
-
-    void* get() override { return params_.get(); }
-
-   private:
-    ScopedPQGParams params_;
-  };
-
-  class DhParamHolder : public PqgParamHolder {
-   public:
-    DhParamHolder(PQGParams* params)
-        : PqgParamHolder(params),
-          params_({/*.arena = */ nullptr,
-                   /*.prime = */ params->prime,
-                   /*.base = */ params->base}) {}
-    ~DhParamHolder() = default;
-
-    void* get() override { return &params_; }
-
-   private:
-    SECKEYDHParams params_;
-  };
 };
 
-TEST_P(Pk11KeyImportTest, GenerateExportImport) { Test(); }
+TEST_P(Pk11KeyImportTest, GenerateExportImport) {
+  Test(Pkcs11KeyPairGenerator(GetParam()));
+}
 
 INSTANTIATE_TEST_CASE_P(Pk11KeyImportTest, Pk11KeyImportTest,
                         ::testing::Values(CKM_RSA_PKCS_KEY_PAIR_GEN,
                                           CKM_DSA_KEY_PAIR_GEN,
                                           CKM_DH_PKCS_KEY_PAIR_GEN));
 
 class Pk11KeyImportTestEC : public Pk11KeyImportTestBase,
                             public ::testing::WithParamInterface<SECOidTag> {
  public:
-  Pk11KeyImportTestEC() : Pk11KeyImportTestBase(CKM_EC_KEY_PAIR_GEN) {}
+  Pk11KeyImportTestEC() = default;
   virtual ~Pk11KeyImportTestEC() = default;
-
- protected:
-  std::unique_ptr<ParamHolder> MakeParams() override {
-    return std::unique_ptr<ParamHolder>(new EcParamHolder(GetParam()));
-  }
-
- private:
-  class EcParamHolder : public ParamHolder {
-   public:
-    EcParamHolder(SECOidTag curve_oid) {
-      SECOidData* curve = SECOID_FindOIDByTag(curve_oid);
-      EXPECT_NE(nullptr, curve);
-
-      size_t plen = curve->oid.len + 2;
-      extra_.reset(new uint8_t[plen]);
-      extra_[0] = SEC_ASN1_OBJECT_ID;
-      extra_[1] = static_cast<uint8_t>(curve->oid.len);
-      memcpy(&extra_[2], curve->oid.data, curve->oid.len);
-
-      ec_params_ = {/*.type = */ siBuffer,
-                    /*.data = */ extra_.get(),
-                    /*.len = */ static_cast<unsigned int>(plen)};
-    }
-    ~EcParamHolder() = default;
-
-    void* get() override { return &ec_params_; }
-
-   private:
-    SECKEYECParams ec_params_;
-    std::unique_ptr<uint8_t[]> extra_;
-  };
 };
 
-TEST_P(Pk11KeyImportTestEC, GenerateExportImport) { Test(); }
+TEST_P(Pk11KeyImportTestEC, GenerateExportImport) {
+  Test(Pkcs11KeyPairGenerator(CKM_EC_KEY_PAIR_GEN, GetParam()));
+}
 
 INSTANTIATE_TEST_CASE_P(Pk11KeyImportTestEC, Pk11KeyImportTestEC,
                         ::testing::Values(SEC_OID_SECG_EC_SECP256R1,
                                           SEC_OID_SECG_EC_SECP384R1,
                                           SEC_OID_SECG_EC_SECP521R1,
                                           SEC_OID_CURVE25519));
 
 }  // namespace nss_test
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/pk11_gtest/pk11_key_unittest.cc
@@ -0,0 +1,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 "pk11pqg.h"
+#include "prerror.h"
+#include "secoid.h"
+
+#include "gtest/gtest.h"
+#include "nss_scoped_ptrs.h"
+#include "pk11_keygen.h"
+
+namespace nss_test {
+
+class Pkcs11NullKeyTestBase : public ::testing::Test {
+ protected:
+  // This constructs a key pair, then erases the public value from the public
+  // key.  NSS should reject this.
+  void Test(const Pkcs11KeyPairGenerator& generator,
+            CK_MECHANISM_TYPE dh_mech) {
+    ScopedSECKEYPrivateKey priv;
+    ScopedSECKEYPublicKey pub;
+    generator.GenerateKey(&priv, &pub);
+    ASSERT_TRUE(priv);
+
+    // These don't leak because they are allocated to the arena associated with
+    // the public key.
+    SECItem* pub_val = nullptr;
+    switch (SECKEY_GetPublicKeyType(pub.get())) {
+      case rsaKey:
+        pub_val = &pub->u.rsa.modulus;
+        break;
+
+      case dsaKey:
+        pub_val = &pub->u.dsa.publicValue;
+        break;
+
+      case dhKey:
+        pub_val = &pub->u.dh.publicValue;
+        break;
+
+      case ecKey:
+        pub_val = &pub->u.ec.publicValue;
+        break;
+
+      default:
+        FAIL() << "Unknown key type " << SECKEY_GetPublicKeyType(pub.get());
+    }
+    pub_val->data = nullptr;
+    pub_val->len = 0;
+
+    ScopedPK11SymKey symKey(PK11_PubDeriveWithKDF(
+        priv.get(), pub.get(), false, nullptr, nullptr, dh_mech,
+        CKM_SHA512_HMAC, CKA_DERIVE, 0, CKD_NULL, nullptr, nullptr));
+    ASSERT_FALSE(symKey);
+  }
+};
+
+class Pkcs11DhNullKeyTest : public Pkcs11NullKeyTestBase {};
+TEST_F(Pkcs11DhNullKeyTest, UseNullPublicValue) {
+  Test(Pkcs11KeyPairGenerator(CKM_DH_PKCS_KEY_PAIR_GEN), CKM_DH_PKCS_DERIVE);
+}
+
+class Pkcs11EcdhNullKeyTest : public Pkcs11NullKeyTestBase,
+                              public ::testing::WithParamInterface<SECOidTag> {
+};
+TEST_P(Pkcs11EcdhNullKeyTest, UseNullPublicValue) {
+  Test(Pkcs11KeyPairGenerator(CKM_EC_KEY_PAIR_GEN, GetParam()),
+       CKM_ECDH1_DERIVE);
+}
+INSTANTIATE_TEST_CASE_P(Pkcs11EcdhNullKeyTest, Pkcs11EcdhNullKeyTest,
+                        ::testing::Values(SEC_OID_SECG_EC_SECP256R1,
+                                          SEC_OID_SECG_EC_SECP384R1,
+                                          SEC_OID_SECG_EC_SECP521R1,
+                                          SEC_OID_CURVE25519));
+
+}  // namespace nss_test
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/pk11_gtest/pk11_keygen.cc
@@ -0,0 +1,143 @@
+/* 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 "pk11_keygen.h"
+
+#include "pk11pub.h"
+#include "pk11pqg.h"
+#include "prerror.h"
+
+#include "gtest/gtest.h"
+
+namespace nss_test {
+
+class ParamHolder {
+ public:
+  virtual void* get() = 0;
+  virtual ~ParamHolder() = default;
+
+ protected:
+  ParamHolder() = default;
+};
+
+void Pkcs11KeyPairGenerator::GenerateKey(ScopedSECKEYPrivateKey* priv_key,
+                                         ScopedSECKEYPublicKey* pub_key) const {
+  // This function returns if an assertion fails, so don't leak anything.
+  priv_key->reset(nullptr);
+  pub_key->reset(nullptr);
+
+  auto params = MakeParams();
+  ASSERT_NE(nullptr, params);
+
+  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
+  ASSERT_TRUE(slot);
+
+  SECKEYPublicKey* pub_tmp;
+  ScopedSECKEYPrivateKey priv_tmp(PK11_GenerateKeyPair(
+      slot.get(), mech_, params->get(), &pub_tmp, PR_FALSE, PR_TRUE, nullptr));
+  ASSERT_NE(nullptr, priv_tmp) << "PK11_GenerateKeyPair failed: "
+                               << PORT_ErrorToName(PORT_GetError());
+  ASSERT_NE(nullptr, pub_tmp);
+
+  priv_key->swap(priv_tmp);
+  pub_key->reset(pub_tmp);
+}
+
+class RsaParamHolder : public ParamHolder {
+ public:
+  RsaParamHolder() : params_({1024, 0x010001}) {}
+  ~RsaParamHolder() = default;
+
+  void* get() override { return &params_; }
+
+ private:
+  PK11RSAGenParams params_;
+};
+
+class PqgParamHolder : public ParamHolder {
+ public:
+  PqgParamHolder(PQGParams* params) : params_(params) {}
+  ~PqgParamHolder() = default;
+
+  void* get() override { return params_.get(); }
+
+ private:
+  ScopedPQGParams params_;
+};
+
+class DhParamHolder : public PqgParamHolder {
+ public:
+  DhParamHolder(PQGParams* params)
+      : PqgParamHolder(params),
+        params_({nullptr, params->prime, params->base}) {}
+  ~DhParamHolder() = default;
+
+  void* get() override { return &params_; }
+
+ private:
+  SECKEYDHParams params_;
+};
+
+class EcParamHolder : public ParamHolder {
+ public:
+  EcParamHolder(SECOidTag curve_oid) {
+    SECOidData* curve = SECOID_FindOIDByTag(curve_oid);
+    EXPECT_NE(nullptr, curve);
+
+    size_t plen = curve->oid.len + 2;
+    extra_.reset(new uint8_t[plen]);
+    extra_[0] = SEC_ASN1_OBJECT_ID;
+    extra_[1] = static_cast<uint8_t>(curve->oid.len);
+    memcpy(&extra_[2], curve->oid.data, curve->oid.len);
+
+    ec_params_ = {siBuffer, extra_.get(), static_cast<unsigned int>(plen)};
+  }
+  ~EcParamHolder() = default;
+
+  void* get() override { return &ec_params_; }
+
+ private:
+  SECKEYECParams ec_params_;
+  std::unique_ptr<uint8_t[]> extra_;
+};
+
+std::unique_ptr<ParamHolder> Pkcs11KeyPairGenerator::MakeParams() const {
+  switch (mech_) {
+    case CKM_RSA_PKCS_KEY_PAIR_GEN:
+      std::cerr << "Generate RSA pair" << std::endl;
+      return std::unique_ptr<ParamHolder>(new RsaParamHolder());
+
+    case CKM_DSA_KEY_PAIR_GEN:
+    case CKM_DH_PKCS_KEY_PAIR_GEN: {
+      PQGParams* pqg_params = nullptr;
+      PQGVerify* pqg_verify = nullptr;
+      const unsigned int key_size = 1024;
+      SECStatus rv = PK11_PQG_ParamGenV2(key_size, 0, key_size / 16,
+                                         &pqg_params, &pqg_verify);
+      if (rv != SECSuccess) {
+        ADD_FAILURE() << "PK11_PQG_ParamGenV2 failed";
+        return nullptr;
+      }
+      EXPECT_NE(nullptr, pqg_verify);
+      EXPECT_NE(nullptr, pqg_params);
+      PK11_PQG_DestroyVerify(pqg_verify);
+      if (mech_ == CKM_DSA_KEY_PAIR_GEN) {
+        std::cerr << "Generate DSA pair" << std::endl;
+        return std::unique_ptr<ParamHolder>(new PqgParamHolder(pqg_params));
+      }
+      std::cerr << "Generate DH pair" << std::endl;
+      return std::unique_ptr<ParamHolder>(new DhParamHolder(pqg_params));
+    }
+
+    case CKM_EC_KEY_PAIR_GEN:
+      std::cerr << "Generate EC pair on " << curve_ << std::endl;
+      return std::unique_ptr<ParamHolder>(new EcParamHolder(curve_));
+
+    default:
+      ADD_FAILURE() << "unknown OID " << mech_;
+  }
+  return nullptr;
+}
+
+}  // namespace nss_test
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/pk11_gtest/pk11_keygen.h
@@ -0,0 +1,34 @@
+/* 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 "nss.h"
+#include "secoid.h"
+
+#include "nss_scoped_ptrs.h"
+
+namespace nss_test {
+
+class ParamHolder;
+
+class Pkcs11KeyPairGenerator {
+ public:
+  Pkcs11KeyPairGenerator(CK_MECHANISM_TYPE mech, SECOidTag curve_oid)
+      : mech_(mech), curve_(curve_oid) {}
+  Pkcs11KeyPairGenerator(CK_MECHANISM_TYPE mech)
+      : Pkcs11KeyPairGenerator(mech, SEC_OID_UNKNOWN) {}
+
+  CK_MECHANISM_TYPE mechanism() const { return mech_; }
+  SECOidTag curve() const { return curve_; }
+
+  void GenerateKey(ScopedSECKEYPrivateKey* priv_key,
+                   ScopedSECKEYPublicKey* pub_key) const;
+
+ private:
+  std::unique_ptr<ParamHolder> MakeParams() const;
+
+  CK_MECHANISM_TYPE mech_;
+  SECOidTag curve_;
+};
+
+}  // namespace nss_test
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/pk11_gtest/pk11_seed_cbc_unittest.cc
@@ -0,0 +1,71 @@
+/* -*- 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 "nss.h"
+#include "pk11pub.h"
+#include "secerr.h"
+
+#include "nss_scoped_ptrs.h"
+#include "gtest/gtest.h"
+#include "util.h"
+
+namespace nss_test {
+class Pkcs11SeedCbcTest : public ::testing::Test {
+ protected:
+  enum class Action { Encrypt, Decrypt };
+
+  SECStatus EncryptDecryptSeed(Action action, unsigned int input_size,
+                               unsigned int output_size) {
+    // Generate a random key.
+    ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+    ScopedPK11SymKey sym_key(
+        PK11_KeyGen(slot.get(), kMech, nullptr, 16, nullptr));
+    EXPECT_TRUE(!!sym_key);
+
+    std::vector<uint8_t> data(input_size);
+    std::vector<uint8_t> init_vector(16);
+    std::vector<uint8_t> output(output_size);
+    SECItem params = {siBuffer, init_vector.data(),
+                      (unsigned int)init_vector.size()};
+
+    // Try to encrypt/decrypt.
+    unsigned int output_len = 0;
+    if (action == Action::Encrypt) {
+      return PK11_Encrypt(sym_key.get(), kMech, &params, output.data(),
+                          &output_len, output_size, data.data(), data.size());
+    } else {
+      return PK11_Decrypt(sym_key.get(), kMech, &params, output.data(),
+                          &output_len, output_size, data.data(), data.size());
+    }
+  }
+  const CK_MECHANISM_TYPE kMech = CKM_SEED_CBC;
+};
+
+// The intention here is to test the arguments of these functions
+// The resulted content is already tested in EncryptDeriveTests.
+// SEED_CBC needs an IV of 16 bytes.
+// The input data size must be multiple of 16.
+// If not, some padding should be added.
+// The output size must be at least the size of input data.
+TEST_F(Pkcs11SeedCbcTest, SeedCBC_ValidArgs) {
+  EXPECT_EQ(SECSuccess, EncryptDecryptSeed(Action::Encrypt, 16, 16));
+  EXPECT_EQ(SECSuccess, EncryptDecryptSeed(Action::Decrypt, 16, 16));
+  // No problem if maxLen is bigger than input data.
+  EXPECT_EQ(SECSuccess, EncryptDecryptSeed(Action::Encrypt, 16, 32));
+  EXPECT_EQ(SECSuccess, EncryptDecryptSeed(Action::Decrypt, 16, 32));
+}
+
+TEST_F(Pkcs11SeedCbcTest, SeedCBC_InvalidArgs) {
+  // maxLen lower than input data.
+  EXPECT_EQ(SECFailure, EncryptDecryptSeed(Action::Encrypt, 16, 10));
+  EXPECT_EQ(SECFailure, EncryptDecryptSeed(Action::Decrypt, 16, 10));
+  // input data not multiple of SEED_BLOCK_SIZE (16)
+  EXPECT_EQ(SECFailure, EncryptDecryptSeed(Action::Encrypt, 17, 32));
+  EXPECT_EQ(SECFailure, EncryptDecryptSeed(Action::Decrypt, 17, 32));
+}
+
+}  // namespace nss_test
\ No newline at end of file
--- a/security/nss/lib/freebl/gcm.c
+++ b/security/nss/lib/freebl/gcm.c
@@ -536,16 +536,25 @@ GCM_CreateContext(void *context, freeblC
 #else
     const PRBool sw = PR_FALSE;
 #endif
 
     if (gcmParams->ulIvLen == 0) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return NULL;
     }
+
+    if (gcmParams->ulTagBits != 128 && gcmParams->ulTagBits != 120 &&
+        gcmParams->ulTagBits != 112 && gcmParams->ulTagBits != 104 &&
+        gcmParams->ulTagBits != 96 && gcmParams->ulTagBits != 64 &&
+        gcmParams->ulTagBits != 32) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+
     gcm = PORT_ZNew(GCMContext);
     if (gcm == NULL) {
         return NULL;
     }
     ghash = PORT_ZNewAligned(gcmHashContext, 16, mem);
 
     /* first plug in the ghash context */
     gcm->ghash_context = ghash;
--- a/security/nss/lib/freebl/intel-gcm-wrap.c
+++ b/security/nss/lib/freebl/intel-gcm-wrap.c
@@ -57,16 +57,25 @@ intel_AES_GCM_CreateContext(void *contex
     __m128i ONE = _mm_set_epi32(0, 0, 0, 1);
     unsigned int j;
     SECStatus rv;
 
     if (gcmParams->ulIvLen == 0) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return NULL;
     }
+
+    if (gcmParams->ulTagBits != 128 && gcmParams->ulTagBits != 120 &&
+        gcmParams->ulTagBits != 112 && gcmParams->ulTagBits != 104 &&
+        gcmParams->ulTagBits != 96 && gcmParams->ulTagBits != 64 &&
+        gcmParams->ulTagBits != 32) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return NULL;
+    }
+
     // Limit AADLen in accordance with SP800-38D
     if (sizeof(AAD_whole_len) >= 8 && AAD_whole_len > (1ULL << 61) - 1) {
         PORT_SetError(SEC_ERROR_INPUT_LEN);
         return NULL;
     }
 
     gcm = PORT_ZNew(intel_AES_GCMContext);
     if (gcm == NULL) {
--- a/security/nss/lib/freebl/seed.c
+++ b/security/nss/lib/freebl/seed.c
@@ -431,81 +431,88 @@ SEED_cbc_encrypt(const unsigned char *in
                  unsigned char ivec[SEED_BLOCK_SIZE], int enc)
 {
     size_t n;
     unsigned char tmp[SEED_BLOCK_SIZE];
     const unsigned char *iv = ivec;
 
     if (enc) {
         while (len >= SEED_BLOCK_SIZE) {
-            for (n = 0; n < SEED_BLOCK_SIZE; ++n)
+            for (n = 0; n < SEED_BLOCK_SIZE; ++n) {
                 out[n] = in[n] ^ iv[n];
+            }
 
             SEED_encrypt(out, out, ks);
             iv = out;
             len -= SEED_BLOCK_SIZE;
             in += SEED_BLOCK_SIZE;
             out += SEED_BLOCK_SIZE;
         }
 
         if (len) {
-            for (n = 0; n < len; ++n)
+            for (n = 0; n < len; ++n) {
                 out[n] = in[n] ^ iv[n];
+            }
 
-            for (n = len; n < SEED_BLOCK_SIZE; ++n)
+            for (n = len; n < SEED_BLOCK_SIZE; ++n) {
                 out[n] = iv[n];
+            }
 
             SEED_encrypt(out, out, ks);
             iv = out;
         }
 
         memcpy(ivec, iv, SEED_BLOCK_SIZE);
     } else if (in != out) {
         while (len >= SEED_BLOCK_SIZE) {
             SEED_decrypt(in, out, ks);
 
-            for (n = 0; n < SEED_BLOCK_SIZE; ++n)
+            for (n = 0; n < SEED_BLOCK_SIZE; ++n) {
                 out[n] ^= iv[n];
+            }
 
             iv = in;
             len -= SEED_BLOCK_SIZE;
             in += SEED_BLOCK_SIZE;
             out += SEED_BLOCK_SIZE;
         }
 
         if (len) {
             SEED_decrypt(in, tmp, ks);
 
-            for (n = 0; n < len; ++n)
+            for (n = 0; n < len; ++n) {
                 out[n] = tmp[n] ^ iv[n];
+            }
 
             iv = in;
         }
 
         memcpy(ivec, iv, SEED_BLOCK_SIZE);
     } else {
         while (len >= SEED_BLOCK_SIZE) {
             memcpy(tmp, in, SEED_BLOCK_SIZE);
             SEED_decrypt(in, out, ks);
 
-            for (n = 0; n < SEED_BLOCK_SIZE; ++n)
+            for (n = 0; n < SEED_BLOCK_SIZE; ++n) {
                 out[n] ^= ivec[n];
+            }
 
             memcpy(ivec, tmp, SEED_BLOCK_SIZE);
             len -= SEED_BLOCK_SIZE;
             in += SEED_BLOCK_SIZE;
             out += SEED_BLOCK_SIZE;
         }
 
         if (len) {
             memcpy(tmp, in, SEED_BLOCK_SIZE);
             SEED_decrypt(tmp, tmp, ks);
 
-            for (n = 0; n < len; ++n)
+            for (n = 0; n < len; ++n) {
                 out[n] = tmp[n] ^ ivec[n];
+            }
 
             memcpy(ivec, tmp, SEED_BLOCK_SIZE);
         }
     }
 }
 
 SEEDContext *
 SEED_AllocateContext(void)
@@ -577,16 +584,22 @@ SEED_Encrypt(SEEDContext *cx, unsigned c
              unsigned int maxOutLen, const unsigned char *in,
              unsigned int inLen)
 {
     if (!cx) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
+    if ((inLen % SEED_BLOCK_SIZE) != 0 || maxOutLen < SEED_BLOCK_SIZE ||
+        maxOutLen < inLen) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
     if (!cx->encrypt) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
     switch (cx->mode) {
         case NSS_SEED:
             SEED_ecb_encrypt(in, out, &cx->ks, 1);
@@ -611,16 +624,22 @@ SEED_Decrypt(SEEDContext *cx, unsigned c
              unsigned int maxOutLen, const unsigned char *in,
              unsigned int inLen)
 {
     if (!cx) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
+    if ((inLen % SEED_BLOCK_SIZE) != 0 || maxOutLen < SEED_BLOCK_SIZE ||
+        maxOutLen < inLen) {
+        PORT_SetError(SEC_ERROR_INVALID_ARGS);
+        return SECFailure;
+    }
+
     if (cx->encrypt) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
 
     switch (cx->mode) {
         case NSS_SEED:
             SEED_ecb_encrypt(in, out, &cx->ks, 0);
--- a/security/nss/lib/softoken/pkcs11c.c
+++ b/security/nss/lib/softoken/pkcs11c.c
@@ -1926,17 +1926,17 @@ sftk_SignCopy(
     return SECSuccess;
 }
 
 /* Verify is just a compare for HMAC */
 static SECStatus
 sftk_HMACCmp(CK_ULONG *copyLen, unsigned char *sig, unsigned int sigLen,
              unsigned char *hash, unsigned int hashLen)
 {
-    return (PORT_Memcmp(sig, hash, *copyLen) == 0) ? SECSuccess : SECFailure;
+    return (NSS_SecureMemcmp(sig, hash, *copyLen) == 0) ? SECSuccess : SECFailure;
 }
 
 /*
  * common HMAC initalization routine
  */
 static CK_RV
 sftk_doHMACInit(SFTKSessionContext *context, HASH_HashType hash,
                 SFTKObject *key, CK_ULONG mac_size)
@@ -2120,17 +2120,17 @@ sftk_SSLMACVerify(SFTKSSLMACInfo *info, 
     unsigned char tmpBuf[SFTK_MAX_MAC_LENGTH];
     unsigned int out;
 
     info->begin(info->hashContext);
     info->update(info->hashContext, info->key, info->keySize);
     info->update(info->hashContext, ssl_pad_2, info->padSize);
     info->update(info->hashContext, hash, hashLen);
     info->end(info->hashContext, tmpBuf, &out, SFTK_MAX_MAC_LENGTH);
-    return (PORT_Memcmp(sig, tmpBuf, info->macSize) == 0) ? SECSuccess : SECFailure;
+    return (NSS_SecureMemcmp(sig, tmpBuf, info->macSize) == 0) ? SECSuccess : SECFailure;
 }
 
 /*
  * common HMAC initalization routine
  */
 static CK_RV
 sftk_doSSLMACInit(SFTKSessionContext *context, SECOidTag oid,
                   SFTKObject *key, CK_ULONG mac_size)
@@ -3642,17 +3642,17 @@ NSC_VerifyFinal(CK_SESSION_HANDLE hSessi
         (*context->end)(context->hashInfo, tmpbuf, &digestLen, sizeof(tmpbuf));
         if (SECSuccess != (context->verify)(context->cipherInfo, pSignature,
                                             ulSignatureLen, tmpbuf, digestLen))
             crv = sftk_MapCryptError(PORT_GetError());
     } else if (ulSignatureLen != context->macSize) {
         /* must be block cipher MACing */
         crv = CKR_SIGNATURE_LEN_RANGE;
     } else if (CKR_OK == (crv = sftk_MACFinal(context))) {
-        if (PORT_Memcmp(pSignature, context->macBuf, ulSignatureLen))
+        if (NSS_SecureMemcmp(pSignature, context->macBuf, ulSignatureLen))
             crv = CKR_SIGNATURE_INVALID;
     }
 
     sftk_TerminateOp(session, SFTK_VERIFY, context);
     sftk_FreeSession(session);
     return crv;
 }
 
--- a/security/nss/lib/softoken/tlsprf.c
+++ b/security/nss/lib/softoken/tlsprf.c
@@ -124,17 +124,17 @@ sftk_TLSPRFVerify(TLSPRFContext *cx,
     if (hashLen) {
         /* hashLen is non-zero when the user does a one-step verify.
         ** In this case, none of the data has been input yet.
         */
         sftk_TLSPRFHashUpdate(cx, hash, hashLen);
     }
     rv = sftk_TLSPRFUpdate(cx, tmp, &tmpLen, sigLen, NULL, 0);
     if (rv == SECSuccess) {
-        rv = (SECStatus)(1 - !PORT_Memcmp(tmp, sig, sigLen));
+        rv = (SECStatus)(1 - !NSS_SecureMemcmp(tmp, sig, sigLen));
     }
     PORT_ZFree(tmp, sigLen);
     return rv;
 }
 
 static void
 sftk_TLSPRFHashDestroy(TLSPRFContext *cx, PRBool freeit)
 {
--- a/security/nss/lib/util/quickder.c
+++ b/security/nss/lib/util/quickder.c
@@ -753,17 +753,17 @@ DecodeItem(void* dest,
                                     temp.len--;
                                 }
                             }
                             break;
                         }
 
                         case SEC_ASN1_BIT_STRING: {
                             /* Can't be 8 or more spare bits, or any spare bits
-			     * if there are no octets. */
+                             * if there are no octets. */
                             if (temp.data[0] >= 8 || (temp.data[0] > 0 && temp.len == 1)) {
                                 PORT_SetError(SEC_ERROR_BAD_DER);
                                 rv = SECFailure;
                                 break;
                             }
                             /* change the length in the SECItem to be the number
                                of bits */
                             temp.len = (temp.len - 1) * 8 - (temp.data[0] & 0x7);
--- a/security/nss/tests/ssl/ssl.sh
+++ b/security/nss/tests/ssl/ssl.sh
@@ -79,17 +79,17 @@ ssl_init()
   PORT=${PORT-8443}
   # Avoid port conflicts when multiple tests are running on the same machine.
   if [ -n "$NSS_TASKCLUSTER_MAC" ]; then
     cwd=$(cd $(dirname $0); pwd -P)
     padd=$(echo $cwd | cut -d "/" -f4 | sed 's/[^0-9]//g')
     PORT=$(($PORT + $padd))
   fi
   NSS_SSL_TESTS=${NSS_SSL_TESTS:-normal_normal}
-  nss_ssl_run="stapling signed_cert_timestamps cov auth dtls scheme"
+  nss_ssl_run="stapling signed_cert_timestamps cov auth dtls scheme exporter"
   NSS_SSL_RUN=${NSS_SSL_RUN:-$nss_ssl_run}
 
   # Test case files
   SSLCOV=${QADIR}/ssl/sslcov.txt
   SSLAUTH=${QADIR}/ssl/sslauth.txt
   SSLSTRESS=${QADIR}/ssl/sslstress.txt
   SSLPOLICY=${QADIR}/ssl/sslpolicy.txt
   REQUEST_FILE=${QADIR}/ssl/sslreq.dat
@@ -1314,16 +1314,48 @@ ssl_scheme_stress()
             kill_selfserv
         done
     done
     NO_ECC_CERTS=0
 
     html "</TABLE><BR>"
 }
 
+############################ ssl_exporter ###################################
+# local shell function to test tstclnt and selfserv handling of TLS exporter
+#########################################################################
+ssl_exporter()
+{
+    html_head "SSL EXPORTER $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE"
+
+    save_fileout=${fileout}
+    fileout=1
+    SAVE_SERVEROUTFILE=${SERVEROUTFILE}
+    SERVEROUTFILE=server.out
+    exporters=("label" "label:10" "label:10:0xdeadbeef" "0x666f6f2c:10:0xdeadbeef" "label1:10:0xdeadbeef,label2:10")
+    for exporter in "${exporters[@]}"; do
+        start_selfserv -V tls1.2:tls1.2 -x "$exporter"
+
+        echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f -d ${P_R_CLIENTDIR} $verbose ${CLIENT_OPTIONS} \\"
+        echo "        -V tls1.2:tls1.2 -x $exporter < ${REQUEST_FILE}"
+        ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${CLIENT_OPTIONS} \
+                    -d ${P_R_CLIENTDIR} $verbose -V tls1.2:tls1.2 -x "$exporter" < ${REQUEST_FILE} 2>&1 > client.out
+        kill_selfserv
+        diff <(LC_ALL=C grep -A1 "^ *Keying Material:" server.out) \
+             <(LC_ALL=C grep -A1 "^ *Keying Material:" client.out)
+        ret=$?
+        html_msg $ret 0 "${testname}" \
+                 "produced a returncode of $ret, expected is 0"
+    done
+    SERVEROUTFILE=${SAVE_SERVEROUTFILE}
+    fileout=${save_fileout}
+
+    html "</TABLE><BR>"
+}
+
 ############################## ssl_cleanup #############################
 # local shell function to finish this script (no exit since it might be
 # sourced)
 ########################################################################
 ssl_cleanup()
 {
   rm $SERVERPID 2>/dev/null
   cd ${QADIR}
@@ -1358,16 +1390,19 @@ ssl_run()
             ;;
         "dtls")
             ssl_dtls
             ;;
         "scheme")
             ssl_scheme
             ssl_scheme_stress
             ;;
+        "exporter")
+            ssl_exporter
+            ;;
          esac
     done
 }
 
 ############################ ssl_run_all ###############################
 # local shell function to run both standard and extended ssl tests
 ########################################################################
 ssl_run_all()