diff --git a/.gitignore b/.gitignore
index 1760934..afa7d16 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/nss-softokn-3.34.0.tar.gz
+SOURCES/nss-softokn-3.36.0.tar.gz
diff --git a/.nss-softokn.metadata b/.nss-softokn.metadata
index 5f27f1b..6b16009 100644
--- a/.nss-softokn.metadata
+++ b/.nss-softokn.metadata
@@ -1 +1 @@
-185931ac63238c24c36369863495110450f2ee0e SOURCES/nss-softokn-3.34.0.tar.gz
+96e5512e1f34b79f65989abb10d45afc0f249f7e SOURCES/nss-softokn-3.36.0.tar.gz
diff --git a/SOURCES/nss-softokn-3.16-add_encrypt_derive.patch b/SOURCES/nss-softokn-3.16-add_encrypt_derive.patch
index be37be3..b6ba1d7 100644
--- a/SOURCES/nss-softokn-3.16-add_encrypt_derive.patch
+++ b/SOURCES/nss-softokn-3.16-add_encrypt_derive.patch
@@ -1,265 +1,59 @@
 diff -up nss/lib/softoken/pkcs11.c.add_encrypt_derive nss/lib/softoken/pkcs11.c
---- nss/lib/softoken/pkcs11.c.add_encrypt_derive	2017-10-30 10:38:09.000000000 +0100
-+++ nss/lib/softoken/pkcs11.c	2017-11-03 14:15:03.648179954 +0100
-@@ -421,11 +421,22 @@ static const struct mechanismList mechan
- #endif
-     /* --------------------- Secret Key Operations ------------------------ */
-     { CKM_GENERIC_SECRET_KEY_GEN, { 1, 32, CKF_GENERATE }, PR_TRUE },
--    { CKM_CONCATENATE_BASE_AND_KEY, { 1, 32, CKF_GENERATE }, PR_FALSE },
--    { CKM_CONCATENATE_BASE_AND_DATA, { 1, 32, CKF_GENERATE }, PR_FALSE },
--    { CKM_CONCATENATE_DATA_AND_BASE, { 1, 32, CKF_GENERATE }, PR_FALSE },
--    { CKM_XOR_BASE_AND_DATA, { 1, 32, CKF_GENERATE }, PR_FALSE },
-+    { CKM_CONCATENATE_BASE_AND_KEY, { 1, 32, CKF_DERIVE }, PR_FALSE },
-+    { CKM_CONCATENATE_BASE_AND_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
-+    { CKM_CONCATENATE_DATA_AND_BASE, { 1, 32, CKF_DERIVE }, PR_FALSE },
-+    { CKM_XOR_BASE_AND_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+--- nss/lib/softoken/pkcs11.c.add_encrypt_derive	2018-02-27 15:47:47.000000000 +0100
++++ nss/lib/softoken/pkcs11.c	2018-03-01 16:01:05.853165433 +0100
+@@ -426,6 +426,8 @@ static const struct mechanismList mechan
+     { CKM_CONCATENATE_DATA_AND_BASE, { 1, 32, CKF_DERIVE }, PR_FALSE },
+     { CKM_XOR_BASE_AND_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
      { CKM_EXTRACT_KEY_FROM_KEY, { 1, 32, CKF_DERIVE }, PR_FALSE },
-+    { CKM_EXTRACT_KEY_FROM_KEY, { 1, 32, CKF_DERIVE }, PR_FALSE },
 +    { CKM_DES_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
 +    { CKM_DES_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
-+    { CKM_DES3_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
-+    { CKM_DES3_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
-+    { CKM_AES_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
-+    { CKM_AES_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
-+    { CKM_CAMELLIA_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
-+    { CKM_CAMELLIA_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
-+    { CKM_SEED_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
-+    { CKM_SEED_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
-     /* ---------------------- SSL Key Derivations ------------------------- */
-     { CKM_SSL3_PRE_MASTER_KEY_GEN, { 48, 48, CKF_GENERATE }, PR_FALSE },
-     { CKM_SSL3_MASTER_KEY_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
+     { CKM_DES3_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+     { CKM_DES3_CBC_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
+     { CKM_AES_ECB_ENCRYPT_DATA, { 1, 32, CKF_DERIVE }, PR_FALSE },
 diff -up nss/lib/softoken/pkcs11c.c.add_encrypt_derive nss/lib/softoken/pkcs11c.c
---- nss/lib/softoken/pkcs11c.c.add_encrypt_derive	2017-10-30 10:38:09.000000000 +0100
-+++ nss/lib/softoken/pkcs11c.c	2017-11-03 14:19:35.665109757 +0100
-@@ -6242,6 +6242,44 @@ sftk_ANSI_X9_63_kdf(CK_BYTE **key, CK_UL
- }
- 
- /*
-+ *  Handle The derive from a block encryption cipher
-+ */
-+CK_RV
-+sftk_DeriveEncrypt(SFTKObject *key, CK_ULONG keySize, void *cipherInfo,
-+                   int blockSize, unsigned char *data, CK_ULONG len, SFTKCipher encrypt)
-+{
-+    unsigned char *tmpdata = NULL;
-+    SECStatus rv;
-+    unsigned int outLen;
-+    CK_RV crv;
-+
-+    if ((len % blockSize) != 0) {
-+        return CKR_MECHANISM_PARAM_INVALID;
-+    }
-+    if (keySize && (len < keySize)) {
-+        return CKR_MECHANISM_PARAM_INVALID;
-+    }
-+    if (keySize == 0) {
-+        keySize = len;
-+    }
-+
-+    tmpdata = PORT_Alloc(len);
-+    if (tmpdata == NULL) {
-+        return CKR_HOST_MEMORY;
-+    }
-+    rv = (*encrypt)(cipherInfo, tmpdata, &outLen, len, data, len);
-+    if (rv != SECSuccess) {
-+        crv = sftk_MapCryptError(PORT_GetError());
-+        PORT_ZFree(tmpdata, len);
-+        return crv;
-+    }
-+
-+    crv = sftk_forceAttribute(key, CKA_VALUE, tmpdata, keySize);
-+    PORT_ZFree(tmpdata, len);
-+    return crv;
-+}
-+
-+/*
-  * SSL Key generation given pre master secret
-  */
- #define NUM_MIXERS 9
-@@ -6286,6 +6324,9 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
-     CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
-     CK_OBJECT_CLASS classType = CKO_SECRET_KEY;
-     CK_KEY_DERIVATION_STRING_DATA *stringPtr;
-+    CK_AES_CBC_ENCRYPT_DATA_PARAMS *aesEncryptPtr;
-+    CK_DES_CBC_ENCRYPT_DATA_PARAMS *desEncryptPtr;
-+    void *cipherInfo;
-     CK_MECHANISM_TYPE mechanism = pMechanism->mechanism;
-     PRBool isTLS = PR_FALSE;
-     PRBool isDH = PR_FALSE;
-@@ -6295,6 +6336,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
-     unsigned int outLen;
-     unsigned char sha_out[SHA1_LENGTH];
-     unsigned char key_block[NUM_MIXERS * SFTK_MAX_MAC_LENGTH];
-+    unsigned char des3key[24];
-     PRBool isFIPS;
-     HASH_HashType hashType;
-     PRBool extractValue = PR_TRUE;
-@@ -6899,6 +6941,168 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
+--- nss/lib/softoken/pkcs11c.c.add_encrypt_derive	2018-02-27 15:47:47.000000000 +0100
++++ nss/lib/softoken/pkcs11c.c	2018-03-01 16:01:18.468880916 +0100
+@@ -6935,6 +6935,43 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
              break;
          }
  
 +        case CKM_DES_ECB_ENCRYPT_DATA:
-+            stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
-+            cipherInfo = DES_CreateContext((unsigned char *)att->attrib.pValue,
-+                                           NULL, NSS_DES, PR_TRUE);
-+            if (cipherInfo == NULL) {
-+                crv = CKR_HOST_MEMORY;
-+                break;
-+            }
-+            crv = sftk_DeriveEncrypt(key, keySize, cipherInfo, 8,
-+                                     stringPtr->pData, stringPtr->ulLen, (SFTKCipher)DES_Encrypt);
-+            DES_DestroyContext(cipherInfo, PR_TRUE);
-+            break;
-+
-+        case CKM_DES_CBC_ENCRYPT_DATA:
-+            desEncryptPtr = (CK_DES_CBC_ENCRYPT_DATA_PARAMS *)
-+                                pMechanism->pParameter;
-+            cipherInfo = DES_CreateContext((unsigned char *)att->attrib.pValue,
-+                                           desEncryptPtr->iv, NSS_DES_CBC, PR_TRUE);
-+            if (cipherInfo == NULL) {
-+                crv = CKR_HOST_MEMORY;
-+                break;
-+            }
-+            crv = sftk_DeriveEncrypt(key, keySize, cipherInfo, 8,
-+                                     desEncryptPtr->pData, desEncryptPtr->length,
-+                                     (SFTKCipher)DES_Encrypt);
-+            DES_DestroyContext(cipherInfo, PR_TRUE);
-+            break;
-+
-+        case CKM_DES3_ECB_ENCRYPT_DATA:
-+            stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
-+            if (att->attrib.ulValueLen == 16) {
-+                PORT_Memcpy(des3key, att->attrib.pValue, 16);
-+                PORT_Memcpy(des3key + 16, des3key, 8);
-+            } else if (att->attrib.ulValueLen == 24) {
-+                PORT_Memcpy(des3key, att->attrib.pValue, 24);
-+            } else {
-+                crv = CKR_KEY_SIZE_RANGE;
-+                break;
-+            }
-+            cipherInfo = DES_CreateContext(des3key, NULL, NSS_DES_EDE3, PR_TRUE);
-+            PORT_Memset(des3key, 0, 24);
-+            if (cipherInfo == NULL) {
-+                crv = CKR_HOST_MEMORY;
-+                break;
-+            }
-+            crv = sftk_DeriveEncrypt(key, keySize, cipherInfo, 8,
-+                                     stringPtr->pData, stringPtr->ulLen, (SFTKCipher)DES_Encrypt);
-+            DES_DestroyContext(cipherInfo, PR_TRUE);
-+            break;
-+
-+        case CKM_DES3_CBC_ENCRYPT_DATA:
-+            desEncryptPtr = (CK_DES_CBC_ENCRYPT_DATA_PARAMS *)
++        case CKM_DES_CBC_ENCRYPT_DATA: {
++            void *cipherInfo;
++            CK_DES_CBC_ENCRYPT_DATA_PARAMS *desEncryptPtr;
++            int mode;
++            unsigned char *iv;
++            unsigned char *data;
++            CK_ULONG len;
++
++            if (mechanism == CKM_DES_ECB_ENCRYPT_DATA) {
++                stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)
 +                                pMechanism->pParameter;
-+            if (att->attrib.ulValueLen == 16) {
-+                PORT_Memcpy(des3key, att->attrib.pValue, 16);
-+                PORT_Memcpy(des3key + 16, des3key, 8);
-+            } else if (att->attrib.ulValueLen == 24) {
-+                PORT_Memcpy(des3key, att->attrib.pValue, 24);
++                mode = NSS_DES;
++                iv = NULL;
++                data = stringPtr->pData;
++                len = stringPtr->ulLen;
 +            } else {
-+                crv = CKR_KEY_SIZE_RANGE;
-+                break;
++                mode = NSS_DES_CBC;
++                desEncryptPtr =
++                    (CK_DES_CBC_ENCRYPT_DATA_PARAMS *)
++                        pMechanism->pParameter;
++                iv = desEncryptPtr->iv;
++                data = desEncryptPtr->pData;
++                len = desEncryptPtr->length;
 +            }
-+            cipherInfo = DES_CreateContext(des3key, desEncryptPtr->iv,
-+                                           NSS_DES_EDE3_CBC, PR_TRUE);
-+            PORT_Memset(des3key, 0, 24);
++            cipherInfo = DES_CreateContext((unsigned char *)att->attrib.pValue, iv, mode, PR_TRUE);
 +            if (cipherInfo == NULL) {
 +                crv = CKR_HOST_MEMORY;
 +                break;
 +            }
-+            crv = sftk_DeriveEncrypt(key, keySize, cipherInfo, 8,
-+                                     desEncryptPtr->pData, desEncryptPtr->length,
-+                                     (SFTKCipher)DES_Encrypt);
++            crv = sftk_DeriveEncrypt((SFTKCipher)DES_Encrypt,
++                                     cipherInfo, 8, key, keySize,
++                                     data, len);
 +            DES_DestroyContext(cipherInfo, PR_TRUE);
 +            break;
++        }
 +
-+        case CKM_AES_ECB_ENCRYPT_DATA:
-+            stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
-+            cipherInfo = AES_CreateContext((unsigned char *)att->attrib.pValue,
-+                                           NULL, NSS_AES, PR_TRUE, att->attrib.ulValueLen, 16);
-+            if (cipherInfo == NULL) {
-+                crv = CKR_HOST_MEMORY;
-+                break;
-+            }
-+            crv = sftk_DeriveEncrypt(key, keySize, cipherInfo, 16,
-+                                     stringPtr->pData, stringPtr->ulLen, (SFTKCipher)AES_Encrypt);
-+            AES_DestroyContext(cipherInfo, PR_TRUE);
-+            break;
-+
-+        case CKM_AES_CBC_ENCRYPT_DATA:
-+            aesEncryptPtr = (CK_AES_CBC_ENCRYPT_DATA_PARAMS *)
-+                                pMechanism->pParameter;
-+            cipherInfo = AES_CreateContext((unsigned char *)att->attrib.pValue,
-+                                           aesEncryptPtr->iv, NSS_AES_CBC,
-+                                           PR_TRUE, att->attrib.ulValueLen, 16);
-+            if (cipherInfo == NULL) {
-+                crv = CKR_HOST_MEMORY;
-+                break;
-+            }
-+            crv = sftk_DeriveEncrypt(key, keySize, cipherInfo, 16,
-+                                     aesEncryptPtr->pData, aesEncryptPtr->length,
-+                                     (SFTKCipher)AES_Encrypt);
-+            AES_DestroyContext(cipherInfo, PR_TRUE);
-+            break;
-+
-+        case CKM_CAMELLIA_ECB_ENCRYPT_DATA:
-+            stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
-+            cipherInfo = Camellia_CreateContext((unsigned char *)att->attrib.pValue,
-+                                                NULL, NSS_CAMELLIA, PR_TRUE, att->attrib.ulValueLen);
-+            if (cipherInfo == NULL) {
-+                crv = CKR_HOST_MEMORY;
-+                break;
-+            }
-+            crv = sftk_DeriveEncrypt(key, keySize, cipherInfo, 16,
-+                                     stringPtr->pData, stringPtr->ulLen,
-+                                     (SFTKCipher)Camellia_Encrypt);
-+            Camellia_DestroyContext(cipherInfo, PR_TRUE);
-+            break;
-+
-+        case CKM_CAMELLIA_CBC_ENCRYPT_DATA:
-+            aesEncryptPtr = (CK_AES_CBC_ENCRYPT_DATA_PARAMS *)
-+                                pMechanism->pParameter;
-+            cipherInfo = Camellia_CreateContext((unsigned char *)att->attrib.pValue,
-+                                                aesEncryptPtr->iv, NSS_CAMELLIA_CBC,
-+                                                PR_TRUE, att->attrib.ulValueLen);
-+            if (cipherInfo == NULL) {
-+                crv = CKR_HOST_MEMORY;
-+                break;
-+            }
-+            crv = sftk_DeriveEncrypt(key, keySize, cipherInfo, 16,
-+                                     aesEncryptPtr->pData, aesEncryptPtr->length,
-+                                     (SFTKCipher)Camellia_Encrypt);
-+            Camellia_DestroyContext(cipherInfo, PR_TRUE);
-+            break;
-+
-+        case CKM_SEED_ECB_ENCRYPT_DATA:
-+            stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter;
-+            cipherInfo = SEED_CreateContext((unsigned char *)att->attrib.pValue,
-+                                            NULL, NSS_SEED, PR_TRUE);
-+            if (cipherInfo == NULL) {
-+                crv = CKR_HOST_MEMORY;
-+                break;
-+            }
-+            crv = sftk_DeriveEncrypt(key, keySize, cipherInfo, 16,
-+                                     stringPtr->pData, stringPtr->ulLen, (SFTKCipher)SEED_Encrypt);
-+            SEED_DestroyContext(cipherInfo, PR_TRUE);
-+            break;
-+
-+        case CKM_SEED_CBC_ENCRYPT_DATA:
-+            aesEncryptPtr = (CK_AES_CBC_ENCRYPT_DATA_PARAMS *)
-+                                pMechanism->pParameter;
-+            cipherInfo = SEED_CreateContext((unsigned char *)att->attrib.pValue,
-+                                            aesEncryptPtr->iv, NSS_SEED_CBC, PR_TRUE);
-+            if (cipherInfo == NULL) {
-+                crv = CKR_HOST_MEMORY;
-+                break;
-+            }
-+            crv = sftk_DeriveEncrypt(key, keySize, cipherInfo, 16,
-+                                     aesEncryptPtr->pData, aesEncryptPtr->length,
-+                                     (SFTKCipher)SEED_Encrypt);
-+            SEED_DestroyContext(cipherInfo, PR_TRUE);
-+            break;
-+
-         case CKM_CONCATENATE_BASE_AND_KEY: {
-             SFTKObject *newKey;
- 
+         case CKM_DES3_ECB_ENCRYPT_DATA:
+         case CKM_DES3_CBC_ENCRYPT_DATA: {
+             void *cipherInfo;
diff --git a/SOURCES/nss-softokn-3.28-fix-fips-login.patch b/SOURCES/nss-softokn-3.28-fix-fips-login.patch
deleted file mode 100644
index d8464e9..0000000
--- a/SOURCES/nss-softokn-3.28-fix-fips-login.patch
+++ /dev/null
@@ -1,107 +0,0 @@
-diff -up ./nss/lib/softoken/fipstokn.c.fix-fips-login ./nss/lib/softoken/fipstokn.c
---- ./nss/lib/softoken/fipstokn.c.fix-fips-login	2017-02-17 05:20:06.000000000 -0800
-+++ ./nss/lib/softoken/fipstokn.c	2017-05-05 15:29:23.934308889 -0700
-@@ -540,7 +540,10 @@ FC_GetTokenInfo(CK_SLOT_ID slotID, CK_TO
- 
-     crv = NSC_GetTokenInfo(slotID, pInfo);
-     if (crv == CKR_OK) {
--        if ((pInfo->flags & CKF_LOGIN_REQUIRED) == 0) {
-+	/* use the global database to figure out if we are running in 
-+         * FIPS 140 Level 1 or Level 2 */
-+        if (slotID == FIPS_SLOT_ID &&
-+		(pInfo->flags & CKF_LOGIN_REQUIRED) == 0) {
-             isLevel2 = PR_FALSE;
-         }
-     }
-@@ -616,7 +619,8 @@ FC_InitPIN(CK_SESSION_HANDLE hSession,
-      * we need to make sure the pin meets FIPS requirements */
-     if ((ulPinLen == 0) || ((rv = sftk_newPinCheck(pPin, ulPinLen)) == CKR_OK)) {
-         rv = NSC_InitPIN(hSession, pPin, ulPinLen);
--        if (rv == CKR_OK) {
-+        if ((rv == CKR_OK) && 
-+		(sftk_SlotIDFromSessionHandle(hSession) == FIPS_SLOT_ID)) {
-             isLevel2 = (ulPinLen > 0) ? PR_TRUE : PR_FALSE;
-         }
-     }
-@@ -644,7 +648,8 @@ FC_SetPIN(CK_SESSION_HANDLE hSession, CK
-     if ((rv = sftk_fipsCheck()) == CKR_OK &&
-         (rv = sftk_newPinCheck(pNewPin, usNewLen)) == CKR_OK) {
-         rv = NSC_SetPIN(hSession, pOldPin, usOldLen, pNewPin, usNewLen);
--        if (rv == CKR_OK) {
-+        if ((rv == CKR_OK) && 
-+		(sftk_SlotIDFromSessionHandle(hSession) == FIPS_SLOT_ID)) {
-             /* if we set the password in level1 we now go
-              * to level2. NOTE: we don't allow the user to
-              * go from level2 to level1 */
-@@ -705,12 +710,24 @@ FC_GetSessionInfo(CK_SESSION_HANDLE hSes
- 
-     rv = NSC_GetSessionInfo(hSession, pInfo);
-     if (rv == CKR_OK) {
--        if ((isLoggedIn) && (pInfo->state == CKS_RO_PUBLIC_SESSION)) {
--            pInfo->state = CKS_RO_USER_FUNCTIONS;
--        }
--        if ((isLoggedIn) && (pInfo->state == CKS_RW_PUBLIC_SESSION)) {
--            pInfo->state = CKS_RW_USER_FUNCTIONS;
--        }
-+	/* handle the case where the auxilary slot doesn't require login.
-+         * piggy back on the main token's login state */
-+	if (isLoggedIn && 
-+		((pInfo->state == CKS_RO_PUBLIC_SESSION) ||
-+		 (pInfo->state == CKS_RW_PUBLIC_SESSION))) {
-+	    CK_RV crv;
-+	    CK_TOKEN_INFO tInfo;
-+	    crv = NSC_GetTokenInfo(sftk_SlotIDFromSessionHandle(hSession),
-+								&tInfo);
-+	    /* if the token doesn't login, use our global login state */
-+	    if ((crv == CKR_OK) && ((tInfo.flags & CKF_LOGIN_REQUIRED) == 0)) {
-+		if (pInfo->state == CKS_RO_PUBLIC_SESSION) {
-+            	    pInfo->state = CKS_RO_USER_FUNCTIONS;
-+		} else {
-+            	   pInfo->state = CKS_RW_USER_FUNCTIONS;
-+	        }
-+	    }
-+	}
-     }
-     return rv;
- }
-diff -up ./nss/lib/softoken/pkcs11.c.fix-fips-login ./nss/lib/softoken/pkcs11.c
---- ./nss/lib/softoken/pkcs11.c.fix-fips-login	2017-05-05 15:33:02.247012129 -0700
-+++ ./nss/lib/softoken/pkcs11.c	2017-05-05 15:34:43.399727983 -0700
-@@ -2370,17 +2370,22 @@ sftk_SlotFromID(CK_SLOT_ID slotID, PRBoo
-     return slot;
- }
- 
--SFTKSlot *
--sftk_SlotFromSessionHandle(CK_SESSION_HANDLE handle)
-+CK_SLOT_ID
-+sftk_SlotIDFromSessionHandle(CK_SESSION_HANDLE handle)
- {
-     CK_ULONG slotIDIndex = (handle >> 24) & 0x7f;
-     CK_ULONG moduleIndex = (handle >> 31) & 1;
- 
-     if (slotIDIndex >= nscSlotCount[moduleIndex]) {
--        return NULL;
-+        return (CK_SLOT_ID)-1;
-     }
-+    return nscSlotList[moduleIndex][slotIDIndex];
-+}
- 
--    return sftk_SlotFromID(nscSlotList[moduleIndex][slotIDIndex], PR_FALSE);
-+SFTKSlot *
-+sftk_SlotFromSessionHandle(CK_SESSION_HANDLE handle)
-+{
-+    return sftk_SlotFromID(sftk_SlotIDFromSessionHandle(handle), PR_FALSE);
- }
- 
- static CK_RV
-diff -up ./nss/lib/softoken/pkcs11i.h.fix-fips-login ./nss/lib/softoken/pkcs11i.h
---- ./nss/lib/softoken/pkcs11i.h.fix-fips-login	2017-02-17 05:20:06.000000000 -0800
-+++ ./nss/lib/softoken/pkcs11i.h	2017-05-05 15:29:23.934308889 -0700
-@@ -667,6 +667,7 @@ extern CK_RV sftk_handleObject(SFTKObjec
- 
- extern SFTKSlot *sftk_SlotFromID(CK_SLOT_ID slotID, PRBool all);
- extern SFTKSlot *sftk_SlotFromSessionHandle(CK_SESSION_HANDLE handle);
-+extern CK_SLOT_ID sftk_SlotIDFromSessionHandle(CK_SESSION_HANDLE handle);
- extern SFTKSession *sftk_SessionFromHandle(CK_SESSION_HANDLE handle);
- extern void sftk_FreeSession(SFTKSession *session);
- extern SFTKSession *sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify,
diff --git a/SOURCES/nss-softokn-add-kas-tests.patch b/SOURCES/nss-softokn-add-kas-tests.patch
new file mode 100644
index 0000000..dc6efff
--- /dev/null
+++ b/SOURCES/nss-softokn-add-kas-tests.patch
@@ -0,0 +1,1254 @@
+diff --git a/cmd/fipstest/fipstest.c b/cmd/fipstest/fipstest.c
+--- a/cmd/fipstest/fipstest.c
++++ b/cmd/fipstest/fipstest.c
+@@ -2330,16 +2330,44 @@ sha_get_hashType(int hashbits)
+             hashType = HASH_AlgSHA512;
+             break;
+         default:
+             break;
+     }
+     return hashType;
+ }
+ 
++HASH_HashType
++hash_string_to_hashType(const char * src)
++{
++    HASH_HashType shaAlg = HASH_AlgNULL;
++    if (strncmp(src, "SHA-1", 5) == 0) {
++         shaAlg = HASH_AlgSHA1;
++    } else if (strncmp(src, "SHA-224", 7) == 0) {
++        shaAlg = HASH_AlgSHA224;
++    } else if (strncmp(src, "SHA-256", 7) == 0) {
++        shaAlg = HASH_AlgSHA256;
++    } else if (strncmp(src, "SHA-384", 7) == 0) {
++        shaAlg = HASH_AlgSHA384;
++    } else if (strncmp(src, "SHA-512", 7) == 0) {
++        shaAlg = HASH_AlgSHA512;
++    } else if (strncmp(src, "SHA1", 4) == 0) {
++         shaAlg = HASH_AlgSHA1;
++    } else if (strncmp(src, "SHA224", 6) == 0) {
++        shaAlg = HASH_AlgSHA224;
++    } else if (strncmp(src, "SHA256", 6) == 0) {
++        shaAlg = HASH_AlgSHA256;
++    } else if (strncmp(src, "SHA384", 6) == 0) {
++        shaAlg = HASH_AlgSHA384;
++    } else if (strncmp(src, "SHA512", 6) == 0) {
++        shaAlg = HASH_AlgSHA512;
++    }
++    return shaAlg;
++}
++
+ /*
+  * Perform the ECDSA Key Pair Generation Test.
+  *
+  * reqfn is the pathname of the REQUEST file.
+  *
+  * The output RESPONSE file is written to stdout.
+  */
+ void
+@@ -2623,27 +2651,18 @@ ecdsa_siggen_test(char *reqfn)
+             *dst++ = tolower(*src);
+             src += 2; /* skip the hyphen */
+             *dst++ = *src++;
+             *dst++ = *src++;
+             *dst++ = *src++;
+             *dst = '\0';
+             src++; /* skip the comma */
+             /* set the SHA Algorithm */
+-            if (strncmp(src, "SHA-1", 5) == 0) {
+-                shaAlg = HASH_AlgSHA1;
+-            } else if (strncmp(src, "SHA-224", 7) == 0) {
+-                shaAlg = HASH_AlgSHA224;
+-            } else if (strncmp(src, "SHA-256", 7) == 0) {
+-                shaAlg = HASH_AlgSHA256;
+-            } else if (strncmp(src, "SHA-384", 7) == 0) {
+-                shaAlg = HASH_AlgSHA384;
+-            } else if (strncmp(src, "SHA-512", 7) == 0) {
+-                shaAlg = HASH_AlgSHA512;
+-            } else {
++            shaAlg = hash_string_to_hashType(src);
++            if (shaAlg == HASH_AlgNULL){
+                 fprintf(ecdsaresp, "ERROR: Unable to find SHAAlg type");
+                 goto loser;
+             }
+             if (ecparams != NULL) {
+                 PORT_FreeArena(ecparams->arena, PR_FALSE);
+                 ecparams = NULL;
+             }
+             encodedparams = getECParams(curve);
+@@ -2793,27 +2812,18 @@ ecdsa_sigver_test(char *reqfn)
+             *dst++ = tolower(*src);
+             src += 2; /* skip the hyphen */
+             *dst++ = *src++;
+             *dst++ = *src++;
+             *dst++ = *src++;
+             *dst = '\0';
+             src++; /* skip the comma */
+             /* set the SHA Algorithm */
+-            if (strncmp(src, "SHA-1", 5) == 0) {
+-                shaAlg = HASH_AlgSHA1;
+-            } else if (strncmp(src, "SHA-224", 7) == 0) {
+-                shaAlg = HASH_AlgSHA224;
+-            } else if (strncmp(src, "SHA-256", 7) == 0) {
+-                shaAlg = HASH_AlgSHA256;
+-            } else if (strncmp(src, "SHA-384", 7) == 0) {
+-                shaAlg = HASH_AlgSHA384;
+-            } else if (strncmp(src, "SHA-512", 7) == 0) {
+-                shaAlg = HASH_AlgSHA512;
+-            } else {
++            shaAlg = hash_string_to_hashType(src);
++            if (shaAlg == HASH_AlgNULL) {
+                 fprintf(ecdsaresp, "ERROR: Unable to find SHAAlg type");
+                 goto loser;
+             }
+             encodedparams = getECParams(curve);
+             if (encodedparams == NULL) {
+                 fprintf(stderr, "Unknown curve %s.", curve);
+                 goto loser;
+             }
+@@ -2951,16 +2961,932 @@ ecdsa_sigver_test(char *reqfn)
+     }
+ loser:
+     if (ecpub.ecParams.arena != NULL) {
+         PORT_FreeArena(ecpub.ecParams.arena, PR_FALSE);
+     }
+     fclose(ecdsareq);
+ }
+ 
++/*
++ * Perform the ECDH Functional Test.
++ *
++ * reqfn is the pathname of the REQUEST file.
++ *
++ * The output RESPONSE file is written to stdout.
++ */
++#define MAX_ECC_PARAMS 256
++void
++ecdh_functional(char *reqfn, PRBool response)
++{
++    char buf[256];   /* holds one line from the input REQUEST file.
++                         * needs to be large enough to hold the longest
++                         * line "Qx = <144 hex digits>\n".
++                         */
++    FILE *ecdhreq;  /* input stream from the REQUEST file */
++    FILE *ecdhresp; /* output stream to the RESPONSE file */
++    char curve[16];  /* "nistxddd" */
++    unsigned char hashBuf[HASH_LENGTH_MAX];
++    ECParams *ecparams[MAX_ECC_PARAMS] = {NULL};
++    ECPrivateKey *ecpriv = NULL;
++    ECParams *current_ecparams = NULL;
++    SECItem pubkey;
++    SECItem ZZ;
++    unsigned int i;
++    unsigned int len = 0;
++    unsigned int uit_len = 0;
++    int current_curve = -1;
++    HASH_HashType hash = HASH_AlgNULL; /* type of SHA Alg */
++
++    ecdhreq = fopen(reqfn, "r");
++    ecdhresp = stdout;
++    strcpy(curve, "nist");
++    pubkey.data = NULL;
++    while (fgets(buf, sizeof buf, ecdhreq) != NULL) {
++        /* a comment or blank line */
++        if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') {
++            fputs(buf, ecdhresp);
++            continue;
++        }
++        if (buf[0] == '[') {
++            /* [Ex] */
++            if (buf[1] == 'E' && buf[3] == ']') {
++                current_curve = buf[2] - 'A';
++                fputs(buf, ecdhresp);
++                continue;
++            }
++            /* [Curve selected: x-nnn */
++            if (strncmp(buf, "[Curve ", 7) == 0) {
++                const char *src;
++                char *dst;
++                SECItem *encodedparams;
++
++                if ((current_curve < 0) || (current_curve > MAX_ECC_PARAMS)) {
++                    fprintf(stderr, "No curve type defined\n");
++                    goto loser;
++                }
++
++                src = &buf[1];
++                /* skip passed the colon */
++                while (*src && *src != ':') src++;
++                if (*src != ':') {
++                    fprintf(stderr,
++                        "No colon in curve selected statement\n%s", buf);
++                    goto loser;
++                }
++                src++;
++                /* skip to the first non-space */
++                while (*src && *src == ' ') src++;
++                dst = &curve[4];
++                *dst++ = tolower(*src);
++                src += 2; /* skip the hyphen */
++                *dst++ = *src++;
++                *dst++ = *src++;
++                *dst++ = *src++;
++                *dst = '\0';
++                if (ecparams[current_curve] != NULL) {
++                    PORT_FreeArena(ecparams[current_curve]->arena, PR_FALSE);
++                    ecparams[current_curve] = NULL;
++                }
++                encodedparams = getECParams(curve);
++                if (encodedparams == NULL) {
++                    fprintf(stderr, "Unknown curve %s.", curve);
++                    goto loser;
++                }
++                if (EC_DecodeParams(encodedparams, &ecparams[current_curve])
++                                                        != SECSuccess) {
++                    fprintf(stderr, "Curve %s not supported.\n", curve);
++                    goto loser;
++                }
++                SECITEM_FreeItem(encodedparams, PR_TRUE);
++                fputs(buf, ecdhresp);
++                continue;
++            }
++            /* [Ex - SHAxxx] */
++            if (buf[1] == 'E' && buf[3] == ' ') {
++                const char *src;
++                current_curve = buf[2] - 'A';
++                if ((current_curve < 0) || (current_curve > 256)) {
++                    fprintf(stderr, "bad curve type defined (%c)\n", buf[2]);
++                    goto loser;
++                }
++                    current_ecparams = ecparams[current_curve];
++                if (current_ecparams == NULL) {
++                    fprintf(stderr, "no curve defined for type %c defined\n",
++                            buf[2]);
++                    goto loser;
++                }
++                /* skip passed the colon */
++                src = &buf[1];
++                while (*src && *src != '-') src++;
++                if (*src != '-') {
++                    fprintf(stderr,
++                        "No data in curve selected statement\n%s",buf);
++                    goto loser;
++                }
++                src++;
++                /* skip to the first non-space */
++                while (*src && *src == ' ') src++;
++                hash = hash_string_to_hashType(src);
++                if (hash == HASH_AlgNULL){
++                    fprintf(ecdhresp, "ERROR: Unable to find SHAAlg type");
++                    goto loser;
++                }
++                fputs(buf, ecdhresp);
++                continue;
++            }
++            fputs(buf, ecdhresp);
++            continue;
++        }
++        /* COUNT = ... */
++        if (strncmp(buf, "COUNT", 5) == 0) {
++            fputs(buf, ecdhresp);
++            if (current_ecparams == NULL) {
++                fprintf(stderr, "no curve defined for type %c defined\n",
++                            buf[2]);
++                goto loser;
++            }
++            len = (current_ecparams->fieldID.size + 7) >> 3;
++            if (pubkey.data != NULL) {
++                PORT_Free(pubkey.data);
++                pubkey.data = NULL;
++            }
++            SECITEM_AllocItem(NULL, &pubkey, EC_GetPointSize(current_ecparams));
++            if (pubkey.data == NULL) {
++                goto loser;
++            }
++            pubkey.data[0] = EC_POINT_FORM_UNCOMPRESSED;
++            continue;
++        }
++        /* QeCAVSx = ... */
++        if (strncmp(buf, "QeCAVSx", 7) == 0) {
++            fputs(buf, ecdhresp);
++            i = 7;
++            while (isspace(buf[i]) || buf[i] == '=') {
++                i++;
++            }
++            from_hex_str(&pubkey.data[1], len, &buf[i]);
++            continue;
++        }
++        /* QeCAVSy = ... */
++        if (strncmp(buf, "QeCAVSy", 7) == 0) {
++            fputs(buf, ecdhresp);
++            i = 7;
++            while (isspace(buf[i]) || buf[i] == '=') {
++                i++;
++            }
++            from_hex_str(&pubkey.data[1 + len], len, &buf[i]);
++            if (current_ecparams == NULL) {
++                fprintf(stderr, "no curve defined\n");
++                goto loser;
++            }
++            /* validate CAVS public key */
++            if (EC_ValidatePublicKey(current_ecparams, &pubkey) != SECSuccess) {
++                fprintf(stderr,"BAD key detected\n");
++                goto loser;
++            }
++
++            /* generate ECC key pair */
++            if (EC_NewKey(current_ecparams, &ecpriv) != SECSuccess) {
++                fprintf(stderr,"Failed to generate new key\n");
++                goto loser;
++            }
++            /* validate UIT generated public key */
++            if (EC_ValidatePublicKey(current_ecparams, &ecpriv->publicValue) !=
++                    SECSuccess) {
++                fprintf(stderr,"generate key did not validate\n");
++                goto loser;
++            }
++            /* output UIT public key */
++            uit_len = ecpriv->publicValue.len;
++            if (uit_len % 2 == 0) {
++                fprintf(stderr,"generate key had invalid public value len\n");
++                goto loser;
++            }
++            uit_len = (uit_len - 1) / 2;
++            if (ecpriv->publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) {
++                fprintf(stderr,"generate key was compressed\n");
++                goto loser;
++            }
++            fputs("QeIUTx = ", ecdhresp);
++            to_hex_str(buf, &ecpriv->publicValue.data[1], uit_len);
++            fputs(buf, ecdhresp);
++            fputc('\n', ecdhresp);
++            fputs("QeIUTy = ", ecdhresp);
++            to_hex_str(buf, &ecpriv->publicValue.data[1 + uit_len], uit_len);
++            fputs(buf, ecdhresp);
++            fputc('\n', ecdhresp);
++            /* ECDH */
++            if (ECDH_Derive(&pubkey,current_ecparams, &ecpriv->privateValue,
++                        PR_FALSE, &ZZ) != SECSuccess) {
++                fprintf(stderr,"Derive failed\n");
++                goto loser;
++            }
++            /* output hash of ZZ */
++            if (fips_hashBuf(hash, hashBuf, ZZ.data, ZZ.len) != SECSuccess ) {
++                fprintf(stderr,"hash of derived key failed\n");
++                goto loser;
++            }
++            SECITEM_FreeItem(&ZZ, PR_FALSE);
++            fputs("HashZZ = ", ecdhresp);
++            to_hex_str(buf, hashBuf, fips_hashLen(hash));
++            fputs(buf, ecdhresp);
++            fputc('\n', ecdhresp);
++            fputc('\n', ecdhresp);
++            PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE);
++            ecpriv = NULL;
++            continue;
++        }
++    }
++loser:
++    if (ecpriv != NULL) {
++        PORT_FreeArena(ecpriv->ecParams.arena, PR_TRUE);
++    }
++    for (i=0; i < MAX_ECC_PARAMS; i++) {
++        if (ecparams[i] != NULL) {
++            PORT_FreeArena(ecparams[i]->arena, PR_FALSE);
++            ecparams[i] = NULL;
++        }
++    }
++    if (pubkey.data != NULL) {
++        PORT_Free(pubkey.data);
++    }
++    fclose(ecdhreq);
++}
++
++#define MATCH_OPENSSL 1 
++/*
++ * Perform the ECDH Validity Test.
++ *
++ * reqfn is the pathname of the REQUEST file.
++ *
++ * The output RESPONSE file is written to stdout.
++ */
++void
++ecdh_verify(char *reqfn, PRBool response)
++{
++    char buf[256];   /* holds one line from the input REQUEST file.
++                         * needs to be large enough to hold the longest
++                         * line "Qx = <144 hex digits>\n".
++                         */
++    FILE *ecdhreq;  /* input stream from the REQUEST file */
++    FILE *ecdhresp; /* output stream to the RESPONSE file */
++    char curve[16];  /* "nistxddd" */
++    unsigned char hashBuf[HASH_LENGTH_MAX];
++    unsigned char cavsHashBuf[HASH_LENGTH_MAX];
++    unsigned char private_data[MAX_ECKEY_LEN];
++    ECParams *ecparams[MAX_ECC_PARAMS] =  {NULL};
++    ECParams *current_ecparams = NULL;
++    SECItem pubkey;
++    SECItem ZZ;
++    SECItem private_value;
++    unsigned int i;
++    unsigned int len = 0;
++    int current_curve = -1;
++    HASH_HashType hash = HASH_AlgNULL; /* type of SHA Alg */
++
++    ecdhreq = fopen(reqfn, "r");
++    ecdhresp = stdout;
++    strcpy(curve, "nist");
++    pubkey.data = NULL;
++    while (fgets(buf, sizeof buf, ecdhreq) != NULL) {
++        /* a comment or blank line */
++        if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') {
++            fputs(buf, ecdhresp);
++            continue;
++        }
++        if (buf[0] == '[') {
++            /* [Ex] */
++            if (buf[1] == 'E' && buf[3] == ']') {
++                current_curve = buf[2] - 'A';
++                fputs(buf, ecdhresp);
++                continue;
++            }
++            /* [Curve selected: x-nnn */
++            if (strncmp(buf, "[Curve ", 7) == 0) {
++                const char *src;
++                char *dst;
++                SECItem *encodedparams;
++
++                if ((current_curve < 0) || (current_curve > MAX_ECC_PARAMS)) {
++                    fprintf(stderr, "No curve type defined\n");
++                    goto loser;
++                }
++
++                src = &buf[1];
++                /* skip passed the colon */
++                while (*src && *src != ':') src++;
++                if (*src != ':') {
++                    fprintf(stderr,
++                        "No colon in curve selected statement\n%s", buf);
++                    goto loser;
++                }
++                src++;
++                /* skip to the first non-space */
++                while (*src && *src == ' ') src++;
++                dst = &curve[4];
++                *dst++ = tolower(*src);
++                src += 2; /* skip the hyphen */
++                *dst++ = *src++;
++                *dst++ = *src++;
++                *dst++ = *src++;
++                *dst = '\0';
++                if (ecparams[current_curve] != NULL) {
++                    PORT_FreeArena(ecparams[current_curve]->arena, PR_FALSE);
++                    ecparams[current_curve] = NULL;
++                }
++                encodedparams = getECParams(curve);
++                if (encodedparams == NULL) {
++                    fprintf(stderr, "Unknown curve %s.\n", curve);
++                    goto loser;
++                }
++                if (EC_DecodeParams(encodedparams, &ecparams[current_curve])
++                                                        != SECSuccess) {
++                    fprintf(stderr, "Curve %s not supported.\n", curve);
++                    goto loser;
++                }
++                SECITEM_FreeItem(encodedparams, PR_TRUE);
++                fputs(buf, ecdhresp);
++                continue;
++            }
++            /* [Ex - SHAxxx] */
++            if (buf[1] == 'E' && buf[3] == ' ') {
++                const char *src;
++                current_curve = buf[2] - 'A';
++                if ((current_curve < 0) || (current_curve > 256)) {
++                    fprintf(stderr, "bad curve type defined (%c)\n", buf[2]);
++                    goto loser;
++                }
++                    current_ecparams = ecparams[current_curve];
++                if (current_ecparams == NULL) {
++                    fprintf(stderr, "no curve defined for type %c defined\n",
++                            buf[2]);
++                    goto loser;
++                }
++                /* skip passed the colon */
++                src = &buf[1];
++                while (*src && *src != '-') src++;
++                if (*src != '-') {
++                    fprintf(stderr,
++                        "No data in curve selected statement\n%s",buf);
++                    goto loser;
++                }
++                src++;
++                /* skip to the first non-space */
++                while (*src && *src == ' ') src++;
++                hash = hash_string_to_hashType(src);
++                if (hash == HASH_AlgNULL){
++                    fprintf(ecdhresp, "ERROR: Unable to find SHAAlg type");
++                    goto loser;
++                }
++                fputs(buf, ecdhresp);
++                continue;
++            }
++            fputs(buf, ecdhresp);
++            continue;
++        }
++        /* COUNT = ... */
++        if (strncmp(buf, "COUNT", 5) == 0) {
++            fputs(buf, ecdhresp);
++            if (current_ecparams == NULL) {
++                fprintf(stderr, "no curve defined for type %c defined\n",
++                            buf[2]);
++                goto loser;
++            }
++            len = (current_ecparams->fieldID.size + 7) >> 3;
++            if (pubkey.data != NULL) {
++                PORT_Free(pubkey.data);
++                pubkey.data = NULL;
++            }
++            SECITEM_AllocItem(NULL, &pubkey, EC_GetPointSize(current_ecparams));
++            if (pubkey.data == NULL) {
++                goto loser;
++            }
++            pubkey.data[0] = EC_POINT_FORM_UNCOMPRESSED;
++            continue;
++        }
++        /* QeCAVSx = ... */
++        if (strncmp(buf, "QeCAVSx", 7) == 0) {
++            fputs(buf, ecdhresp);
++            i = 7;
++            while (isspace(buf[i]) || buf[i] == '=') {
++                i++;
++            }
++            from_hex_str(&pubkey.data[1], len, &buf[i]);
++            continue;
++        }
++        /* QeCAVSy = ... */
++        if (strncmp(buf, "QeCAVSy", 7) == 0) {
++            fputs(buf, ecdhresp);
++            i = 7;
++            while (isspace(buf[i]) || buf[i] == '=') {
++                i++;
++            }
++            from_hex_str(&pubkey.data[1 + len], len, &buf[i]);
++            continue;
++        }
++        if (strncmp(buf, "deIUT", 5) == 0) {
++            fputs(buf, ecdhresp);
++            i = 5;
++            while (isspace(buf[i]) || buf[i] == '=') {
++                i++;
++            }
++            from_hex_str(private_data, len, &buf[i]);
++            private_value.data = private_data;
++            private_value.len = len;
++            continue;
++        }
++        if (strncmp(buf, "QeIUTx", 6) == 0) {
++            fputs(buf, ecdhresp);
++            continue;
++        }
++        if (strncmp(buf, "QeIUTy", 6) == 0) {
++            fputs(buf, ecdhresp);
++            continue;
++        }
++        if (strncmp(buf, "CAVSHashZZ", 10) == 0) {
++            fputs(buf, ecdhresp);
++            i = 10;
++            while (isspace(buf[i]) || buf[i] == '=') {
++                i++;
++            }
++            from_hex_str(cavsHashBuf, fips_hashLen(hash), &buf[i]);
++            if (current_ecparams == NULL) {
++                fprintf(stderr, "no curve defined for type defined\n");
++                goto loser;
++            }
++            /* validate CAVS public key */
++            if (EC_ValidatePublicKey(current_ecparams, &pubkey) != SECSuccess) {
++#ifdef MATCH_OPENSSL
++		fprintf(ecdhresp, "Result = F\n");
++#else
++		fprintf(ecdhresp, "Result = F # key didn't validate\n");
++#endif
++                continue;
++            }
++
++            /* ECDH */
++            if (ECDH_Derive(&pubkey, current_ecparams, &private_value,
++                        PR_FALSE, &ZZ) != SECSuccess) {
++                fprintf(stderr,"Derive failed\n");
++                goto loser;
++            }
++            /* output  ZZ */
++#ifndef MATCH_OPENSSL
++            fputs("Z = ", ecdhresp);
++            to_hex_str(buf, ZZ.data, ZZ.len);
++            fputs(buf, ecdhresp);
++            fputc('\n', ecdhresp);
++#endif
++
++            if (fips_hashBuf(hash, hashBuf, ZZ.data, ZZ.len) != SECSuccess ) {
++                fprintf(stderr,"hash of derived key failed\n");
++                goto loser;
++            }
++            SECITEM_FreeItem(&ZZ, PR_FALSE);
++#ifndef MATCH_NIST
++            fputs("IUTHashZZ = ", ecdhresp);
++            to_hex_str(buf, hashBuf, fips_hashLen(hash));
++            fputs(buf, ecdhresp);
++            fputc('\n', ecdhresp);
++#endif
++            if (memcmp(hashBuf, cavsHashBuf, fips_hashLen(hash)) != 0) {
++#ifdef MATCH_OPENSSL
++		fprintf(ecdhresp, "Result = F\n");
++#else
++		fprintf(ecdhresp, "Result = F # hash doesn't match\n");
++#endif
++            } else {
++		fprintf(ecdhresp, "Result = P\n");
++            }
++#ifndef MATCH_OPENSSL
++            fputc('\n', ecdhresp);
++#endif
++            continue;
++        }
++    }
++loser:
++    for (i=0; i < MAX_ECC_PARAMS; i++) {
++        if (ecparams[i] != NULL) {
++            PORT_FreeArena(ecparams[i]->arena, PR_FALSE);
++            ecparams[i] = NULL;
++        }
++    }
++    if (pubkey.data != NULL) {
++        PORT_Free(pubkey.data);
++    }
++    fclose(ecdhreq);
++}
++
++/*
++ * Perform the DH Functional Test.
++ *
++ * reqfn is the pathname of the REQUEST file.
++ *
++ * The output RESPONSE file is written to stdout.
++ */
++#define MAX_ECC_PARAMS 256
++void
++dh_functional(char *reqfn, PRBool response)
++{
++    char buf[1024];   /* holds one line from the input REQUEST file.
++                         * needs to be large enough to hold the longest
++                         * line "YephCAVS = <512 hex digits>\n".
++                         */
++    FILE *dhreq;  /* input stream from the REQUEST file */
++    FILE *dhresp; /* output stream to the RESPONSE file */
++    unsigned char hashBuf[HASH_LENGTH_MAX];
++    DSAPrivateKey *dsapriv = NULL;
++    PQGParams pqg = { 0 };
++    unsigned char pubkeydata[DSA_MAX_P_BITS/8];
++    SECItem pubkey;
++    SECItem ZZ;
++    unsigned int i,j;
++    unsigned int pgySize;
++    HASH_HashType hash = HASH_AlgNULL; /* type of SHA Alg */
++
++    dhreq = fopen(reqfn, "r");
++    dhresp = stdout;
++    while (fgets(buf, sizeof buf, dhreq) != NULL) {
++        /* a comment or blank line */
++        if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') {
++            fputs(buf, dhresp);
++            continue;
++        }
++        if (buf[0] == '[') {
++            /* [Fx - SHAxxx] */
++            if (buf[1] == 'F' && buf[3] == ' ') {
++                const char *src;
++                /* skip passed the colon */
++                src = &buf[1];
++                while (*src && *src != '-') src++;
++                if (*src != '-') {
++                    fprintf(stderr, "No hash specified\n%s",buf);
++                    goto loser;
++                }
++                src++;
++                /* skip to the first non-space */
++                while (*src && *src == ' ') src++;
++                hash = hash_string_to_hashType(src);
++                if (hash == HASH_AlgNULL){
++                    fprintf(dhresp, "ERROR: Unable to find SHAAlg type");
++                    goto loser;
++                }
++                /* clear the PQG parameters */
++                if (pqg.prime.data) { /* P */
++                    SECITEM_ZfreeItem(&pqg.prime, PR_FALSE);
++                }
++                if (pqg.subPrime.data) { /* Q */
++                    SECITEM_ZfreeItem(&pqg.subPrime, PR_FALSE);
++                }
++                if (pqg.base.data) { /* G */
++                    SECITEM_ZfreeItem(&pqg.base, PR_FALSE);
++                }
++                pgySize = DSA_MAX_P_BITS / 8; /* change if more key sizes are supported in CAVS */
++                SECITEM_AllocItem(NULL, &pqg.prime, pgySize);
++                SECITEM_AllocItem(NULL, &pqg.base, pgySize);
++                pqg.prime.len = pqg.base.len = pgySize;
++
++                /* set q to the max allows */
++                SECITEM_AllocItem(NULL, &pqg.subPrime, DSA_MAX_Q_BITS/ 8);
++                pqg.subPrime.len = DSA_MAX_Q_BITS / 8;
++                fputs(buf, dhresp);
++                continue;
++            }
++            fputs(buf, dhresp);
++            continue;
++        }
++        if (buf[0] == 'P') {
++            i = 1;
++            while (isspace(buf[i]) || buf[i] == '=') {
++                i++;
++            }
++            for (j = 0; j < pqg.prime.len; i += 2, j++) {
++                if (!isxdigit(buf[i])) {
++                    pqg.prime.len = j;
++                    break;
++                }
++                hex_to_byteval(&buf[i], &pqg.prime.data[j]);
++            }
++
++            fputs(buf, dhresp);
++            continue;
++        }
++
++        /* Q = ... */
++        if (buf[0] == 'Q') {
++            i = 1;
++            while (isspace(buf[i]) || buf[i] == '=') {
++                i++;
++            }
++            for (j = 0; j < pqg.subPrime.len; i += 2, j++) {
++                if (!isxdigit(buf[i])) {
++                    pqg.subPrime.len = j;
++                    break;
++                }
++                hex_to_byteval(&buf[i], &pqg.subPrime.data[j]);
++            }
++
++            fputs(buf, dhresp);
++            continue;
++        }
++
++        /* G = ... */
++        if (buf[0] == 'G') {
++            i = 1;
++            while (isspace(buf[i]) || buf[i] == '=') {
++                i++;
++            }
++            for (j = 0; j < pqg.base.len; i += 2, j++) {
++                if (!isxdigit(buf[i])) {
++                    pqg.base.len = j;
++                    break;
++                }
++                hex_to_byteval(&buf[i], &pqg.base.data[j]);
++            }
++
++            fputs(buf, dhresp);
++            continue;
++        }
++
++        /* COUNT = ... */
++        if (strncmp(buf, "COUNT", 5) == 0) {
++            fputs(buf, dhresp);
++            continue;
++        }
++
++        /* YephemCAVS = ... */
++        if (strncmp(buf, "YephemCAVS", 10) == 0) {
++            fputs(buf, dhresp);
++            i = 10;
++            while (isspace(buf[i]) || buf[i] == '=') {
++                i++;
++            }
++            from_hex_str(pubkeydata, pqg.prime.len, &buf[i]);
++            pubkey.data = pubkeydata;
++            pubkey.len = pqg.prime.len;
++
++            /* generate FCC key pair, nist uses pqg rather then pg,
++             * so use DSA to generate the key */
++            if (DSA_NewKey(&pqg, &dsapriv) != SECSuccess) {
++                fprintf(stderr,"Failed to generate new key\n");
++                goto loser;
++            }
++            fputs("XephemIUT = ", dhresp);
++            to_hex_str(buf, dsapriv->privateValue.data, dsapriv->privateValue.len);
++            fputs(buf, dhresp);
++            fputc('\n', dhresp);
++            fputs("YephemIUT = ", dhresp);
++            to_hex_str(buf, dsapriv->publicValue.data, dsapriv->publicValue.len);
++            fputs(buf, dhresp);
++            fputc('\n', dhresp);
++            /* DH */
++            if (DH_Derive(&pubkey,&pqg.prime, &dsapriv->privateValue,
++                        &ZZ, pqg.prime.len) != SECSuccess) {
++                fprintf(stderr,"Derive failed\n");
++                goto loser;
++            }
++            /* output hash of ZZ */
++            if (fips_hashBuf(hash, hashBuf, ZZ.data, ZZ.len) != SECSuccess ) {
++                fprintf(stderr,"hash of derived key failed\n");
++                goto loser;
++            }
++            SECITEM_FreeItem(&ZZ, PR_FALSE);
++            fputs("HashZZ = ", dhresp);
++            to_hex_str(buf, hashBuf, fips_hashLen(hash));
++            fputs(buf, dhresp);
++            fputc('\n', dhresp);
++            fputc('\n', dhresp);
++            PORT_FreeArena(dsapriv->params.arena, PR_TRUE);
++            dsapriv = NULL;
++            continue;
++        }
++    }
++loser:
++    if (dsapriv != NULL) {
++        PORT_FreeArena(dsapriv->params.arena, PR_TRUE);
++    }
++    fclose(dhreq);
++}
++
++#define MATCH_OPENSSL 1 
++/*
++ * Perform the DH Validity Test.
++ *
++ * reqfn is the pathname of the REQUEST file.
++ *
++ * The output RESPONSE file is written to stdout.
++ */
++void
++dh_verify(char *reqfn, PRBool response)
++{
++    char buf[1024];   /* holds one line from the input REQUEST file.
++                         * needs to be large enough to hold the longest
++                         * line "YephCAVS = <512 hex digits>\n".
++                         */
++    FILE *dhreq;  /* input stream from the REQUEST file */
++    FILE *dhresp; /* output stream to the RESPONSE file */
++    unsigned char hashBuf[HASH_LENGTH_MAX];
++    unsigned char cavsHashBuf[HASH_LENGTH_MAX];
++    PQGParams pqg = { 0 };
++    unsigned char pubkeydata[DSA_MAX_P_BITS/8];
++    unsigned char privkeydata[DSA_MAX_P_BITS/8];
++    SECItem pubkey;
++    SECItem privkey;
++    SECItem ZZ;
++    unsigned int i,j;
++    unsigned int pgySize;
++    HASH_HashType hash = HASH_AlgNULL; /* type of SHA Alg */
++
++    dhreq = fopen(reqfn, "r");
++    dhresp = stdout;
++    while (fgets(buf, sizeof buf, dhreq) != NULL) {
++        /* a comment or blank line */
++        if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') {
++            fputs(buf, dhresp);
++            continue;
++        }
++        if (buf[0] == '[') {
++            /* [Fx - SHAxxx] */
++            if (buf[1] == 'F' && buf[3] == ' ') {
++                const char *src;
++                /* skip passed the colon */
++                src = &buf[1];
++                while (*src && *src != '-') src++;
++                if (*src != '-') {
++                    fprintf(stderr, "No hash specified\n%s",buf);
++                    goto loser;
++                }
++                src++;
++                /* skip to the first non-space */
++                while (*src && *src == ' ') src++;
++                hash = hash_string_to_hashType(src);
++                if (hash == HASH_AlgNULL){
++                    fprintf(dhresp, "ERROR: Unable to find SHAAlg type");
++                    goto loser;
++                }
++                /* clear the PQG parameters */
++                if (pqg.prime.data) { /* P */
++                    SECITEM_ZfreeItem(&pqg.prime, PR_FALSE);
++                }
++                if (pqg.subPrime.data) { /* Q */
++                    SECITEM_ZfreeItem(&pqg.subPrime, PR_FALSE);
++                }
++                if (pqg.base.data) { /* G */
++                    SECITEM_ZfreeItem(&pqg.base, PR_FALSE);
++                }
++                pgySize = DSA_MAX_P_BITS / 8; /* change if more key sizes are supported in CAVS */
++                SECITEM_AllocItem(NULL, &pqg.prime, pgySize);
++                SECITEM_AllocItem(NULL, &pqg.base, pgySize);
++                pqg.prime.len = pqg.base.len = pgySize;
++
++                /* set q to the max allows */
++                SECITEM_AllocItem(NULL, &pqg.subPrime, DSA_MAX_Q_BITS/ 8);
++                pqg.subPrime.len = DSA_MAX_Q_BITS / 8;
++                fputs(buf, dhresp);
++                continue;
++            }
++            fputs(buf, dhresp);
++            continue;
++        }
++        if (buf[0] == 'P') {
++            i = 1;
++            while (isspace(buf[i]) || buf[i] == '=') {
++                i++;
++            }
++            for (j = 0; j < pqg.prime.len; i += 2, j++) {
++                if (!isxdigit(buf[i])) {
++                    pqg.prime.len = j;
++                    break;
++                }
++                hex_to_byteval(&buf[i], &pqg.prime.data[j]);
++            }
++
++            fputs(buf, dhresp);
++            continue;
++        }
++
++        /* Q = ... */
++        if (buf[0] == 'Q') {
++            i = 1;
++            while (isspace(buf[i]) || buf[i] == '=') {
++                i++;
++            }
++            for (j = 0; j < pqg.subPrime.len; i += 2, j++) {
++                if (!isxdigit(buf[i])) {
++                    pqg.subPrime.len = j;
++                    break;
++                }
++                hex_to_byteval(&buf[i], &pqg.subPrime.data[j]);
++            }
++
++            fputs(buf, dhresp);
++            continue;
++        }
++
++        /* G = ... */
++        if (buf[0] == 'G') {
++            i = 1;
++            while (isspace(buf[i]) || buf[i] == '=') {
++                i++;
++            }
++            for (j = 0; j < pqg.base.len; i += 2, j++) {
++                if (!isxdigit(buf[i])) {
++                    pqg.base.len = j;
++                    break;
++                }
++                hex_to_byteval(&buf[i], &pqg.base.data[j]);
++            }
++
++            fputs(buf, dhresp);
++            continue;
++        }
++
++        /* COUNT = ... */
++        if (strncmp(buf, "COUNT", 5) == 0) {
++            fputs(buf, dhresp);
++            continue;
++        }
++
++        /* YephemCAVS = ... */
++        if (strncmp(buf, "YephemCAVS", 10) == 0) {
++            fputs(buf, dhresp);
++            i = 10;
++            while (isspace(buf[i]) || buf[i] == '=') {
++                i++;
++            }
++            from_hex_str(pubkeydata, pqg.prime.len, &buf[i]);
++            pubkey.data = pubkeydata;
++            pubkey.len = pqg.prime.len;
++            continue;
++        }
++        /* XephemUIT = ... */
++        if (strncmp(buf, "XephemIUT", 9) == 0) {
++            fputs(buf, dhresp);
++            i = 9;
++            while (isspace(buf[i]) || buf[i] == '=') {
++                i++;
++            }
++            from_hex_str(privkeydata, pqg.subPrime.len, &buf[i]);
++            privkey.data = privkeydata;
++            privkey.len = pqg.subPrime.len;
++            continue;
++        }
++        /* YephemUIT = ... */
++        if (strncmp(buf, "YephemIUT", 9) == 0) {
++            fputs(buf, dhresp);
++            continue;
++        }
++        /* CAVSHashZZ = ... */
++        if (strncmp(buf, "CAVSHashZZ", 10) == 0) {
++            fputs(buf, dhresp);
++            i = 10;
++            while (isspace(buf[i]) || buf[i] == '=') {
++                i++;
++            }
++            from_hex_str(cavsHashBuf, fips_hashLen(hash), &buf[i]);
++            /* do the DH operation*/
++            if (DH_Derive(&pubkey,&pqg.prime, &privkey,
++                        &ZZ, pqg.prime.len) != SECSuccess) {
++                fprintf(stderr,"Derive failed\n");
++                goto loser;
++            }
++            /* output  ZZ */
++#ifndef MATCH_OPENSSL
++            fputs("Z = ", dhresp);
++            to_hex_str(buf, ZZ.data, ZZ.len);
++            fputs(buf, dhresp);
++            fputc('\n', dhresp);
++#endif
++            if (fips_hashBuf(hash, hashBuf, ZZ.data, ZZ.len) != SECSuccess ) {
++                fprintf(stderr,"hash of derived key failed\n");
++                goto loser;
++            }
++            SECITEM_FreeItem(&ZZ, PR_FALSE);
++#ifndef MATCH_NIST_
++            fputs("IUTHashZZ = ", dhresp);
++            to_hex_str(buf, hashBuf, fips_hashLen(hash));
++            fputs(buf, dhresp);
++            fputc('\n', dhresp);
++#endif
++            if (memcmp(hashBuf, cavsHashBuf, fips_hashLen(hash)) != 0) {
++		fprintf(dhresp, "Result = F\n");
++            } else {
++		fprintf(dhresp, "Result = P\n");
++            }
++#ifndef MATCH_OPENSSL
++            fputc('\n', dhresp);
++#endif
++            continue;
++        }
++    }
++loser:
++    fclose(dhreq);
++}
++
+ PRBool
+ isblankline(char *b)
+ {
+     while (isspace(*b))
+         b++;
+     if ((*b == '\n') || (*b == 0)) {
+         return PR_TRUE;
+     }
+@@ -5337,27 +6263,18 @@ rsa_siggen_test(char *reqfn)
+ 
+         /* SHAAlg = ... */
+         if (strncmp(buf, "SHAAlg", 6) == 0) {
+             i = 6;
+             while (isspace(buf[i]) || buf[i] == '=') {
+                 i++;
+             }
+             /* set the SHA Algorithm */
+-            if (strncmp(&buf[i], "SHA1", 4) == 0) {
+-                shaAlg = HASH_AlgSHA1;
+-            } else if (strncmp(&buf[i], "SHA224", 6) == 0) {
+-                shaAlg = HASH_AlgSHA224;
+-            } else if (strncmp(&buf[i], "SHA256", 6) == 0) {
+-                shaAlg = HASH_AlgSHA256;
+-            } else if (strncmp(&buf[i], "SHA384", 6) == 0) {
+-                shaAlg = HASH_AlgSHA384;
+-            } else if (strncmp(&buf[i], "SHA512", 6) == 0) {
+-                shaAlg = HASH_AlgSHA512;
+-            } else {
++            shaAlg = hash_string_to_hashType(&buf[i]);
++            if (shaAlg == HASH_AlgNULL) {
+                 fprintf(rsaresp, "ERROR: Unable to find SHAAlg type");
+                 goto loser;
+             }
+             fputs(buf, rsaresp);
+             continue;
+         }
+         /* Msg = ... */
+         if (strncmp(buf, "Msg", 3) == 0) {
+@@ -5532,27 +6449,18 @@ rsa_sigver_test(char *reqfn)
+ 
+         /* SHAAlg = ... */
+         if (strncmp(buf, "SHAAlg", 6) == 0) {
+             i = 6;
+             while (isspace(buf[i]) || buf[i] == '=') {
+                 i++;
+             }
+             /* set the SHA Algorithm */
+-            if (strncmp(&buf[i], "SHA1", 4) == 0) {
+-                shaAlg = HASH_AlgSHA1;
+-            } else if (strncmp(&buf[i], "SHA224", 6) == 0) {
+-                shaAlg = HASH_AlgSHA224;
+-            } else if (strncmp(&buf[i], "SHA256", 6) == 0) {
+-                shaAlg = HASH_AlgSHA256;
+-            } else if (strncmp(&buf[i], "SHA384", 6) == 0) {
+-                shaAlg = HASH_AlgSHA384;
+-            } else if (strncmp(&buf[i], "SHA512", 6) == 0) {
+-                shaAlg = HASH_AlgSHA512;
+-            } else {
++            shaAlg = hash_string_to_hashType(&buf[i]);
++            if (shaAlg == HASH_AlgNULL) {
+                 fprintf(rsaresp, "ERROR: Unable to find SHAAlg type");
+                 goto loser;
+             }
+             fputs(buf, rsaresp);
+             continue;
+         }
+ 
+         /* e = ... public Key */
+@@ -6103,16 +7011,44 @@ main(int argc, char **argv)
+         } else if (strcmp(argv[2], "siggen") == 0) {
+             /* Signature Generation Test */
+             ecdsa_siggen_test(argv[3]);
+         } else if (strcmp(argv[2], "sigver") == 0) {
+             /* Signature Verification Test */
+             ecdsa_sigver_test(argv[3]);
+         }
+         /*************/
++        /*   ECDH   */
++        /*************/
++    } else if (strcmp(argv[1], "ecdh") == 0) {
++        /* argv[2]={init|resp}-{func|verify} argv[3]=<test name>.req */
++        if (strcmp(argv[2], "init-func") == 0) {
++            ecdh_functional(argv[3], 0);
++        } else if (strcmp(argv[2], "resp-func") == 0) {
++            ecdh_functional(argv[3], 1);
++        } else if (strcmp(argv[2], "init-verify") == 0) {
++            ecdh_verify(argv[3], 0);
++        } else if (strcmp(argv[2], "resp-verify") == 0) {
++            ecdh_verify(argv[3], 1);
++        }
++        /*************/
++        /*   DH   */
++        /*************/
++    } else if (strcmp(argv[1], "dh") == 0) {
++        /* argv[2]={init|resp}-{func|verify} argv[3]=<test name>.req */
++        if (strcmp(argv[2], "init-func") == 0) {
++            dh_functional(argv[3], 0);
++        } else if (strcmp(argv[2], "resp-func") == 0) {
++            dh_functional(argv[3], 1);
++        } else if (strcmp(argv[2], "init-verify") == 0) {
++            dh_verify(argv[3], 0);
++        } else if (strcmp(argv[2], "resp-verify") == 0) {
++            dh_verify(argv[3], 1);
++        }
++        /*************/
+         /*   RNG     */
+         /*************/
+     } else if (strcmp(argv[1], "rng") == 0) {
+         /* argv[2]=vst|mct argv[3]=<test name>.req */
+         if (strcmp(argv[2], "vst") == 0) {
+             /* Variable Seed Test */
+             rng_vst(argv[3]);
+         } else if (strcmp(argv[2], "mct") == 0) {
+diff --git a/cmd/fipstest/kas.sh b/cmd/fipstest/kas.sh
+new file mode 100755
+--- /dev/null
++++ b/cmd/fipstest/kas.sh
+@@ -0,0 +1,84 @@
++#!/bin/sh
++# 
++# 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/.
++#
++# A Bourne shell script for running the NIST DSA Validation System
++#
++# Before you run the script, set your PATH, LD_LIBRARY_PATH, ... environment
++# variables appropriately so that the fipstest command and the NSPR and NSS
++# shared libraries/DLLs are on the search path.  Then run this script in the
++# directory where the REQUEST (.req) files reside.  The script generates the
++# RESPONSE (.rsp) files in the same directory.
++BASEDIR=${1-.}
++TESTDIR=${BASEDIR}/KAS
++COMMAND=${2-run}
++REQDIR=${TESTDIR}/req
++RSPDIR=${TESTDIR}/resp
++
++
++#
++if [ ${COMMAND} = "verify" ]; then
++#
++# need verify for KAS tests
++
++# verify generated keys
++#    name=KeyPair
++#    echo ">>>>>  $name"
++#    fipstest dsa keyver ${RSPDIR}/$name.rsp | grep ^Result.=.F
++# verify generated pqg values
++#    name=PQGGen
++#    echo ">>>>>  $name"
++#    fipstest dsa pqgver ${RSPDIR}/$name.rsp | grep ^Result.=.F
++# verify PQGVer with known answer
++#    sh ./validate1.sh ${TESTDIR} PQGVer.req ' ' '-e /^Result.=.F/s;.(.*);; -e /^Result.=.P/s;.(.*);;'
++# verify signatures
++#    name=SigGen
++#    echo ">>>>>  $name"
++#    fipstest dsa sigver ${RSPDIR}/$name.rsp | grep ^Result.=.F
++# verify SigVer with known answer
++#    sh ./validate1.sh ${TESTDIR} SigVer.req ' ' '-e /^X.=/d -e /^Result.=.F/s;.(.*);;'
++    exit 0
++fi
++
++request=KASFunctionTest_ECCEphemeralUnified_NOKC_ZZOnly_init.req
++response=`echo $request | sed -e "s/req/rsp/"`
++echo $request $response
++fipstest ecdh init-func ${REQDIR}/$request > ${RSPDIR}/$response
++
++request=KASFunctionTest_ECCEphemeralUnified_NOKC_ZZOnly_resp.req
++response=`echo $request | sed -e "s/req/rsp/"`
++echo $request $response
++fipstest ecdh resp-func ${REQDIR}/$request > ${RSPDIR}/$response
++
++request=KASValidityTest_ECCEphemeralUnified_NOKC_ZZOnly_init.req
++response=`echo $request | sed -e "s/req/rsp/"`
++echo $request $response
++fipstest ecdh init-verify ${REQDIR}/$request > ${RSPDIR}/$response
++
++request=KASValidityTest_ECCEphemeralUnified_NOKC_ZZOnly_resp.req
++response=`echo $request | sed -e "s/req/rsp/"`
++echo $request $response
++fipstest ecdh resp-verify ${REQDIR}/$request > ${RSPDIR}/$response
++
++request=KASFunctionTest_FFCEphem_NOKC_ZZOnly_init.req
++response=`echo $request | sed -e "s/req/rsp/"`
++echo $request $response
++fipstest dh init-func ${REQDIR}/$request > ${RSPDIR}/$response
++
++request=KASFunctionTest_FFCEphem_NOKC_ZZOnly_resp.req
++response=`echo $request | sed -e "s/req/rsp/"`
++echo $request $response
++fipstest dh resp-func ${REQDIR}/$request > ${RSPDIR}/$response
++
++request=KASValidityTest_FFCEphem_NOKC_ZZOnly_init.req
++response=`echo $request | sed -e "s/req/rsp/"`
++echo $request $response
++fipstest dh init-verify ${REQDIR}/$request > ${RSPDIR}/$response
++
++request=KASValidityTest_FFCEphem_NOKC_ZZOnly_resp.req
++response=`echo $request | sed -e "s/req/rsp/"`
++echo $request $response
++fipstest dh resp-verify ${REQDIR}/$request > ${RSPDIR}/$response
++
+diff --git a/cmd/fipstest/runtest.sh b/cmd/fipstest/runtest.sh
+--- a/cmd/fipstest/runtest.sh
++++ b/cmd/fipstest/runtest.sh
+@@ -1,14 +1,14 @@
+ #!/bin/sh
+ # 
+ # 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/.
+ #
+ TESTDIR=${1-.}
+ COMMAND=${2-run}
+-TESTS="aes aesgcm dsa ecdsa hmac tls rng rsa sha tdea"
++TESTS="aes aesgcm dsa ecdsa hmac kas tls rng rsa sha tdea"
+ for i in $TESTS
+ do
+     echo "********************Running $i tests"
+     sh ./${i}.sh ${TESTDIR} ${COMMAND}
+ done
diff --git a/SOURCES/nss-softokn-aes-zeroize.patch b/SOURCES/nss-softokn-aes-zeroize.patch
new file mode 100644
index 0000000..1605470
--- /dev/null
+++ b/SOURCES/nss-softokn-aes-zeroize.patch
@@ -0,0 +1,51 @@
+diff --git a/lib/freebl/intel-gcm-wrap.c b/lib/freebl/intel-gcm-wrap.c
+--- a/lib/freebl/intel-gcm-wrap.c
++++ b/lib/freebl/intel-gcm-wrap.c
+@@ -138,16 +138,17 @@ intel_AES_GCM_CreateContext(void *contex
+ loser:
+     PORT_Free(gcm);
+     return NULL;
+ }
+ 
+ void
+ intel_AES_GCM_DestroyContext(intel_AES_GCMContext *gcm, PRBool freeit)
+ {
++    PORT_Memset(gcm, 0, sizeof(intel_AES_GCMContext));
+     if (freeit) {
+         PORT_Free(gcm);
+     }
+ }
+ 
+ SECStatus
+ intel_AES_GCM_EncryptUpdate(intel_AES_GCMContext *gcm,
+                             unsigned char *outbuf,
+diff --git a/lib/freebl/rijndael.c b/lib/freebl/rijndael.c
+--- a/lib/freebl/rijndael.c
++++ b/lib/freebl/rijndael.c
+@@ -1027,23 +1027,25 @@ AES_CreateContext(const unsigned char *k
+  * AES_DestroyContext
+  *
+  * Zero an AES cipher context.  If freeit is true, also free the pointer
+  * to the context.
+  */
+ void
+ AES_DestroyContext(AESContext *cx, PRBool freeit)
+ {
++    void *mem = cx->mem;
+     if (cx->worker_cx && cx->destroy) {
+         (*cx->destroy)(cx->worker_cx, PR_TRUE);
+         cx->worker_cx = NULL;
+         cx->destroy = NULL;
+     }
++    PORT_Memset(cx, 0, sizeof(AESContext));
+     if (freeit) {
+-        PORT_Free(cx->mem);
++        PORT_Free(mem);
+     }
+ }
+ 
+ /*
+  * AES_Encrypt
+  *
+  * Encrypt an arbitrary-length buffer.  The output buffer must already be
+  * allocated to at least inputLen.
diff --git a/SOURCES/nss-softokn-fix-ecc-post.patch b/SOURCES/nss-softokn-fix-ecc-post.patch
deleted file mode 100644
index 3fe1836..0000000
--- a/SOURCES/nss-softokn-fix-ecc-post.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-diff -up ./nss/lib/freebl/fipsfreebl.c.ecc_post ./nss/lib/freebl/fipsfreebl.c
---- ./nss/lib/freebl/fipsfreebl.c.ecc_post	2017-07-21 18:33:27.946809392 -0700
-+++ ./nss/lib/freebl/fipsfreebl.c	2017-07-21 18:34:09.065510689 -0700
-@@ -15,9 +15,7 @@
- #include "secerr.h"
- #include "prtypes.h"
- 
--#ifdef NSS_ENABLE_ECC
- #include "ec.h" /* Required for ECDSA */
--#endif
- 
- /*
-  * different platforms have different ways of calling and initial entry point
-@@ -1077,7 +1075,6 @@ rsa_loser:
-     return (SECFailure);
- }
- 
--#ifdef NSS_ENABLE_ECC
- 
- static SECStatus
- freebl_fips_ECDSA_Test(ECParams *ecparams,
-@@ -1275,8 +1272,6 @@ freebl_fips_ECDSA_PowerUpSelfTest()
-     return (SECSuccess);
- }
- 
--#endif /* NSS_ENABLE_ECC */
--
- static SECStatus
- freebl_fips_DSA_PowerUpSelfTest(void)
- {
-@@ -1559,13 +1554,11 @@ freebl_fipsPowerUpSelfTest(unsigned int
-         if (rv != SECSuccess)
-             return rv;
- 
--#ifdef NSS_ENABLE_ECC
-         /* ECDSA Power-Up SelfTest(s). */
-         rv = freebl_fips_ECDSA_PowerUpSelfTest();
- 
-         if (rv != SECSuccess)
-             return rv;
--#endif
-     }
-     /* Passed Power-Up SelfTest(s). */
-     return (SECSuccess);
diff --git a/SOURCES/nss-softokn-fs-probe.patch b/SOURCES/nss-softokn-fs-probe.patch
new file mode 100644
index 0000000..a070bae
--- /dev/null
+++ b/SOURCES/nss-softokn-fs-probe.patch
@@ -0,0 +1,79 @@
+# HG changeset patch
+# User David Keeler <dkeeler@mozilla.com>
+# Date 1500978196 -7200
+#      Tue Jul 25 12:23:16 2017 +0200
+# Node ID 9c94423e0669decabbb22b0d52ce31115c750265
+# Parent  f212be04f3d0265340bf5ae20ffbbccdda68b0aa
+bug 1382736 - Don't perform costly filesystem probes at startup r=ttaubert
+
+Differential Revision: https://nss-review.dev.mozaws.net/D374
+
+diff --git a/lib/softoken/sdb.c b/lib/softoken/sdb.c
+--- a/lib/softoken/sdb.c
++++ b/lib/softoken/sdb.c
+@@ -1866,30 +1866,29 @@ sdb_init(char *dbname, char *table, sdbD
+      * so we use it for the cache (see sdb_buildCache for how it's done).*/
+ 
+     /*
+-      * we decide whether or not to use the cache based on the following input.
+-      *
+-      * NSS_SDB_USE_CACHE environment variable is non-existant or set to
+-      *   anything other than "no" or "yes" ("auto", for instance).
+-      *   This is the normal case. NSS will measure the performance of access
+-      *   to the temp database versus the access to the users passed in
+-      *   database location. If the temp database location is "significantly"
+-      *   faster we will use the cache.
+-      *
+-      * NSS_SDB_USE_CACHE environment variable is set to "no": cache will not
+-      *   be used.
+-      *
+-      * NSS_SDB_USE_CACHE environment variable is set to "yes": cache will
+-      *   always be used.
+-      *
+-      * It is expected that most applications would use the "auto" selection,
+-      * the environment variable is primarily to simplify testing, and to
+-      * correct potential corner cases where  */
++     * we decide whether or not to use the cache based on the following input.
++     *
++     * NSS_SDB_USE_CACHE environment variable is set to anything other than
++     *   "yes" or "no" (for instance, "auto"): NSS will measure the performance
++     *   of access to the temp database versus the access to the user's
++     *   passed-in database location. If the temp database location is
++     *   "significantly" faster we will use the cache.
++     *
++     * NSS_SDB_USE_CACHE environment variable is nonexistent or set to "no":
++     *   cache will not be used.
++     *
++     * NSS_SDB_USE_CACHE environment variable is set to "yes": cache will
++     *   always be used.
++     *
++     * It is expected that most applications will not need this feature, and
++     * thus it is disabled by default.
++     */
+ 
+     env = PR_GetEnvSecure("NSS_SDB_USE_CACHE");
+ 
+-    if (env && PORT_Strcasecmp(env, "no") == 0) {
++    if (!env || PORT_Strcasecmp(env, "no") == 0) {
+         enableCache = PR_FALSE;
+-    } else if (env && PORT_Strcasecmp(env, "yes") == 0) {
++    } else if (PORT_Strcasecmp(env, "yes") == 0) {
+         enableCache = PR_TRUE;
+     } else {
+         char *tempDir = NULL;
+@@ -2035,10 +2034,11 @@ s_open(const char *directory, const char
+     {
+         char *env;
+         env = PR_GetEnvSecure("NSS_SDB_USE_CACHE");
+-        /* If the environment variable is set to yes or no, sdb_init() will
+-         * ignore the value of accessOps, and we can skip the measuring.*/
+-        if (!env || ((PORT_Strcasecmp(env, "no") != 0) &&
+-                     (PORT_Strcasecmp(env, "yes") != 0))) {
++        /* If the environment variable is undefined or set to yes or no,
++         * sdb_init() will ignore the value of accessOps, and we can skip the
++         * measuring.*/
++        if (env && PORT_Strcasecmp(env, "no") != 0 &&
++            PORT_Strcasecmp(env, "yes") != 0) {
+             accessOps = sdb_measureAccess(directory);
+         }
+     }
diff --git a/SPECS/nss-softokn.spec b/SPECS/nss-softokn.spec
index c6d5557..e598ef8 100644
--- a/SPECS/nss-softokn.spec
+++ b/SPECS/nss-softokn.spec
@@ -1,7 +1,7 @@
-%global nspr_version 4.17.0
+%global nspr_version 4.19.0
 %global nss_name nss
-%global nss_util_version 3.34.0
-%global nss_util_build -2
+%global nss_util_version 3.36.0
+%global nss_util_build -1
 %global unsupported_tools_directory %{_libdir}/nss/unsupported-tools
 %global saved_files_dir %{_libdir}/nss/saved
 %global prelink_conf_dir %{_sysconfdir}/prelink.conf.d/
@@ -31,8 +31,8 @@
 
 Summary:          Network Security Services Softoken Module
 Name:             nss-softokn
-Version:          3.34.0
-Release:          2%{?dist}
+Version:          3.36.0
+Release:          5%{?dist}
 License:          MPLv2.0
 URL:              http://www.mozilla.org/projects/security/pki/nss/
 Group:            System Environment/Libraries
@@ -77,12 +77,23 @@ Source6:	  nss-softokn-dracut.conf
 # Once has been bootstapped the patch may be removed, but it doesn't hurt to keep it.
 Patch10:           iquote.patch
 
+# Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=1236720
+# Although the greater part of the patch has been upstreamed, we still
+# need a downstream patch to keep the single DES mechanisms we had
+# provided in a downstream patch for compatibility reasons.
 Patch97:	   nss-softokn-3.16-add_encrypt_derive.patch
 
 Patch102:          nss-softokn-tls-abi-fix.patch
-# Not upstreamed: https://bugzilla.redhat.com/show_bug.cgi?id=1390154
-Patch105:	   nss-softokn-3.28-fix-fips-login.patch
-Patch107:	   nss-softokn-fix-ecc-post.patch
+
+# Not upstreamed: https://bugzilla.redhat.com/show_bug.cgi?id=1548394
+Patch103:	   nss-softokn-add-kas-tests.patch
+
+# To revert the upstream change in the default behavior in:
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1382736
+Patch104:	   nss-softokn-fs-probe.patch
+
+# Not upstreamed: https://bugzilla.redhat.com/show_bug.cgi?id=1555108
+Patch105:	   nss-softokn-aes-zeroize.patch
 
 %description
 Network Security Services Softoken Cryptographic Module
@@ -139,11 +150,14 @@ Header and library files for doing development with Network Security Services.
 # activate if needed when doing a major update with new apis
 #%patch10 -p0 -b .iquote
 
-%patch97 -p0 -b .add_encrypt_derive
+pushd nss
+%patch97 -p1 -b .add_encrypt_derive
+%patch103 -p1 -b .add-kas-tests
+%patch104 -p1 -R -b .fs-probe
+%patch105 -p1 -b .aes-zeroize
+popd
 
 %patch102 -p1 -b .tls-abi-fix
-%patch105 -p1 -b .fix-fips-login
-%patch107 -p1 -b .ecc_post
 
 %build
 
@@ -469,6 +483,34 @@ done
 %{_includedir}/nss3/shsign.h
 
 %changelog
+* Mon Mar 19 2018 Daiki Ueno <dueno@redhat.com> - 3.36.0-5
+- Use correct tarball of NSS 3.36.0 release
+
+* Thu Mar 15 2018 Bob Relyea <rrelyea@redhat.com> - 3.36.0-4
+- Clear AES key information after use
+
+* Wed Mar  7 2018 Daiki Ueno <dueno@redhat.com> - 3.36.0-3
+- Revert the default behavior change in filesystem probes
+
+* Wed Mar  7 2018 Bob Relyea <rrelyea@redhat.com> - 3.36.0-2
+- Add KAS tests to fipstest
+
+* Mon Mar  5 2018 Daiki Ueno <dueno@redhat.com> - 3.36.0-1
+- Update to NSS 3.36.0
+
+* Mon Mar  5 2018 Daiki Ueno <dueno@redhat.com> - 3.36.0-0.3.beta
+- Apply upstream patch likely to be part of the official release
+
+* Thu Mar  1 2018 Daiki Ueno <dueno@redhat.com> - 3.36.0-0.2.beta
+- Restore nss-softokn-3.16-add_encrypt_derive.patch to add back
+  support for single DES mechanisms
+
+* Thu Mar  1 2018 Daiki Ueno <dueno@redhat.com> - 3.36.0-0.1.beta
+- Update to NSS 3.36 BETA
+- Remove upstreamed nss-softokn-3.16-add_encrypt_derive.patch
+- Remove upstreamed nss-softokn-3.28-fix-fips-login.patch
+- Remove upstreamed nss-softokn-fix-ecc-post.patch
+
 * Tue Jan 16 2018 Daiki Ueno <dueno@redhat.com> - 3.34.0-2
 - Rebuild to utilize ECC slotFlag added in nss-util