Bug 1711262 - land NSS 40edc4f4c117 UPGRADE_NSS_RELEASE, r=beurdouche
authorBenjamin Beurdouche <bbeurdouche@mozilla.com>
Thu, 20 May 2021 17:42:35 +0000
changeset 580336 c1a23140d051534b0ccc0f89d605134e312ab2fd
parent 580335 f50820278a98553b80954165cee19ae9f42e9f02
child 580337 34cf03d9341a0b3d33df2b924b9354d9e07a368b
push id143501
push userbbeurdouche@mozilla.com
push dateThu, 20 May 2021 18:13:36 +0000
treeherderautoland@c1a23140d051 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbeurdouche
bugs1711262, 1710773, 19790, 24759
milestone90.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 1711262 - land NSS 40edc4f4c117 UPGRADE_NSS_RELEASE, r=beurdouche 2021-05-11 Robert Relyea <rrelyea@redhat.com> * automation/abi-check/expected-report-libnss3.so.txt, automation/abi- check/expected-report-libssl3.so.txt, cmd/selfserv/selfserv.c, cmd/strsclnt/strsclnt.c, cmd/tstclnt/tstclnt.c, lib/nss/nss.def, lib/pk11wrap/pk11cxt.c, lib/pk11wrap/pk11load.c, lib/pk11wrap/pk11obj.c, lib/pk11wrap/pk11priv.h, lib/pk11wrap/pk11pub.h, lib/pk11wrap/pk11slot.c, lib/pk11wrap/secmodt.h, lib/softoken/config.mk, lib/softoken/fips_algorithms.h, lib/softoken/fipstokn.c, lib/softoken/pkcs11.c, lib/softoken/pkcs11c.c, lib/softoken/pkcs11i.h, lib/softoken/pkcs11u.c, lib/softoken/sftkmessage.c, lib/ssl/ssl3con.c, lib/ssl/sslimpl.h, lib/ssl/sslinfo.c, lib/ssl/sslt.h, lib/util/pkcs11n.h, tests/ssl/ssl.sh, tests/ssl/sslcov.txt: Bug 1710773 NSS needs FIPS 180-3 FIPS indicators. r=mt Changes from the review: The while loop was taken out of it's subshell pipe, which prevented the selfserv PID from being passed on to the final selfserv-kill. This eventally lead to a freeze on windows. The last paragraph of ISO 19790:2012 section 7.2.4.2 states: All services shall [02.24] provide an indicator when the service utilises an approved cryptographic algorithm, security function or process in an approved manner and those services or processes specified in 7.4.3 This means our libraries need to grow an API or provide some additional information via contexts or similar in order for an application to be able to query this indicator. This can't be just a Security Policy description because ISO 24759:2017 section 6.2.4.2 states: TE02.24.02: The tester shall execute all services and verify that the indicator provides an unambiguous indication of whether the service utilizes an approved cryptographic algorithm, security function or process in an approved manner or not. The indicator can't be just a marker over an algorithm either, because it needs to show different values based on whether the algorithm parameters causes the algorithm to run in approved or non- approved mode (ie keys outside of valid range for RSA means RSA is being used in non-approved mode ...) For NSS, there is a PKCS #11 design: https://docs.google.com/documen t/d/1Me9YksPE7K1Suvk9Ls5PqJXPpDmpAboLsrq0z54m_tA/edit?usp=sharing This patch implments the above design as well as: 1) NSS proper functions to access these indicators from either the pk11wrap layer or the ssl layer. 2) Updates to the ssl tests which will output the value of the Changes decription by file: cmd/selfserv/selfserv.c Add a FIPS indicator if the connection was excuted in FIPS mode on a FIPS token. cmd/strsclnt/strsclnt.c Add a FIPS indicator if the connection was excuted in FIPS mode on a FIPS token. cmd/tstclnt/tstclnt.c Add a FIPS indicator if the connection was excuted in FIPS mode on a FIPS token. lib/nss/nss.def Add the new pk11 functions to access the fips indicator. lib/pk11wrap/pk11cxt.c Implement a function to get the FIPS indicator for the current PK11Context. lib/pk11wrap/pk11load.c Get the fips indicator function from the PKCS #11 module using the vendor function interface from PKCS #11 v3.0 lib/pk11wrap/pk11obj.c Implement a function to get the FIPS indicator for a specific PKCS #11 object. lib/pk11wrap/pk11priv.h Add a generalized helper function to get the FIPS indicator used by all the other exported functions to get FIPS indicator. lib/pk11wrap/pk11pub.h Add function to get the FIPS indicator for the current PK11Context. lib/pk11wrap/pk11slot.c Implement a generalized helper function to get the FIPS indicator. Implement a function to get the FIPS indicator for the latest single shot operation on the slot. lib/pk11wrap/secmodt.h Add a new field to hold the fipsIndicator function. lib/softoken/fips_algorithms.h New sample header which vendors can replace with their own table. In the default NSS case, the table in this header will be empty. lib/softoken/fipstokn.c Add Vendor specific interface for the FIPS indicator to the FIPS token. lib/softoken/pkcs11.c Add Vendor specific interface for the FIPS indicator to the non-FIPS token. Factor out the code tha maps an attribute value to a mechanism flag to it's own file so it can be used by other parts of softoken. (new function is in pkcs11u.c Implement the function that returns the FIPS indicator. This function fetches the indicator from either the session or the object or both. The session indicator is in the crypto context (except the last operation indicator, which is in the session itself. The object indicator is in the base object. lib/softoken/pkcs11c.c Record the FIPS indicator in the various helper function. - sftk_TerminateOp is called when a crypto operation had been finalized, so we can store that fips indicator in the lastOpWasFIPS field. - sftk_InitGeneric is called when a crypto operation has been initialized, so we can make a preliminary determination if the operation is within the FIPS policy (could later change bases on other operations. For this to work, we need the actual mechanism, so pMechanism is now a parameter to sftk_InitGeneric. - sftk_HKDF - HKDF when used in TLS has the unusual characteristic that the salt could actually be a key. In this case, usually the base key is some known public value which would not be FIPS generated, but the security is based on whether the salt is really a FIPS generated key. In this case we redo the calculation based on the salt key. lib/softoken/pkcs11i.h - add the FIPS indicators to the various structures (crypto contexts, sessions, objects). - add the FIPS indicators function list - add pMechanism the the sftkInitGeneric function. - add the helper function to map Attribute Types to Mechanism Flags. - add the function that will look up the current operation in the FIPS table to determine that it is allowed by policy. lib/softoken/pkcs11u.c - include the new fips_algorithms.h (if NSS_FIPS_DISABLED is not on) - handle the FIPS status for objects and session on creation an copy. - implement the helper function to map Attribute Types to Mechanism Flags. - get the key length of a key. This involves getting the key type and then using the key type to determin the appropriate attribute to fetch. Most keys it's simply the CKA_VALUE. ECC is special, we get the key length from the curve. Since only a subset of curves can be FIPS Curves, we use key length to return false for other curves. - the handle special function handles any unusal semantics for various mechanism types. This function precodes possible mechanism semantics we may need to check. The special handling can be selected by the mechanism table in fips_algorithms.h - sftk_operationIsFIPS - the actual function to determine if the givelib/n operation is in the FIPS table. lib/softoken/sftkmessage.c - just need to update the sftk_InitGeneric function to pass the mechanism. lib/ssl/ssl3con.c - and functions to query the underlying crypto contexts to see if the current ssl session is running in FIPS approved mode based on the security policy. It does so by checking the CipherSpecIsFIPS function to verify that both the mac and the encryption algorithm FIPS conforms to the ciphers in the security profile (using PK11_GetFIPSStatus). We check both the cipher specs for read and write. These underlying specs depends on the keys used in these specs being generated with FIPS approved algorithms as well, so this verifies the kea and kdf functions as well. lib/ssl/sslimpl.h - ass ssl_isFIPS() so it can be used by other files here in the ssl directory. lib/ssl/sslinfo.c - set the new isFIPS field in the existing sslinfo structure. SSL_GetChannelInfo knows how to handle sslinfo structures that are smaller then expected and larger than expected. unknown fields will be set to '0' (so new applications running against old versions will always get zero for new fields). sslinfo that are smaller will only return a the subset the calling application expects (so old applications will not get the new fields). lib/ssl/sslt.h - Add the new isFIPS field (must be at the end of the ChannelInfo structure). lib/util/pkcs11n.h - add the new FIPS indicator defines. tests/ssl/ssl.h - The main changes was to turn on verbose for the coverage tests so we can test the FIPS indicators on various cipher suites. NOTE: this only works with either NSS_TEST_FIPS_ALGORIHTMS set, or a vendor fips_algorthims.h, so vendors will need to do their own test interpretation. While working in ssl.sh I fixed an number of other issues: - many tests that were skipped in FIPS mode were skipped not because they didn't work in FIPS mode, but because tstclnt requires a password when running in FIPS mode. I've now added the password if the function is running in fips mode and removed the fips restrictions. - dtls had a race condition. the server side needed to come up before the client, but couldn't end before the client ran. We already had a sleep to guarrentee the former, I added a sleep before sending the server it's data to handle the latter. - CURVE25519 is the default ECC curve, but it's not a fiPS curve, so I disable it in FIPS mode so we will actually get FIPS indicators when using ECDHE. - I added TLS 1.3 to the coverage tests. [40edc4f4c117] [tip] Differential Revision: https://phabricator.services.mozilla.com/D115625
security/nss/TAG-INFO
security/nss/automation/abi-check/expected-report-libnss3.so.txt
security/nss/automation/abi-check/expected-report-libssl3.so.txt
security/nss/cmd/selfserv/selfserv.c
security/nss/cmd/strsclnt/strsclnt.c
security/nss/cmd/tstclnt/tstclnt.c
security/nss/coreconf/coreconf.dep
security/nss/lib/nss/nss.def
security/nss/lib/pk11wrap/pk11cxt.c
security/nss/lib/pk11wrap/pk11load.c
security/nss/lib/pk11wrap/pk11obj.c
security/nss/lib/pk11wrap/pk11priv.h
security/nss/lib/pk11wrap/pk11pub.h
security/nss/lib/pk11wrap/pk11slot.c
security/nss/lib/pk11wrap/secmodt.h
security/nss/lib/softoken/config.mk
security/nss/lib/softoken/fips_algorithms.h
security/nss/lib/softoken/fipstokn.c
security/nss/lib/softoken/pkcs11.c
security/nss/lib/softoken/pkcs11c.c
security/nss/lib/softoken/pkcs11i.h
security/nss/lib/softoken/pkcs11u.c
security/nss/lib/softoken/sftkmessage.c
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslinfo.c
security/nss/lib/ssl/sslt.h
security/nss/lib/util/pkcs11n.h
security/nss/tests/ssl/ssl.sh
security/nss/tests/ssl/sslcov.txt
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-8c299ec6b2bc
\ No newline at end of file
+40edc4f4c117
\ No newline at end of file
--- a/security/nss/automation/abi-check/expected-report-libnss3.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libnss3.so.txt
@@ -0,0 +1,17 @@
+
+3 Added functions:
+
+  'function PRBool PK11_ContextGetFIPSStatus(PK11Context*)'    {PK11_ContextGetFIPSStatus@@NSS_3.66}
+  'function PRBool PK11_ObjectGetFIPSStatus(PK11ObjectType, void*)'    {PK11_ObjectGetFIPSStatus@@NSS_3.66}
+  'function PRBool PK11_SlotGetLastFIPSStatus(PK11SlotInfo*)'    {PK11_SlotGetLastFIPSStatus@@NSS_3.66}
+
+1 function with some indirect sub-type change:
+
+  [C]'function SECStatus PK11_GetModInfo(SECMODModule*, CK_INFO*)' at pk11util.c:613:1 has some indirect sub-type changes:
+    parameter 1 of type 'SECMODModule*' has sub-type changes:
+      in pointed to type 'typedef SECMODModule' at secmodt.h:29:1:
+        underlying type 'struct SECMODModuleStr' at secmodt.h:44:1 changed:
+          type size changed from 1664 to 1728 bits
+          1 data member insertion:
+            'CK_NSS_GetFIPSStatus SECMODModuleStr::fipsIndicator', at offset 1664 (in bits) at secmodt.h:79:1
+          no data member changes (2 filtered);
--- a/security/nss/automation/abi-check/expected-report-libssl3.so.txt
+++ b/security/nss/automation/abi-check/expected-report-libssl3.so.txt
@@ -0,0 +1,10 @@
+
+1 function with some indirect sub-type change:
+
+  [C]'function SECStatus SSL_GetChannelInfo(PRFileDesc*, SSLChannelInfo*, PRUintn)' at sslinfo.c:14:1 has some indirect sub-type changes:
+    parameter 2 of type 'SSLChannelInfo*' has sub-type changes:
+      in pointed to type 'typedef SSLChannelInfo' at sslt.h:383:1:
+        underlying type 'struct SSLChannelInfoStr' at sslt.h:299:1 changed:
+          type size changed from 1024 to 1088 bits
+          1 data member insertion:
+            'PRBool SSLChannelInfoStr::isFIPS', at offset 1024 (in bits) at sslt.h:379:1
--- a/security/nss/cmd/selfserv/selfserv.c
+++ b/security/nss/cmd/selfserv/selfserv.c
@@ -399,20 +399,21 @@ printSecurityInfo(PRFileDesc *fd)
     result = SSL_GetChannelInfo(fd, &channel, sizeof channel);
     if (result == SECSuccess &&
         channel.length == sizeof channel &&
         channel.cipherSuite) {
         result = SSL_GetCipherSuiteInfo(channel.cipherSuite,
                                         &suite, sizeof suite);
         if (result == SECSuccess) {
             FPRINTF(stderr,
-                    "selfserv: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
+                    "selfserv: SSL version %d.%d using %d-bit %s with %d-bit %s MAC%s\n",
                     channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
                     suite.effectiveKeyBits, suite.symCipherName,
-                    suite.macBits, suite.macAlgorithmName);
+                    suite.macBits, suite.macAlgorithmName,
+                    channel.isFIPS ? " FIPS" : "");
             FPRINTF(stderr,
                     "selfserv: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
                     "          Compression: %s, Extended Master Secret: %s\n",
                     channel.authKeyBits, suite.authAlgorithmName,
                     channel.keaKeyBits, suite.keaTypeName,
                     channel.compressionMethodName,
                     channel.extendedMasterSecretUsed ? "Yes" : "No");
         }
--- a/security/nss/cmd/strsclnt/strsclnt.c
+++ b/security/nss/cmd/strsclnt/strsclnt.c
@@ -290,20 +290,21 @@ printSecurityInfo(PRFileDesc *fd)
     result = SSL_GetChannelInfo(fd, &channel, sizeof channel);
     if (result == SECSuccess &&
         channel.length == sizeof channel &&
         channel.cipherSuite) {
         result = SSL_GetCipherSuiteInfo(channel.cipherSuite,
                                         &suite, sizeof suite);
         if (result == SECSuccess) {
             FPRINTF(stderr,
-                    "strsclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
+                    "strsclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC%s\n",
                     channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
                     suite.effectiveKeyBits, suite.symCipherName,
-                    suite.macBits, suite.macAlgorithmName);
+                    suite.macBits, suite.macAlgorithmName,
+                    channel.isFIPS ? " FIPS" : "");
             FPRINTF(stderr,
                     "strsclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
                     "          Compression: %s\n",
                     channel.authKeyBits, suite.authAlgorithmName,
                     channel.keaKeyBits, suite.keaTypeName,
                     channel.compressionMethodName);
         }
     }
--- a/security/nss/cmd/tstclnt/tstclnt.c
+++ b/security/nss/cmd/tstclnt/tstclnt.c
@@ -163,20 +163,21 @@ printSecurityInfo(PRFileDesc *fd)
     result = SSL_GetChannelInfo(fd, &channel, sizeof channel);
     if (result == SECSuccess &&
         channel.length == sizeof channel &&
         channel.cipherSuite) {
         result = SSL_GetCipherSuiteInfo(channel.cipherSuite,
                                         &suite, sizeof suite);
         if (result == SECSuccess) {
             FPRINTF(stderr,
-                    "tstclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
+                    "tstclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC%s\n",
                     channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
                     suite.effectiveKeyBits, suite.symCipherName,
-                    suite.macBits, suite.macAlgorithmName);
+                    suite.macBits, suite.macAlgorithmName,
+                    channel.isFIPS ? " FIPS" : "");
             FPRINTF(stderr,
                     "tstclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
                     "         Compression: %s, Extended Master Secret: %s\n"
                     "         Signature Scheme: %s\n",
                     channel.authKeyBits, suite.authAlgorithmName,
                     channel.keaKeyBits, suite.keaTypeName,
                     channel.compressionMethodName,
                     channel.extendedMasterSecretUsed ? "Yes" : "No",
--- 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/lib/nss/nss.def
+++ b/security/nss/lib/nss/nss.def
@@ -1217,16 +1217,24 @@ PK11_PubUnwrapSymKeyWithMechanism;
 ;+    global:
 PK11_HPKE_ExportContext;
 PK11_HPKE_ImportContext;
 ;+    local:
 ;+       *;
 ;+};
 ;+NSS_3.65 { 	# NSS 3.65 release
 ;+    global:
+HASH_GetHMACOidTagByHashOidTag;
 PK11_CreateContextByPubKey;
 PK11_CreateContextByPrivKey;
 PK11_ExportEncryptedPrivKeyInfoV2;
 PK11_ExportEncryptedPrivateKeyInfoV2;
-HASH_GetHMACOidTagByHashOidTag;
 ;+    local:
 ;+       *;
 ;+};
+;+NSS_3.66 { 	# NSS 3.66 release
+;+    global:
+PK11_ContextGetFIPSStatus;
+PK11_ObjectGetFIPSStatus;
+PK11_SlotGetLastFIPSStatus;
+;+    local:
+;+       *;
+;+};
--- a/security/nss/lib/pk11wrap/pk11cxt.c
+++ b/security/nss/lib/pk11wrap/pk11cxt.c
@@ -1778,8 +1778,18 @@ PK11_DigestFinal(PK11Context *context, u
 
     if (crv != CKR_OK) {
         PORT_SetError(PK11_MapError(crv));
         return SECFailure;
     }
     *outLen = (unsigned int)len;
     return SECSuccess;
 }
+
+PRBool
+PK11_ContextGetFIPSStatus(PK11Context *context)
+{
+    if (context->slot == NULL) {
+        return PR_FALSE;
+    }
+    return pk11slot_GetFIPSStatus(context->slot, context->session,
+                                  CK_INVALID_HANDLE, context->init ? CKT_NSS_SESSION_CHECK : CKT_NSS_SESSION_LAST_CHECK);
+}
--- a/security/nss/lib/pk11wrap/pk11load.c
+++ b/security/nss/lib/pk11wrap/pk11load.c
@@ -404,16 +404,18 @@ secmod_LoadPKCS11Module(SECMODModule *mo
     const char *nss_interface;
     const char *nss_function;
 #endif
     CK_INTERFACE_PTR interface;
 
     if (mod->loaded)
         return SECSuccess;
 
+    mod->fipsIndicator = NULL;
+
     /* internal modules get loaded from their internal list */
     if (mod->internal && (mod->dllName == NULL)) {
 #ifdef NSS_STATIC_SOFTOKEN
         ientry = (CK_C_GetInterface)NSC_GetInterface;
 #else
         /*
          * Loads softoken as a dynamic library,
          * even though the rest of NSS assumes this as the "internal" module.
@@ -509,16 +511,21 @@ secmod_LoadPKCS11Module(SECMODModule *mo
                       CKF_INTERFACE_FORK_SAFE) != CKR_OK) {
             /* one is not appearantly available, get a non-fork safe version */
             if ((*ientry)((CK_UTF8CHAR_PTR) "PKCS 11", NULL, &interface, 0) != CKR_OK) {
                 goto fail;
             }
         }
         mod->functionList = interface->pFunctionList;
         mod->flags = interface->flags;
+        /* if we have a fips indicator, grab it */
+        if ((*ientry)((CK_UTF8CHAR_PTR) "Vendor NSS FIPS Interface", NULL,
+                      &interface, 0) == CKR_OK) {
+            mod->fipsIndicator = ((CK_NSS_FIPS_FUNCTIONS *)(interface->pFunctionList))->NSC_NSSGetFIPSStatus;
+        }
     } else {
         if ((*fentry)((CK_FUNCTION_LIST_PTR *)&mod->functionList) != CKR_OK)
             goto fail;
         mod->flags = 0;
     }
 
 #ifdef DEBUG_MODULE
     modToDBG = PR_GetEnvSecure("NSS_DEBUG_PKCS11_MODULE");
--- a/security/nss/lib/pk11wrap/pk11obj.c
+++ b/security/nss/lib/pk11wrap/pk11obj.c
@@ -2260,8 +2260,23 @@ pk11_GetLowLevelKeyFromHandle(PK11SlotIn
         return NULL;
     }
 
     item->data = (unsigned char *)theTemplate[0].pValue;
     item->len = theTemplate[0].ulValueLen;
 
     return item;
 }
+
+PRBool
+PK11_ObjectGetFIPSStatus(PK11ObjectType objType, void *objSpec)
+{
+    PK11SlotInfo *slot = NULL;
+    CK_OBJECT_HANDLE handle = 0;
+
+    handle = PK11_GetObjectHandle(objType, objSpec, &slot);
+    if (handle == CK_INVALID_HANDLE) {
+        PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE);
+        return PR_FALSE;
+    }
+    return pk11slot_GetFIPSStatus(slot, slot->session, handle,
+                                  CKT_NSS_OBJECT_CHECK);
+}
--- a/security/nss/lib/pk11wrap/pk11priv.h
+++ b/security/nss/lib/pk11wrap/pk11priv.h
@@ -195,11 +195,16 @@ SECStatus pk11_RetrieveCrls(CERTCrlHeadN
 /* set global options for NSS PKCS#11 module loader */
 SECStatus pk11_setGlobalOptions(PRBool noSingleThreadedModules,
                                 PRBool allowAlreadyInitializedModules,
                                 PRBool dontFinalizeModules);
 
 /* return whether NSS is allowed to call C_Finalize */
 PRBool pk11_getFinalizeModulesOption(void);
 
+/* fetch the FIPS state from the fips indicator, public versions of
+ * this function operate on the slot, the context, and the object */
+PRBool pk11slot_GetFIPSStatus(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
+                              CK_OBJECT_HANDLE object, CK_ULONG operationType);
+
 SEC_END_PROTOS
 
 #endif
--- a/security/nss/lib/pk11wrap/pk11pub.h
+++ b/security/nss/lib/pk11wrap/pk11pub.h
@@ -1024,11 +1024,29 @@ PRBool SECMOD_HasRootCerts(void);
 /*
  * Get the state of the system FIPS mode -
  *  NSS uses this to force FIPS mode if the system bit is on. This returns
  *  the system state independent of the database state and can be called
  *  before NSS initializes.
  */
 int SECMOD_GetSystemFIPSEnabled(void);
 
+/* FIPS indicator functions. Some operations are physically allowed, but
+ * are against the NSS FIPS security policy. This is because sometimes NSS
+ * functions are used in non-security contexts. You can call these functions
+ * to determine if you are operating inside or outside the the current vendor's
+ * FIPS Security Policy for NSS. NOTE: if the current version of NSS is not
+ * actually FIPS certified, then these functions will always return PR_FALSE */
+
+/* This function tells if if the last single shot operation on the slot
+ * was inside or outside the FIPS security policy */
+PRBool PK11_SlotGetLastFIPSStatus(PK11SlotInfo *slot);
+/* This tells you if the current operation is within the FIPS security policy. If
+ * you have called finalize on the context, it tells you if the last operation
+ * was within the FIPS security policy */
+PRBool PK11_ContextGetFIPSStatus(PK11Context *context);
+/* This tells you if the requested object was created in accordance to the
+ * NSS FIPS security policy. */
+PRBool PK11_ObjectGetFIPSStatus(PK11ObjectType objType, void *objSpec);
+
 SEC_END_PROTOS
 
 #endif
--- a/security/nss/lib/pk11wrap/pk11slot.c
+++ b/security/nss/lib/pk11wrap/pk11slot.c
@@ -2660,16 +2660,49 @@ PK11Slot_SetNSSToken(PK11SlotInfo *sl, N
 }
 
 NSSToken *
 PK11Slot_GetNSSToken(PK11SlotInfo *sl)
 {
     return sl->nssToken;
 }
 
+PRBool
+pk11slot_GetFIPSStatus(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
+                       CK_OBJECT_HANDLE object, CK_ULONG operationType)
+{
+    SECMODModule *mod = slot->module;
+    CK_RV crv;
+    CK_ULONG fipsState = CKS_NSS_FIPS_NOT_OK;
+
+    /* handle the obvious conditions:
+     * 1) the module doesn't have a fipsIndicator - fips state must be false */
+    if (mod->fipsIndicator == NULL) {
+        return PR_FALSE;
+    }
+    /* 2) the session doesn't exist - fips state must be false */
+    if (session == CK_INVALID_HANDLE) {
+        return PR_FALSE;
+    }
+
+    /* go fetch the state */
+    crv = mod->fipsIndicator(session, object, operationType, &fipsState);
+    if (crv != CKR_OK) {
+        return PR_FALSE;
+    }
+    return (fipsState == CKS_NSS_FIPS_OK) ? PR_TRUE : PR_FALSE;
+}
+
+PRBool
+PK11_SlotGetLastFIPSStatus(PK11SlotInfo *slot)
+{
+    return pk11slot_GetFIPSStatus(slot, slot->session, CK_INVALID_HANDLE,
+                                  CKT_NSS_SESSION_LAST_CHECK);
+}
+
 /*
  * wait for a token to change it's state. The application passes in the expected
  * new state in event.
  */
 PK11TokenStatus
 PK11_WaitForTokenEvent(PK11SlotInfo *slot, PK11TokenEvent event,
                        PRIntervalTime timeout, PRIntervalTime latency, int series)
 {
--- a/security/nss/lib/pk11wrap/secmodt.h
+++ b/security/nss/lib/pk11wrap/secmodt.h
@@ -69,16 +69,19 @@ struct SECMODModuleStr {
     PRBool isModuleDB;           /* this module has lists of PKCS #11 modules */
     PRBool moduleDBOnly;         /* this module only has lists of PKCS #11 modules */
     int trustOrder;              /* order for this module's certificate trust rollup */
     int cipherOrder;             /* order for cipher operations */
     unsigned long evControlMask; /* control the running and shutdown of slot
                                   * events (SECMOD_WaitForAnyTokenEvent) */
     CK_VERSION cryptokiVersion;  /* version of this library */
     CK_FLAGS flags;              /* pkcs11 v3 flags */
+    /* Warning this could go way in future versions of NSS
+     * when FIPS indicators wind up in the functionList */
+    CK_NSS_GetFIPSStatus fipsIndicator;
 };
 
 /* evControlMask flags */
 /*
  * These bits tell the current state of a SECMOD_WaitForAnyTokenEvent.
  *
  * SECMOD_WAIT_PKCS11_EVENT - we're waiting in the PKCS #11 module in
  *  C_WaitForSlotEvent().
--- a/security/nss/lib/softoken/config.mk
+++ b/security/nss/lib/softoken/config.mk
@@ -49,8 +49,13 @@ EXTRA_SHARED_LIBS += \
 	-lplds4 \
 	-lnspr4 \
 	$(NULL)
 endif
 
 ifeq ($(OS_TARGET),AIX)
 OS_LIBS += -lpthread
 endif
+
+ifdef NSS_ENABLE_FIPS_INDICATORS
+DEFINES += -DNSS_ENABLE_FIPS_INDICATORS
+endif
+
new file mode 100644
--- /dev/null
+++ b/security/nss/lib/softoken/fips_algorithms.h
@@ -0,0 +1,170 @@
+/* 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/. */
+
+/*
+ * Vendors should replace this header file with the file containing those
+ * algorithms which have NIST algorithm Certificates.
+ */
+
+/* handle special cases. Classes require existing code to already be
+ * in place for that class */
+typedef enum {
+    SFTKFIPSNone = 0,
+    SFTKFIPSDH,  /* allow only specific primes */
+    SFTKFIPSECC, /* not just keys but specific curves */
+    SFTKFIPSAEAD /* single shot AEAD functions not allowed in FIPS mode */
+} SFTKFIPSSpecialClass;
+
+typedef struct SFTKFIPSAlgorithmListStr SFTKFIPSAlgorithmList;
+struct SFTKFIPSAlgorithmListStr {
+    CK_MECHANISM_TYPE type;
+    CK_MECHANISM_INFO info;
+    CK_ULONG step;
+    SFTKFIPSSpecialClass special;
+};
+
+SFTKFIPSAlgorithmList sftk_fips_mechs[] = {
+/* A sample set of algorithms to allow basic testing in our continous
+ * testing infrastructure. The vendor version should replace this with
+ * a version that matches their algorithm testing and security policy */
+/* NOTE, This looks a lot like the PKCS #11 mechanism list in pkcs11.c, it
+ * differs in the following ways:
+ *    1) the addition of step and class elements to help restrict
+ *       the supported key sizes and types.
+ *    2) The mechanism flags are restricted to only those that map to
+ *       fips approved operations.
+ *    3) All key sizes are in bits, independent of mechanism.
+ *    4) You can add more then one entry for the same mechanism to handle
+ *       multiple descrete keys where the MIN/MAX/STEP semantics doesn't apply
+ *       or where different operations have different key requirements.
+ * This table does not encode all the modules legal FIPS semantics, only
+ * those semantics that might possibly change due to algorithms dropping
+ * of the security policy late in the process. */
+/* handy common flag types */
+#define CKF_KPG CKF_GENERATE_KEY_PAIR
+#define CKF_GEN CKF_GENERATE
+#define CKF_SGN (CKF_SIGN | CKF_VERIFY)
+#define CKF_ENC (CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP)
+#define CKF_KEK (CKF_WRAP | CKF_UNWRAP)
+#define CKF_KEA CKF_DERIVE
+#define CKF_KDF CKF_DERIVE
+#define CKF_HSH CKF_DIGEST
+#define CK_MAX 0xffffffffUL
+/* mechanisms using the same key types share the same key type
+ * limits */
+#define RSA_FB_KEY 2048, 4096 /* min, max */
+#define RSA_FB_STEP 1024
+#define DSA_FB_KEY 2048, 4096 /* min, max */
+#define DSA_FB_STEP 1024
+#define DH_FB_KEY 2048, 4096 /* min, max */
+#define DH_FB_STEP 1024
+#define EC_FB_KEY 256, 521 /* min, max */
+#define EC_FB_STEP 1       /* key limits handled by special operation */
+#define AES_FB_KEY 128, 256
+#define AES_FB_STEP 64
+    { CKM_RSA_PKCS_KEY_PAIR_GEN, { RSA_FB_KEY, CKF_KPG }, RSA_FB_STEP, SFTKFIPSNone },
+    { CKM_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+    { CKM_RSA_PKCS_OAEP, { RSA_FB_KEY, CKF_ENC }, RSA_FB_STEP, SFTKFIPSNone },
+    /* -------------- RSA Multipart Signing Operations -------------------- */
+    { CKM_SHA224_RSA_PKCS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+    { CKM_SHA256_RSA_PKCS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+    { CKM_SHA384_RSA_PKCS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+    { CKM_SHA512_RSA_PKCS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+    { CKM_SHA224_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+    { CKM_SHA256_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+    { CKM_SHA384_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+    { CKM_SHA512_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone },
+    /* ------------------------- DSA Operations --------------------------- */
+    { CKM_DSA_KEY_PAIR_GEN, { DSA_FB_KEY, CKF_KPG }, DSA_FB_STEP, SFTKFIPSNone },
+    { CKM_DSA, { DSA_FB_KEY, CKF_SGN }, DSA_FB_STEP, SFTKFIPSNone },
+    { CKM_DSA_PARAMETER_GEN, { DSA_FB_KEY, CKF_KPG }, DSA_FB_STEP, SFTKFIPSNone },
+    { CKM_DSA_SHA224, { DSA_FB_KEY, CKF_SGN }, DSA_FB_STEP, SFTKFIPSNone },
+    { CKM_DSA_SHA256, { DSA_FB_KEY, CKF_SGN }, DSA_FB_STEP, SFTKFIPSNone },
+    { CKM_DSA_SHA384, { DSA_FB_KEY, CKF_SGN }, DSA_FB_STEP, SFTKFIPSNone },
+    { CKM_DSA_SHA512, { DSA_FB_KEY, CKF_SGN }, DSA_FB_STEP, SFTKFIPSNone },
+    /* -------------------- Diffie Hellman Operations --------------------- */
+    /* no diffie hellman yet */
+    { CKM_DH_PKCS_KEY_PAIR_GEN, { DH_FB_KEY, CKF_KPG }, DH_FB_STEP, SFTKFIPSDH },
+    { CKM_DH_PKCS_DERIVE, { DH_FB_KEY, CKF_KEA }, DH_FB_STEP, SFTKFIPSDH },
+    /* -------------------- Elliptic Curve Operations --------------------- */
+    { CKM_EC_KEY_PAIR_GEN, { EC_FB_KEY, CKF_KPG }, EC_FB_STEP, SFTKFIPSECC },
+    { CKM_ECDH1_DERIVE, { EC_FB_KEY, CKF_KEA }, EC_FB_STEP, SFTKFIPSECC },
+    { CKM_ECDSA, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC },
+    { CKM_ECDSA_SHA224, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC },
+    { CKM_ECDSA_SHA256, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC },
+    { CKM_ECDSA_SHA384, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC },
+    { CKM_ECDSA_SHA512, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC },
+    /* ------------------------- RC2 Operations --------------------------- */
+    /* ------------------------- AES Operations --------------------------- */
+    { CKM_AES_KEY_GEN, { AES_FB_KEY, CKF_GEN }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_ECB, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_CBC, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_MAC, { AES_FB_KEY, CKF_SGN }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_MAC_GENERAL, { AES_FB_KEY, CKF_SGN }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_CMAC, { AES_FB_KEY, CKF_SGN }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_CMAC_GENERAL, { AES_FB_KEY, CKF_SGN }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_CBC_PAD, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_CTS, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_CTR, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_GCM, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSAEAD },
+    { CKM_AES_KEY_WRAP, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_KEY_WRAP_PAD, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_KEY_WRAP_KWP, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone },
+    { CKM_AES_XCBC_MAC_96, { 96, 96, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_AES_XCBC_MAC, { 128, 128, CKF_SGN }, 1, SFTKFIPSNone },
+    /* ------------------------- Hashing Operations ----------------------- */
+    { CKM_SHA224, { 0, 0, CKF_HSH }, 1, SFTKFIPSNone },
+    { CKM_SHA224_HMAC, { 112, 224, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_SHA224_HMAC_GENERAL, { 112, 224, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_SHA256, { 0, 0, CKF_HSH }, 1, SFTKFIPSNone },
+    { CKM_SHA256_HMAC, { 128, 256, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_SHA256_HMAC_GENERAL, { 128, 256, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_SHA384, { 0, 0, CKF_HSH }, 1, SFTKFIPSNone },
+    { CKM_SHA384_HMAC, { 192, 384, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_SHA384_HMAC_GENERAL, { 192, 384, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_SHA512, { 0, 0, CKF_HSH }, 1, SFTKFIPSNone },
+    { CKM_SHA512_HMAC, { 256, 512, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_SHA512_HMAC_GENERAL, { 256, 512, CKF_SGN }, 1, SFTKFIPSNone },
+    /* --------------------- Secret Key Operations ------------------------ */
+    { CKM_GENERIC_SECRET_KEY_GEN, { 8, 256, CKF_GEN }, 1, SFTKFIPSNone },
+    /* ---------------------- SSL/TLS operations ------------------------- */
+    { CKM_SHA224_KEY_DERIVATION, { 112, 224, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_SHA256_KEY_DERIVATION, { 128, 256, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_SHA384_KEY_DERIVATION, { 192, 284, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_SHA512_KEY_DERIVATION, { 256, 512, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_TLS12_MASTER_KEY_DERIVE, { 384, 384, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_TLS12_MASTER_KEY_DERIVE_DH, { DH_FB_KEY, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_TLS12_KEY_AND_MAC_DERIVE, { 384, 384, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_TLS_PRF_GENERAL, { 8, 512, CKF_SGN }, 1, SFTKFIPSNone },
+    { CKM_TLS_MAC, { 8, 512, CKF_SGN }, 1, SFTKFIPSNone },
+    /* sigh, is this algorithm really tested. ssl doesn't seem to have a
+     * way of turning the extension off */
+    { CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE, { 192, 1024, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH, { 192, 1024, CKF_DERIVE }, 1, SFTKFIPSNone },
+
+    /* ------------------------- HKDF Operations -------------------------- */
+    { CKM_HKDF_DERIVE, { 8, 255 * 64 * 8, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_HKDF_DATA, { 8, 255 * 64 * 8, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_HKDF_KEY_GEN, { 160, 224, CKF_GEN }, 1, SFTKFIPSNone },
+    { CKM_HKDF_KEY_GEN, { 256, 512, CKF_GEN }, 128, SFTKFIPSNone },
+    /* ------------------ NIST 800-108 Key Derivations  ------------------- */
+    { CKM_SP800_108_COUNTER_KDF, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_SP800_108_FEEDBACK_KDF, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_SP800_108_DOUBLE_PIPELINE_KDF, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_NSS_SP800_108_COUNTER_KDF_DERIVE_DATA, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_NSS_SP800_108_FEEDBACK_KDF_DERIVE_DATA, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_NSS_SP800_108_DOUBLE_PIPELINE_KDF_DERIVE_DATA, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone },
+    /* --------------------IPSEC ----------------------- */
+    { CKM_NSS_IKE_PRF_PLUS_DERIVE, { 8, 255 * 64, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_NSS_IKE_PRF_DERIVE, { 8, 64, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_NSS_IKE1_PRF_DERIVE, { 8, 64, CKF_KDF }, 1, SFTKFIPSNone },
+    { CKM_NSS_IKE1_APP_B_PRF_DERIVE, { 8, 255 * 64, CKF_KDF }, 1, SFTKFIPSNone },
+    /* ------------------ PBE Key Derivations  ------------------- */
+    { CKM_PKCS5_PBKD2, { 1, 256, CKF_GEN }, 1, SFTKFIPSNone },
+    { CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN, { 224, 224, CKF_GEN }, 1, SFTKFIPSNone },
+    { CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN, { 256, 256, CKF_GEN }, 1, SFTKFIPSNone },
+    { CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN, { 384, 384, CKF_GEN }, 1, SFTKFIPSNone },
+    { CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN, { 512, 512, CKF_GEN }, 1, SFTKFIPSNone }
+};
+const int SFTK_NUMBER_FIPS_ALGORITHMS = PR_ARRAY_SIZE(sftk_fips_mechs);
--- a/security/nss/lib/softoken/fipstokn.c
+++ b/security/nss/lib/softoken/fipstokn.c
@@ -296,20 +296,21 @@ static CK_FUNCTION_LIST sftk_fipsTable_v
 #undef __PASTE
 
 /*
  * Array is orderd by default first
  */
 static CK_INTERFACE fips_interfaces[] = {
     { (CK_UTF8CHAR_PTR) "PKCS 11", &sftk_fipsTable, NSS_INTERFACE_FLAGS },
     { (CK_UTF8CHAR_PTR) "PKCS 11", &sftk_fipsTable_v2, NSS_INTERFACE_FLAGS },
-    { (CK_UTF8CHAR_PTR) "Vendor NSS Module Interface", &sftk_module_funcList, NSS_INTERFACE_FLAGS }
+    { (CK_UTF8CHAR_PTR) "Vendor NSS Module Interface", &sftk_module_funcList, NSS_INTERFACE_FLAGS },
+    { (CK_UTF8CHAR_PTR) "Vendor NSS FIPS Interface", &sftk_fips_funcList, NSS_INTERFACE_FLAGS }
 };
 /* must match the count of interfaces in fips_interfaces above*/
-#define FIPS_INTERFACE_COUNT 3
+#define FIPS_INTERFACE_COUNT 4
 
 /* CKO_NOT_A_KEY can be any object class that's not a key object. */
 #define CKO_NOT_A_KEY CKO_DATA
 
 #define SFTK_IS_KEY_OBJECT(objClass)    \
     (((objClass) == CKO_PUBLIC_KEY) ||  \
      ((objClass) == CKO_PRIVATE_KEY) || \
      ((objClass) == CKO_SECRET_KEY))
--- a/security/nss/lib/softoken/pkcs11.c
+++ b/security/nss/lib/softoken/pkcs11.c
@@ -140,26 +140,37 @@ static CK_FUNCTION_LIST sftk_funcList_v2
 
 #undef __PASTE
 
 CK_NSS_MODULE_FUNCTIONS sftk_module_funcList = {
     { 1, 0 },
     NSC_ModuleDBFunc
 };
 
+static CK_RV
+nsc_NSSGetFIPSStatus(CK_SESSION_HANDLE hSession,
+                     CK_OBJECT_HANDLE hObject,
+                     CK_ULONG ulOperationType,
+                     CK_ULONG *pulFIPSStatus);
+CK_NSS_FIPS_FUNCTIONS sftk_fips_funcList = {
+    { 1, 0 },
+    nsc_NSSGetFIPSStatus
+};
+
 /*
  * Array is orderd by default first
  */
 static CK_INTERFACE nss_interfaces[] = {
     { (CK_UTF8CHAR_PTR) "PKCS 11", &sftk_funcList, NSS_INTERFACE_FLAGS },
     { (CK_UTF8CHAR_PTR) "PKCS 11", &sftk_funcList_v2, NSS_INTERFACE_FLAGS },
-    { (CK_UTF8CHAR_PTR) "Vendor NSS Module Interface", &sftk_module_funcList, NSS_INTERFACE_FLAGS }
+    { (CK_UTF8CHAR_PTR) "Vendor NSS Module Interface", &sftk_module_funcList, NSS_INTERFACE_FLAGS },
+    { (CK_UTF8CHAR_PTR) "Vendor NSS FIPS Interface", &sftk_fips_funcList, NSS_INTERFACE_FLAGS }
 };
 /* must match the count of interfaces in nss_interfaces above */
-#define NSS_INTERFACE_COUNT 3
+#define NSS_INTERFACE_COUNT 4
 
 /* List of DES Weak Keys */
 typedef unsigned char desKey[8];
 static const desKey sftk_desWeakTable[] = {
 #ifdef noParity
     /* weak */
     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
     { 0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e },
@@ -3844,60 +3855,20 @@ NSC_GetMechanismInfoV2(CK_SLOT_ID slotID
     }
     return crv;
 }
 
 CK_RV
 sftk_MechAllowsOperation(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE op)
 {
     CK_ULONG i;
-    CK_FLAGS flags;
-
-    switch (op) {
-        case CKA_ENCRYPT:
-            flags = CKF_ENCRYPT;
-            break;
-        case CKA_DECRYPT:
-            flags = CKF_DECRYPT;
-            break;
-        case CKA_WRAP:
-            flags = CKF_WRAP;
-            break;
-        case CKA_UNWRAP:
-            flags = CKF_UNWRAP;
-            break;
-        case CKA_SIGN:
-            flags = CKF_SIGN;
-            break;
-        case CKA_SIGN_RECOVER:
-            flags = CKF_SIGN_RECOVER;
-            break;
-        case CKA_VERIFY:
-            flags = CKF_VERIFY;
-            break;
-        case CKA_VERIFY_RECOVER:
-            flags = CKF_VERIFY_RECOVER;
-            break;
-        case CKA_DERIVE:
-            flags = CKF_DERIVE;
-            break;
-        case CKA_NSS_MESSAGE | CKA_ENCRYPT:
-            flags = CKF_MESSAGE_ENCRYPT;
-            break;
-        case CKA_NSS_MESSAGE | CKA_DECRYPT:
-            flags = CKF_MESSAGE_DECRYPT;
-            break;
-        case CKA_NSS_MESSAGE | CKA_SIGN:
-            flags = CKF_MESSAGE_SIGN;
-            break;
-        case CKA_NSS_MESSAGE | CKA_VERIFY:
-            flags = CKF_MESSAGE_VERIFY;
-            break;
-        default:
-            return CKR_ARGUMENTS_BAD;
+    CK_FLAGS flags = sftk_AttributeToFlags(op);
+
+    if (flags == 0) {
+        return CKR_ARGUMENTS_BAD;
     }
     for (i = 0; i < mechanismCount; i++) {
         if (type == mechanisms[i].type) {
             return (flags & mechanisms[i].info.flags) ? CKR_OK
                                                       : CKR_MECHANISM_INVALID;
         }
     }
     return CKR_MECHANISM_INVALID;
@@ -4620,16 +4591,18 @@ NSC_CreateObject(CK_SESSION_HANDLE hSess
     }
     /*
      * now lets create an object to hang the attributes off of
      */
     object = sftk_NewObject(slot); /* fill in the handle later */
     if (object == NULL) {
         return CKR_HOST_MEMORY;
     }
+    object->isFIPS = PR_FALSE; /* if we created the object on the fly,
+                                * it's not a FIPS object */
 
     /*
      * load the template values into the object
      */
     for (i = 0; i < (int)ulCount; i++) {
         crv = sftk_AddAttributeType(object, sftk_attr_expand(&pTemplate[i]));
         if (crv != CKR_OK) {
             sftk_FreeObject(object);
@@ -5293,8 +5266,111 @@ NSC_FindObjectsFinal(CK_SESSION_HANDLE h
 CK_RV
 NSC_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot,
                      CK_VOID_PTR pReserved)
 {
     CHECK_FORK();
 
     return CKR_FUNCTION_NOT_SUPPORTED;
 }
+
+static CK_RV
+nsc_NSSGetFIPSStatus(CK_SESSION_HANDLE hSession,
+                     CK_OBJECT_HANDLE hObject,
+                     CK_ULONG ulOperationType,
+                     CK_ULONG *pulFIPSStatus)
+{
+    CK_ULONG sessionState = CKS_NSS_UNINITIALIZED;
+    CK_ULONG objectState = CKS_NSS_UNINITIALIZED;
+    PRBool needSession = PR_FALSE;
+    PRBool needObject = PR_FALSE;
+    SFTKSession *session;
+    SFTKObject *object;
+
+    *pulFIPSStatus = CKS_NSS_FIPS_NOT_OK;
+
+    /* first determine what we need to look up */
+    switch (ulOperationType) {
+        case CKT_NSS_SESSION_CHECK:
+        case CKT_NSS_SESSION_LAST_CHECK:
+            needSession = PR_TRUE;
+            needObject = PR_FALSE;
+            break;
+        case CKT_NSS_OBJECT_CHECK:
+            needSession = PR_FALSE;
+            needObject = PR_TRUE;
+            break;
+        case CKT_NSS_BOTH_CHECK:
+            needSession = PR_TRUE;
+            needObject = PR_TRUE;
+            break;
+        default:
+            return CKR_ARGUMENTS_BAD;
+    }
+
+    /* we always need the session handle, the object handle is only
+     * meaningful if there is a session */
+    session = sftk_SessionFromHandle(hSession);
+    if (!session) {
+        return CKR_SESSION_HANDLE_INVALID;
+    }
+    if (needSession) {
+        if (CKT_NSS_SESSION_LAST_CHECK == ulOperationType) {
+            sessionState = session->lastOpWasFIPS ? CKS_NSS_FIPS_OK : CKS_NSS_FIPS_NOT_OK;
+        } else {
+            if (session->enc_context) {
+                sessionState = session->enc_context->isFIPS ? CKS_NSS_FIPS_OK : CKS_NSS_FIPS_NOT_OK;
+            }
+            if (sessionState != CKS_NSS_FIPS_NOT_OK && session->hash_context) {
+                sessionState = session->hash_context->isFIPS ? CKS_NSS_FIPS_OK : CKS_NSS_FIPS_NOT_OK;
+            }
+            /* sessionState is set to CKS_NSS_UNINITIALIZED if neither
+             * context exists */
+        }
+    }
+
+    if (needObject) {
+        object = sftk_ObjectFromHandle(hObject, session);
+        if (!object) {
+            sftk_FreeSession(session);
+            return CKR_OBJECT_HANDLE_INVALID;
+        }
+        objectState = object->isFIPS ? CKS_NSS_FIPS_OK : CKS_NSS_FIPS_NOT_OK;
+        sftk_FreeObject(object);
+    }
+
+    sftk_FreeSession(session);
+
+    /* If we didn't fetch the state, then it is uninitialized.
+     * The session state can also be uninitialized if there are no active
+     * crypto operations on the session. Turns out the rules for combining
+     * the states are the same whether or not the state was uninitialzed
+     * because we didn't fetch it or because there wasn't a state to fetch.
+     */
+
+    /* if the object State is uninitialized, return the state of the session. */
+    if (objectState == CKS_NSS_UNINITIALIZED) {
+        /* if they are both uninitalized, return CKS_FIPS_NOT_OK */
+        if (sessionState == CKS_NSS_UNINITIALIZED) {
+            /* *pulFIPSStatus already set to CKS_FIPS_NOT_OK */
+            return CKR_OK;
+        }
+        *pulFIPSStatus = sessionState;
+        return CKR_OK;
+    }
+    /* objectState is initialized, if sessionState is uninitialized, we can
+     * just return objectState */
+    if (sessionState == CKS_NSS_UNINITIALIZED) {
+        *pulFIPSStatus = objectState;
+        return CKR_OK;
+    }
+
+    /* they are are not equal, one must be CKS_FIPS_NOT_OK, so we return that
+     * value CKS_FIPS_NOT_OK */
+    if (objectState != sessionState) {
+        /* *pulFIPSStatus already set to CKS_FIPS_NOT_OK */
+        return CKR_OK;
+    }
+
+    /* objectState and sessionState or the same, so we can return either */
+    *pulFIPSStatus = sessionState;
+    return CKR_OK;
+}
--- a/security/nss/lib/softoken/pkcs11c.c
+++ b/security/nss/lib/softoken/pkcs11c.c
@@ -395,30 +395,32 @@ sftk_GetContext(CK_SESSION_HANDLE handle
 
 /** Terminate operation (in the PKCS#11 spec sense).
  *  Intuitive name for FreeContext/SetNullContext pair.
  */
 void
 sftk_TerminateOp(SFTKSession *session, SFTKContextType ctype,
                  SFTKSessionContext *context)
 {
+    session->lastOpWasFIPS = context->isFIPS;
     sftk_FreeContext(context);
     sftk_SetContextByType(session, ctype, NULL);
 }
 
 /*
  ************** Crypto Functions:     Encrypt ************************
  */
 
 /*
  * All the NSC_InitXXX functions have a set of common checks and processing they
  * all need to do at the beginning. This is done here.
  */
 CK_RV
-sftk_InitGeneric(SFTKSession *session, SFTKSessionContext **contextPtr,
+sftk_InitGeneric(SFTKSession *session, CK_MECHANISM *pMechanism,
+                 SFTKSessionContext **contextPtr,
                  SFTKContextType ctype, SFTKObject **keyPtr,
                  CK_OBJECT_HANDLE hKey, CK_KEY_TYPE *keyTypePtr,
                  CK_OBJECT_CLASS pubKeyType, CK_ATTRIBUTE_TYPE operation)
 {
     SFTKObject *key = NULL;
     SFTKAttribute *att;
     SFTKSessionContext *context;
 
@@ -430,17 +432,19 @@ sftk_InitGeneric(SFTKSession *session, S
     /* find the key */
     if (keyPtr) {
         key = sftk_ObjectFromHandle(hKey, session);
         if (key == NULL) {
             return CKR_KEY_HANDLE_INVALID;
         }
 
         /* make sure it's a valid  key for this operation */
-        if (((key->objclass != CKO_SECRET_KEY) && (key->objclass != pubKeyType)) || !sftk_isTrue(key, operation)) {
+        if (((key->objclass != CKO_SECRET_KEY) &&
+             (key->objclass != pubKeyType)) ||
+            !sftk_isTrue(key, operation)) {
             sftk_FreeObject(key);
             return CKR_KEY_TYPE_INCONSISTENT;
         }
         /* get the key type */
         att = sftk_FindAttribute(key, CKA_KEY_TYPE);
         if (att == NULL) {
             sftk_FreeObject(key);
             return CKR_KEY_TYPE_INCONSISTENT;
@@ -468,17 +472,18 @@ sftk_InitGeneric(SFTKSession *session, S
     context->rsa = PR_FALSE;
     context->cipherInfo = NULL;
     context->hashInfo = NULL;
     context->doPad = PR_FALSE;
     context->padDataLength = 0;
     context->key = key;
     context->blockSize = 0;
     context->maxLen = 0;
-
+    context->isFIPS = sftk_operationIsFIPS(session->slot, pMechanism,
+                                           operation, key);
     *contextPtr = context;
     return CKR_OK;
 }
 
 static int
 sftk_aes_mode(CK_MECHANISM_TYPE mechanism)
 {
     switch (mechanism) {
@@ -808,18 +813,20 @@ sftk_CryptInit(CK_SESSION_HANDLE hSessio
     crv = sftk_MechAllowsOperation(pMechanism->mechanism, mechUsage);
     if (crv != CKR_OK)
         return crv;
 
     session = sftk_SessionFromHandle(hSession);
     if (session == NULL)
         return CKR_SESSION_HANDLE_INVALID;
 
-    crv = sftk_InitGeneric(session, &context, contextType, &key, hKey, &key_type,
-                           isEncrypt ? CKO_PUBLIC_KEY : CKO_PRIVATE_KEY, keyUsage);
+    crv = sftk_InitGeneric(session, pMechanism, &context, contextType, &key,
+                           hKey, &key_type,
+                           isEncrypt ? CKO_PUBLIC_KEY : CKO_PRIVATE_KEY,
+                           keyUsage);
 
     if (crv != CKR_OK) {
         sftk_FreeSession(session);
         return crv;
     }
 
     context->doPad = PR_FALSE;
     switch (pMechanism->mechanism) {
@@ -1895,17 +1902,18 @@ NSC_DigestInit(CK_SESSION_HANDLE hSessio
     SFTKSessionContext *context;
     CK_RV crv = CKR_OK;
 
     CHECK_FORK();
 
     session = sftk_SessionFromHandle(hSession);
     if (session == NULL)
         return CKR_SESSION_HANDLE_INVALID;
-    crv = sftk_InitGeneric(session, &context, SFTK_HASH, NULL, 0, NULL, 0, 0);
+    crv = sftk_InitGeneric(session, pMechanism, &context, SFTK_HASH,
+                           NULL, 0, NULL, 0, CKA_DIGEST);
     if (crv != CKR_OK) {
         sftk_FreeSession(session);
         return crv;
     }
 
 #define INIT_MECH(mmm)                                         \
     case CKM_##mmm: {                                          \
         mmm##Context *mmm##_ctx = mmm##_NewContext();          \
@@ -2761,18 +2769,18 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
     crv = sftk_InitCBCMac(hSession, pMechanism, hKey, CKA_SIGN, SFTK_SIGN);
     if (crv != CKR_FUNCTION_NOT_SUPPORTED)
         return crv;
 
     /* we're not using a block cipher mac */
     session = sftk_SessionFromHandle(hSession);
     if (session == NULL)
         return CKR_SESSION_HANDLE_INVALID;
-    crv = sftk_InitGeneric(session, &context, SFTK_SIGN, &key, hKey, &key_type,
-                           CKO_PRIVATE_KEY, CKA_SIGN);
+    crv = sftk_InitGeneric(session, pMechanism, &context, SFTK_SIGN, &key,
+                           hKey, &key_type, CKO_PRIVATE_KEY, CKA_SIGN);
     if (crv != CKR_OK) {
         sftk_FreeSession(session);
         return crv;
     }
 
     context->multi = PR_FALSE;
 
 #define INIT_RSA_SIGN_MECH(mmm)                         \
@@ -3560,18 +3568,18 @@ NSC_VerifyInit(CK_SESSION_HANDLE hSessio
     /* Block Cipher MACing Algorithms use a different Context init method..*/
     crv = sftk_InitCBCMac(hSession, pMechanism, hKey, CKA_VERIFY, SFTK_VERIFY);
     if (crv != CKR_FUNCTION_NOT_SUPPORTED)
         return crv;
 
     session = sftk_SessionFromHandle(hSession);
     if (session == NULL)
         return CKR_SESSION_HANDLE_INVALID;
-    crv = sftk_InitGeneric(session, &context, SFTK_VERIFY, &key, hKey, &key_type,
-                           CKO_PUBLIC_KEY, CKA_VERIFY);
+    crv = sftk_InitGeneric(session, pMechanism, &context, SFTK_VERIFY, &key,
+                           hKey, &key_type, CKO_PUBLIC_KEY, CKA_VERIFY);
     if (crv != CKR_OK) {
         sftk_FreeSession(session);
         return crv;
     }
 
     context->multi = PR_FALSE;
 
 #define INIT_RSA_VFY_MECH(mmm)                            \
@@ -3889,17 +3897,17 @@ NSC_VerifyRecoverInit(CK_SESSION_HANDLE 
     CK_RV crv = CKR_OK;
     NSSLOWKEYPublicKey *pubKey;
 
     CHECK_FORK();
 
     session = sftk_SessionFromHandle(hSession);
     if (session == NULL)
         return CKR_SESSION_HANDLE_INVALID;
-    crv = sftk_InitGeneric(session, &context, SFTK_VERIFY_RECOVER,
+    crv = sftk_InitGeneric(session, pMechanism, &context, SFTK_VERIFY_RECOVER,
                            &key, hKey, &key_type, CKO_PUBLIC_KEY, CKA_VERIFY_RECOVER);
     if (crv != CKR_OK) {
         sftk_FreeSession(session);
         return crv;
     }
 
     context->multi = PR_TRUE;
 
@@ -6531,16 +6539,19 @@ NSC_UnwrapKey(CK_SESSION_HANDLE hSession
 
     /* get the session */
     session = sftk_SessionFromHandle(hSession);
     if (session == NULL) {
         sftk_FreeObject(key);
         return CKR_SESSION_HANDLE_INVALID;
     }
 
+    /* mark the key as FIPS if the previous operation was all FIPS */
+    key->isFIPS = session->lastOpWasFIPS;
+
     /*
      * handle the base object stuff
      */
     crv = sftk_handleObject(key, session);
     *phKey = key->handle;
     sftk_FreeSession(session);
     sftk_FreeObject(key);
 
@@ -7001,16 +7012,26 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
                     return CKR_SESSION_HANDLE_INVALID;
                 }
 
                 saltKey = sftk_ObjectFromHandle(params->hSaltKey, session);
                 sftk_FreeSession(session);
                 if (saltKey == NULL) {
                     return CKR_KEY_HANDLE_INVALID;
                 }
+                /* if the base key is not fips, but the salt key is, the
+                 * resulting key can be fips */
+                if (isFIPS && (key->isFIPS == 0) && (saltKey->isFIPS == 1)) {
+                    CK_MECHANISM mech;
+                    mech.mechanism = CKM_HKDF_DERIVE;
+                    mech.pParameter = params;
+                    mech.ulParameterLen = sizeof(*params);
+                    key->isFIPS = sftk_operationIsFIPS(saltKey->slot, &mech,
+                                                       CKA_DERIVE, saltKey);
+                }
                 saltKey_att = sftk_FindAttribute(saltKey, CKA_VALUE);
                 if (saltKey_att == NULL) {
                     sftk_FreeObject(saltKey);
                     return CKR_KEY_HANDLE_INVALID;
                 }
                 /* save the resulting salt */
                 salt = saltKey_att->attrib.pValue;
                 saltLen = saltKey_att->attrib.ulValueLen;
@@ -7246,30 +7267,34 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
     session = sftk_SessionFromHandle(hSession);
     if (session == NULL) {
         sftk_FreeObject(key);
         return CKR_SESSION_HANDLE_INVALID;
     }
 
     sourceKey = sftk_ObjectFromHandle(hBaseKey, session);
     sftk_FreeSession(session);
+    /* is this eventually succeeds, lastOpWasFIPS will be set the resulting key's
+     * FIPS state below. */
+    session->lastOpWasFIPS = PR_FALSE;
     if (sourceKey == NULL) {
         sftk_FreeObject(key);
         return CKR_KEY_HANDLE_INVALID;
     }
 
     if (extractValue) {
         /* get the value of the base key */
         att = sftk_FindAttribute(sourceKey, CKA_VALUE);
         if (att == NULL) {
             sftk_FreeObject(key);
             sftk_FreeObject(sourceKey);
             return CKR_KEY_HANDLE_INVALID;
         }
     }
+    key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_DERIVE, sourceKey);
 
     switch (mechanism) {
         /* get a public key from a private key. nsslowkey_ConvertToPublickey()
          * will generate the public portion if it doesn't already exist. */
         case CKM_NSS_PUB_FROM_PRIV: {
             NSSLOWKEYPrivateKey *privKey;
             NSSLOWKEYPublicKey *pubKey;
             int error;
@@ -8699,16 +8724,17 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
         sessKey->wasDerived = PR_TRUE;
         session = sftk_SessionFromHandle(hSession);
         if (session == NULL) {
             sftk_FreeObject(key);
             return CKR_HOST_MEMORY;
         }
 
         crv = sftk_handleObject(key, session);
+        session->lastOpWasFIPS = key->isFIPS;
         sftk_FreeSession(session);
         *phKey = key->handle;
         sftk_FreeObject(key);
     }
     return crv;
 }
 
 /* NSC_GetFunctionStatus obtains an updated status of a function running
--- a/security/nss/lib/softoken/pkcs11i.h
+++ b/security/nss/lib/softoken/pkcs11i.h
@@ -186,16 +186,17 @@ struct SFTKObjectStr {
     SFTKObject *prev;
     CK_OBJECT_CLASS objclass;
     CK_OBJECT_HANDLE handle;
     int refCount;
     PZLock *refLock;
     SFTKSlot *slot;
     void *objectInfo;
     SFTKFree infoFree;
+    PRBool isFIPS;
 };
 
 struct SFTKTokenObjectStr {
     SFTKObject obj;
     SECItem dbKey;
 };
 
 struct SFTKSessionObjectStr {
@@ -261,16 +262,17 @@ typedef enum {
  *      multi=0 hashInfo=X   *** shouldn't happen ***
  */
 struct SFTKSessionContextStr {
     SFTKContextType type;
     PRBool multi;               /* is multipart */
     PRBool rsa;                 /* is rsa */
     PRBool doPad;               /* use PKCS padding for block ciphers */
     PRBool isXCBC;              /* xcbc, use special handling in final */
+    PRBool isFIPS;              /* current operation is in FIPS mode */
     unsigned int blockSize;     /* blocksize for padding */
     unsigned int padDataLength; /* length of the valid data in padbuf */
     /** latest incomplete block of data for block cipher */
     unsigned char padBuf[SFTK_MAX_BLOCK_SIZE];
     /** result of MAC'ing of latest full block of data with block cipher */
     unsigned char macBuf[SFTK_MAX_BLOCK_SIZE];
     unsigned char k2[SFTK_MAX_BLOCK_SIZE];
     unsigned char k3[SFTK_MAX_BLOCK_SIZE];
@@ -302,16 +304,17 @@ struct SFTKSessionStr {
     CK_SESSION_INFO info;
     CK_NOTIFY notify;
     CK_VOID_PTR appData;
     SFTKSlot *slot;
     SFTKSearchResults *search;
     SFTKSessionContext *enc_context;
     SFTKSessionContext *hash_context;
     SFTKSessionContext *sign_context;
+    PRBool lastOpWasFIPS;
     SFTKObjectList *objects[1];
 };
 
 /*
  * slots (have sessions and objects)
  *
  * The array of sessionLock's protect the session hash table (head[])
  * as well as the reference count of session objects in that bucket
@@ -684,16 +687,17 @@ struct sftk_MACCtxStr {
         void *raw;
     } mac;
 
     void (*destroy_func)(void *ctx, PRBool free_it);
 };
 typedef struct sftk_MACCtxStr sftk_MACCtx;
 
 extern CK_NSS_MODULE_FUNCTIONS sftk_module_funcList;
+extern CK_NSS_FIPS_FUNCTIONS sftk_fips_funcList;
 
 SEC_BEGIN_PROTOS
 
 /* shared functions between pkcs11.c and fipstokn.c */
 extern PRBool nsf_init;
 extern CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS);
 extern CK_RV nsc_CommonFinalize(CK_VOID_PTR pReserved, PRBool isFIPS);
 extern PRBool sftk_ForkReset(CK_VOID_PTR pReserved, CK_RV *crv);
@@ -790,16 +794,17 @@ extern void sftk_update_state(SFTKSlot *
 extern void sftk_update_all_states(SFTKSlot *slot);
 extern void sftk_InitFreeLists(void);
 extern void sftk_CleanupFreeLists(void);
 
 /*
  * Helper functions to handle the session crypto contexts
  */
 extern CK_RV sftk_InitGeneric(SFTKSession *session,
+                              CK_MECHANISM *pMechanism,
                               SFTKSessionContext **contextPtr,
                               SFTKContextType ctype, SFTKObject **keyPtr,
                               CK_OBJECT_HANDLE hKey, CK_KEY_TYPE *keyTypePtr,
                               CK_OBJECT_CLASS pubKeyType,
                               CK_ATTRIBUTE_TYPE operation);
 void sftk_SetContextByType(SFTKSession *session, SFTKContextType type,
                            SFTKSessionContext *context);
 extern CK_RV sftk_GetContext(CK_SESSION_HANDLE handle,
@@ -939,12 +944,17 @@ CK_RV sftk_HKDF(CK_HKDF_PARAMS_PTR param
 char **NSC_ModuleDBFunc(unsigned long function, char *parameters, void *args);
 
 /* dh verify functions */
 /* verify that dhPrime matches one of our known primes, and if so return
  * it's subprime value */
 const SECItem *sftk_VerifyDH_Prime(SECItem *dhPrime);
 /* check if dhSubPrime claims dhPrime is a safe prime. */
 SECStatus sftk_IsSafePrime(SECItem *dhPrime, SECItem *dhSubPrime, PRBool *isSafe);
-
+/* map an operation Attribute to a Mechanism flag */
+CK_FLAGS sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE op);
+/* check the FIPS table to determine if this current operation is allowed by
+ * FIPS security policy */
+PRBool sftk_operationIsFIPS(SFTKSlot *slot, CK_MECHANISM *mech,
+                            CK_ATTRIBUTE_TYPE op, SFTKObject *source);
 SEC_END_PROTOS
 
 #endif /* _PKCS11I_H_ */
--- a/security/nss/lib/softoken/pkcs11u.c
+++ b/security/nss/lib/softoken/pkcs11u.c
@@ -8,16 +8,28 @@
 #include "pkcs11i.h"
 #include "lowkeyi.h"
 #include "secasn1.h"
 #include "blapi.h"
 #include "secerr.h"
 #include "prnetdb.h" /* for PR_ntohl */
 #include "sftkdb.h"
 #include "softoken.h"
+#include "secoid.h"
+
+#if !defined(NSS_FIPS_DISABLED) && defined(NSS_ENABLE_FIPS_INDICATORS)
+/* this file should be supplied by the vendor and include all the
+ * algorithms which have Algorithm certs and have been reviewed by
+ * the lab. A blank file is included for the base so that FIPS mode
+ * will still be compiled and run, but FIPS indicators will always
+ * return PR_FALSE
+ */
+#include "fips_algorithms.h"
+#define NSS_HAS_FIPS_INDICATORS 1
+#endif
 
 /*
  * ******************** Error mapping *******************************
  */
 /*
  * map all the SEC_ERROR_xxx error codes that may be returned by freebl
  * functions to CKR_xxx.  return CKR_DEVICE_ERROR by default for backward
  * compatibility.
@@ -1076,16 +1088,17 @@ sftk_NewObject(SFTKSlot *slot)
         sessObject->attrList[i].attrib.pValue = NULL;
         sessObject->attrList[i].freeData = PR_FALSE;
     }
     sessObject->optimizeSpace = slot->optimizeSpace;
 
     object->handle = 0;
     object->next = object->prev = NULL;
     object->slot = slot;
+    object->isFIPS = sftk_isFIPS(slot->slotID);
 
     object->refCount = 1;
     sessObject->sessionList.next = NULL;
     sessObject->sessionList.prev = NULL;
     sessObject->sessionList.parent = object;
     sessObject->session = NULL;
     sessObject->wasDerived = PR_FALSE;
     if (!hasLocks)
@@ -1629,16 +1642,17 @@ fail:
  */
 CK_RV
 sftk_CopyObject(SFTKObject *destObject, SFTKObject *srcObject)
 {
     SFTKAttribute *attribute;
     SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject);
     unsigned int i;
 
+    destObject->isFIPS = srcObject->isFIPS;
     if (src_so == NULL) {
         return sftk_CopyTokenObject(destObject, srcObject);
     }
 
     PZ_Lock(src_so->attributeLock);
     for (i = 0; i < src_so->hashSize; i++) {
         attribute = src_so->head[i];
         do {
@@ -1866,16 +1880,18 @@ sftk_NewSession(CK_SLOT_ID slotID, CK_NO
 
     session->slot = slot;
     session->notify = notify;
     session->appData = pApplication;
     session->info.flags = flags;
     session->info.slotID = slotID;
     session->info.ulDeviceError = 0;
     sftk_update_state(slot, session);
+    /* no ops completed yet, so the last one couldn't be a FIPS op */
+    session->lastOpWasFIPS = PR_FALSE;
     return session;
 }
 
 /* free all the data associated with a session. */
 void
 sftk_DestroySession(SFTKSession *session)
 {
     SFTKObjectList *op, *next;
@@ -1989,16 +2005,17 @@ sftk_NewTokenObject(SFTKSlot *slot, SECI
     object->handle = handle;
     /* every object must have a class, if we can't get it, the object
      * doesn't exist */
     crv = handleToClass(slot, handle, &object->objclass);
     if (crv != CKR_OK) {
         goto loser;
     }
     object->slot = slot;
+    object->isFIPS = sftk_isFIPS(slot->slotID);
     object->objectInfo = NULL;
     object->infoFree = NULL;
     if (!hasLocks) {
         object->refLock = PZ_NewLock(nssILockRefLock);
     }
     if (object->refLock == NULL) {
         goto loser;
     }
@@ -2117,8 +2134,255 @@ sftk_EncodeInteger(PRUint64 integer, CK_
         }
     } else {
         for (size_t offset = 0; offset < num_bits / 8; offset++) {
             PRUint64 shift = num_bits - (offset + 1) * 8;
             output[offset] = (unsigned char)((integer >> shift) & 0xFF);
         }
     }
 }
+
+CK_FLAGS
+sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE op)
+{
+    CK_FLAGS flags = 0;
+
+    switch (op) {
+        case CKA_ENCRYPT:
+            flags = CKF_ENCRYPT;
+            break;
+        case CKA_DECRYPT:
+            flags = CKF_DECRYPT;
+            break;
+        case CKA_WRAP:
+            flags = CKF_WRAP;
+            break;
+        case CKA_UNWRAP:
+            flags = CKF_UNWRAP;
+            break;
+        case CKA_SIGN:
+            flags = CKF_SIGN;
+            break;
+        case CKA_SIGN_RECOVER:
+            flags = CKF_SIGN_RECOVER;
+            break;
+        case CKA_VERIFY:
+            flags = CKF_VERIFY;
+            break;
+        case CKA_VERIFY_RECOVER:
+            flags = CKF_VERIFY_RECOVER;
+            break;
+        case CKA_DERIVE:
+            flags = CKF_DERIVE;
+            break;
+        /* fake attribute to select digesting */
+        case CKA_DIGEST:
+            flags = CKF_DIGEST;
+            break;
+        case CKA_NSS_MESSAGE | CKA_ENCRYPT:
+            flags = CKF_MESSAGE_ENCRYPT;
+            break;
+        case CKA_NSS_MESSAGE | CKA_DECRYPT:
+            flags = CKF_MESSAGE_DECRYPT;
+            break;
+        case CKA_NSS_MESSAGE | CKA_SIGN:
+            flags = CKF_MESSAGE_SIGN;
+            break;
+        case CKA_NSS_MESSAGE | CKA_VERIFY:
+            flags = CKF_MESSAGE_VERIFY;
+            break;
+        default:
+            break;
+    }
+    return flags;
+}
+
+#ifdef NSS_HAS_FIPS_INDICATORS
+/* sigh, we probably need a version of this in secutil so that both
+ * softoken and NSS can use it */
+static SECOidTag
+sftk_quickGetECCCurveOid(SFTKObject *source)
+{
+    SFTKAttribute *attribute = sftk_FindAttribute(source, CKA_EC_PARAMS);
+    unsigned char *encoded;
+    int len;
+    SECItem oid;
+    SECOidTag tag;
+
+    if (attribute == NULL) {
+        return SEC_OID_UNKNOWN;
+    }
+    encoded = attribute->attrib.pValue;
+    len = attribute->attrib.ulValueLen;
+    if ((len < 2) || (encoded[0] != SEC_ASN1_OBJECT_ID) ||
+        (len != encoded[1] + 2)) {
+        sftk_FreeAttribute(attribute);
+        return SEC_OID_UNKNOWN;
+    }
+    oid.data = encoded + 2;
+    oid.len = len - 2;
+    tag = SECOID_FindOIDTag(&oid);
+    sftk_FreeAttribute(attribute);
+    return tag;
+}
+
+/* This function currently only returns valid lengths for
+ * FIPS approved ECC curves. If we want to make this generic
+ * in the future, that Curve determination can be done in
+ * the sftk_handleSpecial. Since it's currently only used
+ * in FIPS indicators, it's currently only compiled with
+ * the FIPS indicator code */
+static int
+sftk_getKeyLength(SFTKObject *source)
+{
+    CK_KEY_TYPE keyType = CK_INVALID_HANDLE;
+    CK_ATTRIBUTE_TYPE keyAttribute;
+    CK_ULONG keyLength = 0;
+    SFTKAttribute *attribute;
+    CK_RV crv;
+
+    /* If we don't have a key, then it doesn't have a length.
+     * this may be OK (say we are hashing). The mech info will
+     * sort this out because algorithms which expect no keys
+     * will accept zero length for the keys */
+    if (source == NULL) {
+        return 0;
+    }
+
+    crv = sftk_GetULongAttribute(source, CKA_KEY_TYPE, &keyType);
+    if (crv != CKR_OK) {
+        /* sometimes we're passed a data object, in that case the
+         * key length is CKA_VALUE, which is the default */
+        keyType = CKK_INVALID_KEY_TYPE;
+    }
+    if (keyType == CKK_EC) {
+        SECOidTag curve = sftk_quickGetECCCurveOid(source);
+        switch (curve) {
+            case SEC_OID_CURVE25519:
+                /* change when we start algorithm testing on curve25519 */
+                return 0;
+            case SEC_OID_SECG_EC_SECP256R1:
+                return 256;
+            case SEC_OID_SECG_EC_SECP384R1:
+                return 384;
+            case SEC_OID_SECG_EC_SECP521R1:
+                /* this is a lie, but it makes the table easier. We don't
+                 * have to have a double entry for every ECC mechanism */
+                return 512;
+            default:
+                break;
+        }
+        /* other curves aren't NIST approved, returning 0 will cause these
+         * curves to fail FIPS length criteria */
+        return 0;
+    }
+
+    switch (keyType) {
+        case CKK_RSA:
+            keyAttribute = CKA_MODULUS;
+            break;
+        case CKK_DSA:
+        case CKK_DH:
+            keyAttribute = CKA_PRIME;
+            break;
+        default:
+            keyAttribute = CKA_VALUE;
+            break;
+    }
+    attribute = sftk_FindAttribute(source, keyAttribute);
+    if (attribute) {
+        keyLength = attribute->attrib.ulValueLen * 8;
+        sftk_FreeAttribute(attribute);
+    }
+    return keyLength;
+}
+
+/*
+ * handle specialized FIPS semantics that are too complicated to
+ * handle with just a table. NOTE: this means any additional semantics
+ * would have to be coded here before they can be added to the table */
+static PRBool
+sftk_handleSpecial(SFTKSlot *slot, CK_MECHANISM *mech,
+                   SFTKFIPSAlgorithmList *mechInfo, SFTKObject *source)
+{
+    switch (mechInfo->special) {
+        case SFTKFIPSDH: {
+            SECItem dhPrime;
+            const SECItem *dhSubPrime;
+            CK_RV crv = sftk_Attribute2SecItem(NULL, &dhPrime,
+                                               source, CKA_PRIME);
+            if (crv != CKR_OK) {
+                return PR_FALSE;
+            }
+            dhSubPrime = sftk_VerifyDH_Prime(&dhPrime);
+            SECITEM_ZfreeItem(&dhPrime, PR_FALSE);
+            return (dhSubPrime) ? PR_TRUE : PR_FALSE;
+        }
+        case SFTKFIPSNone:
+            return PR_FALSE;
+        case SFTKFIPSECC:
+            /* we've already handled the curve selection in the 'getlength'
+          * function */
+            return PR_TRUE;
+        case SFTKFIPSAEAD: {
+            if (mech->ulParameterLen == 0) {
+                /* AEAD ciphers are only in FIPS mode if we are using the
+                 * MESSAGE interface. This takes an empty parameter
+                 * in the init function */
+                return PR_TRUE;
+            }
+            return PR_FALSE;
+        }
+        default:
+            break;
+    }
+    /* if we didn't understand the special processing, mark it non-fips */
+    return PR_FALSE;
+}
+#endif
+
+PRBool
+sftk_operationIsFIPS(SFTKSlot *slot, CK_MECHANISM *mech, CK_ATTRIBUTE_TYPE op,
+                     SFTKObject *source)
+{
+#ifndef NSS_HAS_FIPS_INDICATORS
+    return PR_FALSE;
+#else
+    int i;
+    CK_FLAGS opFlags;
+    CK_ULONG keyLength;
+
+    /* handle all the quick stuff first */
+    if (!sftk_isFIPS(slot->slotID)) {
+        return PR_FALSE;
+    }
+    if (source && !source->isFIPS) {
+        return PR_FALSE;
+    }
+    if (mech == NULL) {
+        return PR_FALSE;
+    }
+
+    /* now get the calculated values */
+    opFlags = sftk_AttributeToFlags(op);
+    if (opFlags == 0) {
+        return PR_FALSE;
+    }
+    keyLength = sftk_getKeyLength(source);
+
+    /* check against our algorithm array */
+    for (i = 0; i < SFTK_NUMBER_FIPS_ALGORITHMS; i++) {
+        SFTKFIPSAlgorithmList *mechs = &sftk_fips_mechs[i];
+        /* if we match the number of records exactly, then we are an
+         * approved algorithm in the approved mode with an approved key */
+        if (((mech->mechanism == mechs->type) &&
+             (opFlags == (mechs->info.flags & opFlags)) &&
+             (keyLength <= mechs->info.ulMaxKeySize) &&
+             (keyLength >= mechs->info.ulMinKeySize) &&
+             ((keyLength - mechs->info.ulMinKeySize) % mechs->step) == 0) &&
+            ((mechs->special == SFTKFIPSNone) ||
+             sftk_handleSpecial(slot, mech, mechs, source))) {
+            return PR_TRUE;
+        }
+    }
+    return PR_FALSE;
+#endif
+}
--- a/security/nss/lib/softoken/sftkmessage.c
+++ b/security/nss/lib/softoken/sftkmessage.c
@@ -67,18 +67,18 @@ sftk_MessageCryptInit(CK_SESSION_HANDLE 
                                    CKA_NSS_MESSAGE | operation);
     if (crv != CKR_OK)
         return crv;
 
     session = sftk_SessionFromHandle(hSession);
     if (session == NULL)
         return CKR_SESSION_HANDLE_INVALID;
 
-    crv = sftk_InitGeneric(session, &context, contextType, &key, hKey,
-                           &key_type, CKO_SECRET_KEY, operation);
+    crv = sftk_InitGeneric(session, pMechanism, &context, contextType, &key,
+                           hKey, &key_type, CKO_SECRET_KEY, operation);
     if (crv != CKR_OK) {
         sftk_FreeSession(session);
         return crv;
     }
 
     att = sftk_FindAttribute(key, CKA_VALUE);
     if (att == NULL) {
         sftk_FreeSession(session);
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -13871,16 +13871,51 @@ ssl3_DestroySSL3Info(sslSocket *ss)
     tls13_DestroyPskList(&ss->ssl3.hs.psks);
 
     /* TLS 1.3 ECH state. */
     PK11_HPKE_DestroyContext(ss->ssl3.hs.echHpkeCtx, PR_TRUE);
     PORT_Free((void *)ss->ssl3.hs.echPublicName); /* CONST */
     sslBuffer_Clear(&ss->ssl3.hs.greaseEchBuf);
 }
 
+/* check if the current cipher spec is FIPS. We only need to
+ * check the contexts here, if the kea, prf or keys were not FIPS,
+ * that status would have been rolled up in the create context
+ * call */
+static PRBool
+ssl_cipherSpecIsFips(ssl3CipherSpec *spec)
+{
+    if (!spec || !spec->cipherDef) {
+        return PR_FALSE;
+    }
+
+    if (spec->cipherDef->type != type_aead) {
+        if (spec->keyMaterial.macContext == NULL) {
+            return PR_FALSE;
+        }
+        if (!PK11_ContextGetFIPSStatus(spec->keyMaterial.macContext)) {
+            return PR_FALSE;
+        }
+    }
+    if (!spec->cipherContext) {
+        return PR_FALSE;
+    }
+    return PK11_ContextGetFIPSStatus(spec->cipherContext);
+}
+
+/* return true if the current operation is running in FIPS mode */
+PRBool
+ssl_isFIPS(sslSocket *ss)
+{
+    if (!ssl_cipherSpecIsFips(ss->ssl3.crSpec)) {
+        return PR_FALSE;
+    }
+    return ssl_cipherSpecIsFips(ss->ssl3.cwSpec);
+}
+
 /*
  * parse the policy value for a single algorithm in a cipher_suite,
  *   return TRUE if we disallow by the cipher suite by policy
  *   (we don't have to parse any more algorithm policies on this cipher suite),
  *  otherwise return FALSE.
  *   1. If we don't have the required policy, disable by default, disallow by
  *      policy and return TRUE (no more processing needed).
  *   2. If we have the required policy, and we are disabled, return FALSE,
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -1842,16 +1842,19 @@ PRBool ssl_IsResumptionTokenUsable(sslSo
 /* unwrap helper function to handle the case where the wrapKey doesn't wind
  *  * up in the correct token for the master secret */
 PK11SymKey *ssl_unwrapSymKey(PK11SymKey *wrapKey,
                              CK_MECHANISM_TYPE wrapType, SECItem *param,
                              SECItem *wrappedKey,
                              CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation,
                              int keySize, CK_FLAGS keyFlags, void *pinArg);
 
+/* determine if the current ssl connection is operating in FIPS mode */
+PRBool ssl_isFIPS(sslSocket *ss);
+
 /* Experimental APIs. Remove when stable. */
 
 SECStatus SSLExp_SetResumptionTokenCallback(PRFileDesc *fd,
                                             SSLResumptionTokenCallback cb,
                                             void *ctx);
 SECStatus SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token,
                                     unsigned int len);
 
--- a/security/nss/lib/ssl/sslinfo.c
+++ b/security/nss/lib/ssl/sslinfo.c
@@ -105,16 +105,17 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLCh
 
             inf.earlyDataAccepted =
                 (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted ||
                  ss->ssl3.hs.zeroRttState == ssl_0rtt_done);
             sidLen = sid->u.ssl3.sessionIDLength;
             sidLen = PR_MIN(sidLen, sizeof inf.sessionID);
             inf.sessionIDLength = sidLen;
             memcpy(inf.sessionID, sid->u.ssl3.sessionID, sidLen);
+            inf.isFIPS = ssl_isFIPS(ss);
         }
     }
 
     memcpy(info, &inf, inf.length);
 
     return SECSuccess;
 }
 
--- a/security/nss/lib/ssl/sslt.h
+++ b/security/nss/lib/ssl/sslt.h
@@ -368,16 +368,21 @@ typedef struct SSLChannelInfoStr {
     /* Indicates what type of PSK, if any, was used in a handshake. */
     SSLPskType pskType;
 
     /* The following fields were added in NSS 3.60 */
     /* This field is PR_TRUE when the connection is established
      * with TLS 1.3 Encrypted Client Hello. */
     PRBool echAccepted;
 
+    /* The following field was added in NSS 3.66 */
+    /* This filed is PR_TRUE if the FIPS indicator is true for the
+     * current connection */
+    PRBool isFIPS;
+
     /* When adding new fields to this structure, please document the
      * NSS version in which they were added. */
 } SSLChannelInfo;
 
 /* Preliminary channel info */
 #define ssl_preinfo_version (1U << 0)
 #define ssl_preinfo_cipher_suite (1U << 1)
 #define ssl_preinfo_0rtt_cipher_suite (1U << 2)
--- a/security/nss/lib/util/pkcs11n.h
+++ b/security/nss/lib/util/pkcs11n.h
@@ -264,16 +264,26 @@
 #define CKM_NSS_PBE_SHA1_128_BIT_RC4 0x80000007UL
 #define CKM_NSS_PBE_SHA1_FAULTY_3DES_CBC 0x80000008UL
 #define CKM_NSS_PBE_SHA1_HMAC_KEY_GEN 0x80000009UL
 #define CKM_NSS_PBE_MD5_HMAC_KEY_GEN 0x8000000aUL
 #define CKM_NSS_PBE_MD2_HMAC_KEY_GEN 0x8000000bUL
 
 #define CKM_TLS_PRF_GENERAL 0x80000373UL
 
+/* FIPS Indicator defines */
+#define CKS_NSS_UNINITIALIZED 0xffffffffUL
+#define CKS_NSS_FIPS_NOT_OK 0UL
+#define CKS_NSS_FIPS_OK 1UL
+
+#define CKT_NSS_SESSION_CHECK 1UL
+#define CKT_NSS_OBJECT_CHECK 2UL
+#define CKT_NSS_BOTH_CHECK 3UL
+#define CKT_NSS_SESSION_LAST_CHECK 4UL
+
 typedef struct CK_NSS_JPAKEPublicValue {
     CK_BYTE *pGX;
     CK_ULONG ulGXLen;
     CK_BYTE *pGV;
     CK_ULONG ulGVLen;
     CK_BYTE *pR;
     CK_ULONG ulRLen;
 } CK_NSS_JPAKEPublicValue;
@@ -584,16 +594,28 @@ typedef char **(PR_CALLBACK *SECMODModul
  * "Vendor NSS Module Interface" */
 typedef char **(*CK_NSS_ModuleDBFunc)(unsigned long function,
                                       char *parameters, void *args);
 typedef struct CK_NSS_MODULE_FUNCTIONS {
     CK_VERSION version;
     CK_NSS_ModuleDBFunc NSC_ModuleDBFunc;
 } CK_NSS_MODULE_FUNCTIONS;
 
+/* FIPS Indicator Interface. This may move to the normal PKCS #11 table
+ * in the future. For now it's called "Vendor NSS FIPS Interface" */
+typedef CK_RV (*CK_NSS_GetFIPSStatus)(CK_SESSION_HANDLE hSession,
+                                      CK_OBJECT_HANDLE hObject,
+                                      CK_ULONG ulOperationType,
+                                      CK_ULONG *pulFIPSStatus);
+
+typedef struct CK_NSS_FIPS_FUNCTIONS {
+    CK_VERSION version;
+    CK_NSS_GetFIPSStatus NSC_NSSGetFIPSStatus;
+} CK_NSS_FIPS_FUNCTIONS;
+
 /* There was an inconsistency between the spec and the header file in defining
  * the CK_GCM_PARAMS structure. The authoritative reference is the header file,
  * but NSS used the spec when adding it to its own header. In V3 we've
  * corrected it, but we need to handle the old case for devices that followed
  * us in using the incorrect specification. */
 typedef struct CK_NSS_GCM_PARAMS {
     CK_BYTE_PTR pIv;
     CK_ULONG ulIvLen;
@@ -608,17 +630,17 @@ typedef CK_NSS_GCM_PARAMS CK_PTR CK_NSS_
 #ifdef NSS_PKCS11_2_0_COMPAT
 
 /* defines that were changed between NSS's PKCS #11 and the Oasis headers */
 #define CKF_EC_FP CKF_EC_F_P
 #define CKO_KG_PARAMETERS CKO_DOMAIN_PARAMETERS
 #define CK_INVALID_SESSION CK_INVALID_HANDLE
 #define CKR_KEY_PARAMS_INVALID 0x0000006B
 
-/* use the old wrong CK_GCM_PARAMS is NSS_PCKS11_2_0_COMPAT is defined */
+/* use the old wrong CK_GCM_PARAMS if NSS_PCKS11_2_0_COMPAT is defined */
 typedef struct CK_NSS_GCM_PARAMS CK_GCM_PARAMS;
 typedef CK_NSS_GCM_PARAMS CK_PTR CK_GCM_PARAMS_PTR;
 
 /* don't leave old programs in a lurch just yet, give them the old NETSCAPE
  * synonym if NSS_PKCS11_2_0_COMPAT is defined*/
 #define CKO_NETSCAPE_CRL CKO_NSS_CRL
 #define CKO_NETSCAPE_SMIME CKO_NSS_SMIME
 #define CKO_NETSCAPE_TRUST CKO_NSS_TRUST
--- a/security/nss/tests/ssl/ssl.sh
+++ b/security/nss/tests/ssl/ssl.sh
@@ -110,19 +110,30 @@ ssl_init()
   NORM_EXT=""
 
   EC_SUITES=":C001:C002:C003:C004:C005:C006:C007:C008:C009:C00A:C00B:C00C:C00D"
   EC_SUITES="${EC_SUITES}:C00E:C00F:C010:C011:C012:C013:C014:C023:C024:C027"
   EC_SUITES="${EC_SUITES}:C028:C02B:C02C:C02F:C030:CCA8:CCA9:CCAA"
 
   NON_EC_SUITES=":0016:0032:0033:0038:0039:003B:003C:003D:0040:0041:0067:006A:006B"
   NON_EC_SUITES="${NON_EC_SUITES}:0084:009C:009D:009E:009F:00A2:00A3:CCAAcdeinvyz"
+  TLS13_SUITES=":1301:1302:1303"
 
   # List of cipher suites to test, including ECC cipher suites.
   CIPHER_SUITES="-c ${EC_SUITES}${NON_EC_SUITES}"
+  TLS13_CIPHER_SUITES="-c ${TLS13_SUITES}${EC_SUITES}${NON_EC_SUITES}"
+
+  # in fips mode, turn off curve25519 until it's NIST approved
+  FIPS_OPTIONS="-I P256,P384,P521,FF2048,FF3072,FF4096,FF6144,FF8192"
+
+  # in non-fips mode, tstclnt may run without the db password in some
+  # cases, but in fips mode it's always needed
+  CLIENT_PW=""
+  CLIENT_PW_FIPS="-w nss"
+  CLIENT_PW_NORMAL=""
 
   if [ "${OS_ARCH}" != "WINNT" ]; then
       ulimit -n 1000 # make sure we have enough file descriptors
   fi
 
   cd ${CLIENTDIR}
 }
 
@@ -287,27 +298,40 @@ ignore_blank_lines()
   LC_ALL=C egrep -v '^[[:space:]]*(#|$)' "$1"
 }
 
 ############################## ssl_cov #################################
 # local shell function to perform SSL Cipher Coverage tests
 ########################################################################
 ssl_cov()
 {
-  #verbose="-v"
+  verbose_save=${verbose}
+  verbose="-v"
   html_head "SSL Cipher Coverage $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE"
 
   testname=""
 
+  SAVE_SERVER_OPTIONS=${SERVER_OPTIONS}
+  if [ "${SERVER_MODE}" = "fips" ] ; then
+      SERVER_OPTIONS="${SERVER_OPTIONS} ${FIPS_OPTIONS}"
+  fi
+  SAVE_CLIENT_OPTIONS=${CLIENT_OPTIONS}
+  if [ "${CLIENT_MODE}" = "fips" ] ; then
+      CLIENT_OPTIONS="${CLIENT_OPTIONS} ${FIPS_OPTIONS}"
+  fi
+
   start_selfserv $CIPHER_SUITES # Launch the server
 
   VMIN="ssl3"
   VMAX="tls1.1"
-
-  ignore_blank_lines ${SSLCOV} | \
+  # can't use a pipe here, because we may have to restart selfserv, and
+  # doing so hides the server pid environment variable in the subshell in
+  # cygwin, which means we can't kill selfserv at the end here.
+  SSL_COV_TMP=$(mktemp /tmp/ssl_cov.XXXXXX)
+  ignore_blank_lines ${SSLCOV} > ${SSL_COV_TMP}
   while read ectype testmax param testname
   do
       echo "${testname}" | grep "EXPORT" > /dev/null
       EXP=$?
 
       # RSA-PSS tests are handled in a separate function
       case $testname in
         *RSA-PSS)
@@ -321,31 +345,60 @@ ssl_cov()
           VMAX="tls1.0"
       fi
       if [ "$testmax" = "TLS11" ]; then
           VMAX="tls1.1"
       fi
       if [ "$testmax" = "TLS12" ]; then
           VMAX="tls1.2"
       fi
+      if [ "$testmax" = "TLS13" ]; then
+          # if our selfserv can only do up to tls1.2
+          # restart it so it can do tls1.3, This requires
+          # moving VMIN up to tls1.0 because you can't enable SSL3 and
+          # TLS 1.3.
+          if [ "$VMIN" = "ssl3" ]; then
+              SERVER_VMIN="tls1.0"
+              SERVER_VMAX="tls1.3"
+              kill_selfserv
+              start_selfserv ${TLS13_CIPHER_SUITES}
+              unset SERVER_VMIN
+              unset SERVER_VMAX
+              VMIN="tls1.0"
+          fi
+          VMAX="tls1.3"
+      fi
+      # if we are testing ssl3 and our server can only do down to tls1.1,
+      # restart it to enable ssl3
+      if [ "$VMAX" = "ssl3" -a "$VMIN" = "tls1.1" ]; then
+              kill_selfserv
+              start_selfserv $CIPHER_SUITES
+              VMIN="ssl3"
+      fi
+
+
 
       echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} \\"
       echo "        -f -d ${P_R_CLIENTDIR} $verbose -w nss < ${REQUEST_FILE}"
 
       rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
       ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} -f \
               -d ${P_R_CLIENTDIR} $verbose -w nss < ${REQUEST_FILE} \
               >${TMP}/$HOST.tmp.$$  2>&1
       ret=$?
       cat ${TMP}/$HOST.tmp.$$
       rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
       html_msg $ret 0 "${testname}" \
                "produced a returncode of $ret, expected is 0"
-  done
+  done < ${SSL_COV_TMP}
+  rm -f ${SSL_COV_TMP}
 
+  SERVER_OPTIONS=${SAVE_SERVER_OPTIONS}
+  CLIENT_OPTIONS=${SAVE_CLIENT_OPTIONS}
+  verbose=${verbose_save}
   kill_selfserv
   html "</TABLE><BR>"
 }
 
 ssl_cov_rsa_pss()
 {
   #verbose="-v"
   html_head "SSL Cipher Coverage (RSA-PSS) $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE"
@@ -464,36 +517,32 @@ ssl_stapling_sub()
 
     if [ "$NORM_EXT" = "Extended Test" ] ; then
         # these tests use the ext_client directory for tstclnt,
         # which doesn't contain the required "TestCA" for server cert
         # verification, I don't know if it would be OK to add it...
         echo "$SCRIPTNAME: skipping  $testname for $NORM_EXT"
         return 0
     fi
-    if [ "$SERVER_MODE" = "fips" -o "$CLIENT_MODE" = "fips" ] ; then
-          echo "$SCRIPTNAME: skipping  $testname (non-FIPS only)"
-        return 0
-    fi
 
     SAVE_SERVER_OPTIONS=${SERVER_OPTIONS}
     SERVER_OPTIONS="${SERVER_OPTIONS} ${SO}"
 
     SAVE_P_R_SERVERDIR=${P_R_SERVERDIR}
     P_R_SERVERDIR=${P_R_SERVERDIR}/../stapling/
 
     echo "${testname}"
 
     start_selfserv
 
     echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f -d ${P_R_CLIENTDIR} $verbose ${CLIENT_OPTIONS} \\"
-    echo "        -c v -T -O -F -M 1 -V ssl3:tls1.2 < ${REQUEST_FILE}"
+    echo "        -c v -T -O -F -M 1 -V ssl3:tls1.2 ${CLIENT_PW} < ${REQUEST_FILE}"
     rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
     ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${CLIENT_OPTIONS} \
-            -d ${P_R_CLIENTDIR} $verbose -c v -T -O -F -M 1 -V ssl3:tls1.2 < ${REQUEST_FILE} \
+            -d ${P_R_CLIENTDIR} $verbose -c v -T -O -F -M 1 -V ssl3:tls1.2 ${CLIENT_PW} < ${REQUEST_FILE} \
             >${TMP}/$HOST.tmp.$$  2>&1
     ret=$?
     cat ${TMP}/$HOST.tmp.$$
     rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
 
     # hopefully no workaround for bug #402058 needed here?
     # (see commands in ssl_auth
 
@@ -513,20 +562,16 @@ ssl_stapling_stress()
 
     if [ "$NORM_EXT" = "Extended Test" ] ; then
         # these tests use the ext_client directory for tstclnt,
         # which doesn't contain the required "TestCA" for server cert
         # verification, I don't know if it would be OK to add it...
         echo "$SCRIPTNAME: skipping  $testname for $NORM_EXT"
         return 0
     fi
-    if [ "$SERVER_MODE" = "fips" -o "$CLIENT_MODE" = "fips" ] ; then
-          echo "$SCRIPTNAME: skipping  $testname (non-FIPS only)"
-        return 0
-    fi
 
     SAVE_SERVER_OPTIONS=${SERVER_OPTIONS}
     SERVER_OPTIONS="${SERVER_OPTIONS} ${SO}"
 
     SAVE_P_R_SERVERDIR=${P_R_SERVERDIR}
     P_R_SERVERDIR=${P_R_SERVERDIR}/../stapling/
 
     echo "${testname}"
@@ -587,32 +632,27 @@ ssl_stapling()
 ssl_signed_cert_timestamps()
 {
   #verbose="-v"
   html_head "SSL Signed Certificate Timestamps $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE"
 
     testname="ssl_signed_cert_timestamps"
     value=0
 
-    if [ "$SERVER_MODE" = "fips" -o "$CLIENT_MODE" = "fips" ] ; then
-          echo "$SCRIPTNAME: skipping  $testname (non-FIPS only)"
-        return 0
-    fi
-
     echo "${testname}"
 
     start_selfserv
 
     # Since we don't have server-side support, this test only covers advertising the
     # extension in the client hello.
     echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f -d ${P_R_CLIENTDIR} $verbose ${CLIENT_OPTIONS} \\"
-    echo "        -U -V tls1.0:tls1.2 < ${REQUEST_FILE}"
+    echo "        -U -V tls1.0:tls1.2 ${CLIENT_PW} < ${REQUEST_FILE}"
     rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
     ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${CLIENT_OPTIONS} \
-            -d ${P_R_CLIENTDIR} $verbose -U -V tls1.0:tls1.2 < ${REQUEST_FILE} \
+            -d ${P_R_CLIENTDIR} $verbose -U -V tls1.0:tls1.2 ${CLIENT_PW} < ${REQUEST_FILE} \
             >${TMP}/$HOST.tmp.$$  2>&1
     ret=$?
     cat ${TMP}/$HOST.tmp.$$
     rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
 
     html_msg $ret $value "${testname}" \
             "produced a returncode of $ret, expected is $value"
     kill_selfserv
@@ -647,17 +687,17 @@ ssl_stress()
           if [ "$ectype" = "SNI" ]; then
               cparam=`echo $cparam | sed -e "s/Host/$HOST/g" -e "s/Dom/$DOMSUF/g" `
               sparam=`echo $sparam | sed -e "s/Host/$HOST/g" -e "s/Dom/$DOMSUF/g" `
           fi
 
           start_selfserv `echo "$sparam" | sed -e 's,_, ,g'`
 
           if [ "`uname -n`" = "sjsu" ] ; then
-              echo "debugging disapering selfserv... ps -ef | grep selfserv"
+              echo "debugging disappearing selfserv... ps -ef | grep selfserv"
               ps -ef | grep selfserv
           fi
 
           if [ "${NOLOGIN}" -eq 0 ] ; then
               dbdir=${P_R_NOLOGINDIR}
           else
               dbdir=${P_R_CLIENTDIR}
           fi
@@ -1270,71 +1310,61 @@ ssl_crl_cache()
 ssl_dtls()
 {
   #verbose="-v"
   html_head "SSL DTLS $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE"
 
     testname="ssl_dtls"
     value=0
 
-    if [ "$SERVER_MODE" = "fips" -o "$CLIENT_MODE" = "fips" ] ; then
-        echo "$SCRIPTNAME: skipping  $testname (non-FIPS only)"
-        return 0
-    fi
-
     echo "${testname}"
 
-    echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f -d ${P_R_SERVERDIR} $verbose ${SERVER_OPTIONS} \\"
-    echo "        -U -V tls1.1:tls1.2 -P server -Q < ${REQUEST_FILE} &"
+    echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${SERVER_OPTIONS} \\"
+    echo "        -d ${P_R_SERVERDIR} $verbose -U -V tls1.1:tls1.2 -P server -n ${HOSTADDR} -w nss < ${REQUEST_FILE} &"
 
-    ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${SERVER_OPTIONS} \
-                -d ${P_R_SERVERDIR} $verbose -U -V tls1.1:tls1.2 -P server -n ${HOSTADDR} -w nss < ${REQUEST_FILE} 2>&1 &
+    (sleep 2; cat ${REQUEST_FILE}) | ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${SERVER_OPTIONS} \
+                -d ${P_R_SERVERDIR} $verbose -U -V tls1.1:tls1.2 -P server -n ${HOSTADDR} -w nss 2>&1 &
 
     PID=$!
 
     sleep 1
 
-    echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f -d ${P_R_CLIENTDIR} $verbose ${CLIENT_OPTIONS} \\"
-    echo "        -U -V tls1.1:tls1.2 -P client -Q < ${REQUEST_FILE}"
+    echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${CLIENT_OPTIONS} \\"
+    echo "        -d ${P_R_CLIENTDIR} $verbose -U -V tls1.1:tls1.2 -P client -Q ${CLIENT_PW} < ${REQUEST_FILE}"
     ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${CLIENT_OPTIONS} \
-            -d ${P_R_CLIENTDIR} $verbose -U -V tls1.1:tls1.2 -P client -Q < ${REQUEST_FILE} 2>&1
+            -d ${P_R_CLIENTDIR} $verbose -U -V tls1.1:tls1.2 -P client -Q ${CLIENT_PW} < ${REQUEST_FILE} 2>&1
     ret=$?
     html_msg $ret $value "${testname}" \
              "produced a returncode of $ret, expected is $value"
 
     kill ${PID}
 
   html "</TABLE><BR>"
 }
 
 ############################ ssl_scheme ###################################
 # local shell function to test tstclnt and selfserv handling of signature schemes
 #########################################################################
 ssl_scheme()
 {
-    if [ "$SERVER_MODE" = "fips" -o "$CLIENT_MODE" = "fips" ] ; then
-        echo "$SCRIPTNAME: skipping  $testname (non-FIPS only)"
-        return 0
-    fi
-
     html_head "SSL SCHEME $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE"
 
     NO_ECC_CERTS=1
     schemes=("rsa_pkcs1_sha256" "rsa_pss_rsae_sha256" "rsa_pkcs1_sha256,rsa_pss_rsae_sha256")
     for sscheme in "${schemes[@]}"; do
         for cscheme in "${schemes[@]}"; do
             testname="ssl_scheme server='$sscheme' client='$cscheme'"
             echo "${testname}"
 
             start_selfserv -V tls1.2:tls1.2 -J "$sscheme"
 
             echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f -d ${P_R_CLIENTDIR} $verbose ${CLIENT_OPTIONS} \\"
-            echo "        -V tls1.2:tls1.2 -J "$cscheme" < ${REQUEST_FILE}"
+            echo "        -V tls1.2:tls1.2 -J "$cscheme" ${CLIENT_PW} < ${REQUEST_FILE}"
             ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${CLIENT_OPTIONS} \
-                        -d ${P_R_CLIENTDIR} $verbose -V tls1.2:tls1.2 -J "$cscheme" < ${REQUEST_FILE} 2>&1
+                        -d ${P_R_CLIENTDIR} $verbose -V tls1.2:tls1.2 -J "$cscheme" ${CLIENT_PW} < ${REQUEST_FILE} 2>&1
             ret=$?
             # If both schemes include just one option and those options don't
             # match, then the test should fail; otherwise, assume that it works.
             if [ "${cscheme#*,}" = "$cscheme" -a \
                  "${sscheme#*,}" = "$sscheme" -a \
                  "$cscheme" != "$sscheme" ]; then
                 expected=254
             else
@@ -1350,36 +1380,31 @@ ssl_scheme()
     html "</TABLE><BR>"
 }
 
 ############################ ssl_scheme_stress ##########################
 # local shell function to test strsclnt and selfserv handling of signature schemes
 #########################################################################
 ssl_scheme_stress()
 {
-    if [ "$SERVER_MODE" = "fips" -o "$CLIENT_MODE" = "fips" ] ; then
-        echo "$SCRIPTNAME: skipping  $testname (non-FIPS only)"
-        return 0
-    fi
-
     html_head "SSL SCHEME $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE"
 
     NO_ECC_CERTS=1
     schemes=("rsa_pkcs1_sha256" "rsa_pss_rsae_sha256" "rsa_pkcs1_sha256,rsa_pss_rsae_sha256")
     for sscheme in "${schemes[@]}"; do
         for cscheme in "${schemes[@]}"; do
             testname="ssl_scheme server='$sscheme' client='$cscheme'"
             echo "${testname}"
 
             start_selfserv -V tls1.2:tls1.2 -J "$sscheme"
 
             echo "strsclnt -4 -q -p ${PORT} -d ${P_R_CLIENTDIR} $verbose ${CLIENT_OPTIONS} \\"
-            echo "         -V tls1.2:tls1.2 -J "$cscheme" ${HOSTADDR} < ${REQUEST_FILE}"
+            echo "         -V tls1.2:tls1.2 -J "$cscheme" ${HOSTADDR} ${CLIENT_PW} < ${REQUEST_FILE}"
             ${PROFTOOL} ${BINDIR}/strsclnt -4 -q -p ${PORT} ${CLIENT_OPTIONS} \
-                        -d ${P_R_CLIENTDIR} $verbose -V tls1.2:tls1.2 -J "$cscheme" ${HOSTADDR} < ${REQUEST_FILE} 2>&1
+                        -d ${P_R_CLIENTDIR} $verbose -V tls1.2:tls1.2 -J "$cscheme" ${HOSTADDR} ${CLIENT_PW} < ${REQUEST_FILE} 2>&1
             ret=$?
             # If both schemes include just one option and those options don't
             # match, then the test should fail; otherwise, assume that it works.
             if [ "${cscheme#*,}" = "$cscheme" -a \
                  "${sscheme#*,}" = "$sscheme" -a \
                  "$cscheme" != "$sscheme" ]; then
                 expected=1
             else
@@ -1406,19 +1431,19 @@ ssl_exporter()
     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}"
+        echo "        -V tls1.2:tls1.2 -x $exporter ${CLIENT_PW} < ${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
+                    -d ${P_R_CLIENTDIR} $verbose -V tls1.2:tls1.2 -x "$exporter" ${CLIENT_PW} < ${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}
@@ -1624,19 +1649,21 @@ ssl_run_tests()
                 html_failed "${SCRIPTNAME}: Error: Unknown server mode ${SERVER_MODE}"
                 return 1
                 ;;
             esac
 
             case "${CLIENT_MODE}" in
             "normal")
                 CLIENT_OPTIONS=
+                CLIENT_PW=${CLIENT_PW_NORMAL}
                 ;;
             "fips")
-                SERVER_OPTIONS=
+                CLIENT_OPTIONS=
+                CLIENT_PW=${CLIENT_PW_FIPS}
                 ssl_set_fips client on
                 ;;
             *)
                 html_failed "${SCRIPTNAME}: Error: Unknown client mode ${CLIENT_MODE}"
                 return 1
                 ;;
             esac
 
--- a/security/nss/tests/ssl/sslcov.txt
+++ b/security/nss/tests/ssl/sslcov.txt
@@ -61,16 +61,19 @@
   noECC  TLS12 :0040  TLS12_DHE_DSS_WITH_AES_128_CBC_SHA256
   noECC  TLS12 :0067  TLS12_DHE_RSA_WITH_AES_128_CBC_SHA256
   noECC  TLS12 :006A  TLS12_DHE_DSS_WITH_AES_256_CBC_SHA256
   noECC  TLS12 :006B  TLS12_DHE_RSA_WITH_AES_256_CBC_SHA256
   noECC  TLS12 :009C  TLS12_RSA_WITH_AES_128_GCM_SHA256
   noECC  TLS12 :009E  TLS12_DHE_RSA_WITH_AES_128_GCM_SHA256
   noECC  TLS12 :00A2  TLS12_DHE_DSS_WITH_AES_128_GCM_SHA256
   noECC  TLS12 :CCAA  TLS12_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+  noECC  TLS13 :1301  TLS13_DHE_WITH_AES_128_GCM_SHA256
+  noECC  TLS13 :1302  TLS13_DHE_WITH_AES_256_GCM_SHA384
+  noECC  TLS13 :1303  TLS13_DHE_WITH_CHACHA20_POLY1305_SHA256
 #
 # ECC ciphers (TLS)
 #
    ECC   TLS10  :C001 TLS_ECDH_ECDSA_WITH_NULL_SHA
    ECC   TLS10  :C002 TLS_ECDH_ECDSA_WITH_RC4_128_SHA
    ECC   TLS10  :C003 TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
    ECC   TLS10  :C004 TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
    ECC   TLS10  :C005 TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
@@ -141,8 +144,12 @@
    ECC   TLS12  :C030 TLS12_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    ECC   TLS12  :CCA8 TLS12_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
    ECC   TLS12  :CCA9 TLS12_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
 #
 # Test against server with RSA-PSS server certificate
 #
    ECC   TLS12  :C02F TLS12_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - RSA-PSS
    ECC   TLS12  :C030 TLS12_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - RSA-PSS
+# test TLS 1.3
+   ECC   TLS13  :1301 TLS13_ECDHE_WITH_AES_128_GCM_SHA256
+   ECC   TLS13  :1302 TLS13_ECDHE_WITH_AES_256_GCM_SHA384
+   ECC   TLS13  :1303 TLS13_ECDHE_WITH_CHACHA20_POLY1305_SHA256