0c41dc
diff --git a/lib/freebl/config.mk b/lib/freebl/config.mk
0c41dc
--- a/lib/freebl/config.mk
0c41dc
+++ b/lib/freebl/config.mk
0c41dc
@@ -85,9 +85,13 @@ EXTRA_SHARED_LIBS += \
0c41dc
 	$(NULL)
0c41dc
 endif
0c41dc
 endif
0c41dc
 
0c41dc
 ifeq ($(OS_ARCH), Darwin)
0c41dc
 EXTRA_SHARED_LIBS += -dylib_file @executable_path/libplc4.dylib:$(DIST)/lib/libplc4.dylib -dylib_file @executable_path/libplds4.dylib:$(DIST)/lib/libplds4.dylib
0c41dc
 endif
0c41dc
 
0c41dc
+ifdef NSS_FIPS_140_3
0c41dc
+DEFINES += -DNSS_FIPS_140_3
0c41dc
 endif
0c41dc
+
0c41dc
+endif
0c41dc
diff --git a/lib/freebl/unix_urandom.c b/lib/freebl/unix_urandom.c
0c41dc
--- a/lib/freebl/unix_urandom.c
0c41dc
+++ b/lib/freebl/unix_urandom.c
0c41dc
@@ -20,53 +20,110 @@ RNG_SystemInfoForRNG(void)
0c41dc
     if (!numBytes) {
0c41dc
         /* error is set */
0c41dc
         return;
0c41dc
     }
0c41dc
     RNG_RandomUpdate(bytes, numBytes);
0c41dc
     PORT_Memset(bytes, 0, sizeof bytes);
0c41dc
 }
0c41dc
 
0c41dc
+#ifdef NSS_FIPS_140_3
0c41dc
+#include <sys/random.h>
0c41dc
+#include "prinit.h"
0c41dc
+
0c41dc
+static int rng_grndFlags= 0;
0c41dc
+static PRCallOnceType rng_KernelFips;
0c41dc
+
0c41dc
+static PRStatus
0c41dc
+rng_getKernelFips()
0c41dc
+{
0c41dc
+#ifdef LINUX
0c41dc
+    FILE *f;
0c41dc
+    char d;
0c41dc
+    size_t size;
0c41dc
+
0c41dc
+    f = fopen("/proc/sys/crypto/fips_enabled", "r");
0c41dc
+    if (!f)
0c41dc
+        return PR_FAILURE;
0c41dc
+
0c41dc
+    size = fread(&d, 1, 1, f);
0c41dc
+    fclose(f);
0c41dc
+    if (size != 1)
0c41dc
+        return PR_SUCCESS;
0c41dc
+    if (d != '1')
0c41dc
+        return PR_SUCCESS;
0c41dc
+    /* if the kernel is in FIPS mode, set the GRND_RANDOM flag */
0c41dc
+    rng_grndFlags = GRND_RANDOM;
0c41dc
+#endif /* LINUX */
0c41dc
+    return PR_SUCCESS;
0c41dc
+}
0c41dc
+#endif
0c41dc
+
0c41dc
 size_t
0c41dc
 RNG_SystemRNG(void *dest, size_t maxLen)
0c41dc
 {
0c41dc
+    size_t fileBytes = 0;
0c41dc
+    unsigned char *buffer = dest;
0c41dc
+#ifndef NSS_FIPS_140_3
0c41dc
     int fd;
0c41dc
     int bytes;
0c41dc
-    size_t fileBytes = 0;
0c41dc
-    unsigned char *buffer = dest;
0c41dc
+#else
0c41dc
+    PR_CallOnce(&rng_KernelFips, rng_getKernelFips);
0c41dc
+#endif
0c41dc
 
0c41dc
 #if defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD_version >= 1200000) || (defined(LINUX) && defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 25))))
0c41dc
     int result;
0c41dc
-
0c41dc
     while (fileBytes < maxLen) {
0c41dc
         size_t getBytes = maxLen - fileBytes;
0c41dc
         if (getBytes > GETENTROPY_MAX_BYTES) {
0c41dc
             getBytes = GETENTROPY_MAX_BYTES;
0c41dc
         }
0c41dc
+#ifdef NSS_FIPS_140_3
0c41dc
+        /* FIP 140-3 requires full kernel reseeding for chained entropy sources
0c41dc
+         * so we need to use getrandom with GRND_RANDOM.
0c41dc
+         * getrandom returns -1 on failure, otherwise returns
0c41dc
+         * the number of bytes, which can be less than getBytes */
0c41dc
+        result = getrandom(buffer, getBytes, rng_grndFlags);
0c41dc
+        if (result < 0) {
0c41dc
+            break;
0c41dc
+        }
0c41dc
+        fileBytes += result;
0c41dc
+        buffer += result;
0c41dc
+#else
0c41dc
+        /* get entropy returns 0 on success and always return
0c41dc
+         * getBytes on success */
0c41dc
         result = getentropy(buffer, getBytes);
0c41dc
         if (result == 0) { /* success */
0c41dc
             fileBytes += getBytes;
0c41dc
             buffer += getBytes;
0c41dc
         } else {
0c41dc
             break;
0c41dc
         }
0c41dc
+#endif
0c41dc
     }
0c41dc
     if (fileBytes == maxLen) { /* success */
0c41dc
         return maxLen;
0c41dc
     }
0c41dc
+#ifdef NSS_FIPS_140_3
0c41dc
+    /* in FIPS 104-3 we don't fallback, just fail */
0c41dc
+    PORT_SetError(SEC_ERROR_NEED_RANDOM);
0c41dc
+    return 0;
0c41dc
+#else
0c41dc
     /* If we failed with an error other than ENOSYS, it means the destination
0c41dc
      * buffer is not writeable. We don't need to try writing to it again. */
0c41dc
     if (errno != ENOSYS) {
0c41dc
         PORT_SetError(SEC_ERROR_NEED_RANDOM);
0c41dc
         return 0;
0c41dc
     }
0c41dc
+#endif /*!NSS_FIPS_140_3 */
0c41dc
+#endif /* platorm has getentropy */
0c41dc
+#ifndef NSS_FIPS_140_3
0c41dc
     /* ENOSYS means the kernel doesn't support getentropy()/getrandom().
0c41dc
      * Reset the number of bytes to get and fall back to /dev/urandom. */
0c41dc
     fileBytes = 0;
0c41dc
-#endif
0c41dc
     fd = open("/dev/urandom", O_RDONLY);
0c41dc
     if (fd < 0) {
0c41dc
         PORT_SetError(SEC_ERROR_NEED_RANDOM);
0c41dc
         return 0;
0c41dc
     }
0c41dc
     while (fileBytes < maxLen) {
0c41dc
         bytes = read(fd, buffer, maxLen - fileBytes);
0c41dc
         if (bytes <= 0) {
0c41dc
@@ -76,9 +133,10 @@ RNG_SystemRNG(void *dest, size_t maxLen)
0c41dc
         buffer += bytes;
0c41dc
     }
0c41dc
     (void)close(fd);
0c41dc
     if (fileBytes != maxLen) {
0c41dc
         PORT_SetError(SEC_ERROR_NEED_RANDOM);
0c41dc
         return 0;
0c41dc
     }
0c41dc
     return fileBytes;
0c41dc
+#endif
0c41dc
 }
0c41dc
diff --git a/lib/softoken/config.mk b/lib/softoken/config.mk
0c41dc
--- a/lib/softoken/config.mk
0c41dc
+++ b/lib/softoken/config.mk
0c41dc
@@ -58,8 +58,12 @@ endif
0c41dc
 ifdef NSS_ENABLE_FIPS_INDICATORS
0c41dc
 DEFINES += -DNSS_ENABLE_FIPS_INDICATORS
0c41dc
 endif
0c41dc
 
0c41dc
 ifdef NSS_FIPS_MODULE_ID
0c41dc
 DEFINES += -DNSS_FIPS_MODULE_ID=\"${NSS_FIPS_MODULE_ID}\"
0c41dc
 endif
0c41dc
 
0c41dc
+ifdef NSS_FIPS_140_3
0c41dc
+DEFINES += -DNSS_FIPS_140_3
0c41dc
+endif
0c41dc
+
0c41dc
diff --git a/lib/softoken/lowpbe.c b/lib/softoken/lowpbe.c
0c41dc
--- a/lib/softoken/lowpbe.c
0c41dc
+++ b/lib/softoken/lowpbe.c
0c41dc
@@ -1766,16 +1766,20 @@ sftk_fips_pbkdf_PowerUpSelfTests(void)
0c41dc
     unsigned char iteration_count = 5;
0c41dc
     unsigned char keyLen = 64;
0c41dc
     char *inKeyData = TEST_KEY;
0c41dc
-    static const unsigned char saltData[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
0c41dc
+    static const unsigned char saltData[] = {
0c41dc
+        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0c41dc
+        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
0c41dc
+    };
0c41dc
+
0c41dc
     static const unsigned char pbkdf_known_answer[] = {
0c41dc
-        0x31, 0xf0, 0xe5, 0x39, 0x9f, 0x39, 0xb9, 0x29,
0c41dc
-        0x68, 0xac, 0xf2, 0xe9, 0x53, 0x9b, 0xb4, 0x9c,
0c41dc
-        0x28, 0x59, 0x8b, 0x5c, 0xd8, 0xd4, 0x02, 0x37,
0c41dc
-        0x18, 0x22, 0xc1, 0x92, 0xd0, 0xfa, 0x72, 0x90,
0c41dc
-        0x2c, 0x8d, 0x19, 0xd4, 0x56, 0xfb, 0x16, 0xfa,
0c41dc
-        0x8d, 0x5c, 0x06, 0x33, 0xd1, 0x5f, 0x17, 0xb1,
0c41dc
-        0x22, 0xd9, 0x9c, 0xaf, 0x5e, 0x3f, 0xf3, 0x66,
0c41dc
-        0xc6, 0x14, 0xfe, 0x83, 0xfa, 0x1a, 0x2a, 0xc5
0c41dc
+        0x73, 0x8c, 0xfa, 0x02, 0xe8, 0xdb, 0x43, 0xe4,
0c41dc
+        0x99, 0xc5, 0xfd, 0xd9, 0x4d, 0x8e, 0x3e, 0x7b,
0c41dc
+        0xc4, 0xda, 0x22, 0x1b, 0xe1, 0xae, 0x23, 0x7a,
0c41dc
+        0x21, 0x27, 0xbd, 0xcc, 0x78, 0xc4, 0xe6, 0xc5,
0c41dc
+        0x33, 0x38, 0x35, 0xe0, 0x68, 0x1a, 0x1e, 0x06,
0c41dc
+        0xad, 0xaf, 0x7f, 0xd7, 0x3f, 0x0e, 0xc0, 0x90,
0c41dc
+        0x17, 0x97, 0x73, 0x75, 0x7b, 0x88, 0x49, 0xd8,
0c41dc
+        0x6f, 0x78, 0x5a, 0xde, 0x50, 0x20, 0x55, 0x33
0c41dc
     };
0c41dc
0c41dc
     sftk_PBELockInit();
0c41dc
diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
0c41dc
--- a/lib/softoken/pkcs11c.c
0c41dc
+++ b/lib/softoken/pkcs11c.c
0c41dc
@@ -4609,16 +4609,17 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSessi
0c41dc
         goto loser;
0c41dc
     }
0c41dc
 
0c41dc
     /* make sure we don't have any class, key_type, or value fields */
0c41dc
     sftk_DeleteAttributeType(key, CKA_CLASS);
0c41dc
     sftk_DeleteAttributeType(key, CKA_KEY_TYPE);
0c41dc
     sftk_DeleteAttributeType(key, CKA_VALUE);
0c41dc
 
0c41dc
+
0c41dc
     /* Now Set up the parameters to generate the key (based on mechanism) */
0c41dc
     key_gen_type = nsc_bulk; /* bulk key by default */
0c41dc
     switch (pMechanism->mechanism) {
0c41dc
         case CKM_CDMF_KEY_GEN:
0c41dc
         case CKM_DES_KEY_GEN:
0c41dc
         case CKM_DES2_KEY_GEN:
0c41dc
         case CKM_DES3_KEY_GEN:
0c41dc
             checkWeak = PR_TRUE;
0c41dc
@@ -4812,16 +4813,19 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSessi
0c41dc
     crv = sftk_handleObject(key, session);
0c41dc
     sftk_FreeSession(session);
0c41dc
     if (crv == CKR_OK && sftk_isTrue(key, CKA_SENSITIVE)) {
0c41dc
         crv = sftk_forceAttribute(key, CKA_ALWAYS_SENSITIVE, &cktrue, sizeof(CK_BBOOL));
0c41dc
     }
0c41dc
     if (crv == CKR_OK && !sftk_isTrue(key, CKA_EXTRACTABLE)) {
0c41dc
         crv = sftk_forceAttribute(key, CKA_NEVER_EXTRACTABLE, &cktrue, sizeof(CK_BBOOL));
0c41dc
     }
0c41dc
+    /* we need to do this check at the end, so we can check the generated key length against
0c41dc
+     * fips requirements */
0c41dc
+    key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_NSS_GENERATE, key);
0c41dc
     if (crv == CKR_OK) {
0c41dc
         *phKey = key->handle;
0c41dc
     }
0c41dc
 loser:
0c41dc
     PORT_Memset(buf, 0, sizeof buf);
0c41dc
     sftk_FreeObject(key);
0c41dc
     return crv;
0c41dc
 }
0c41dc
@@ -5780,16 +5784,19 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
0c41dc
 
0c41dc
     if (crv != CKR_OK) {
0c41dc
         NSC_DestroyObject(hSession, publicKey->handle);
0c41dc
         sftk_FreeObject(publicKey);
0c41dc
         NSC_DestroyObject(hSession, privateKey->handle);
0c41dc
         sftk_FreeObject(privateKey);
0c41dc
         return crv;
0c41dc
     }
0c41dc
+    /* we need to do this check at the end to make sure the generated key meets the key length requirements */
0c41dc
+    privateKey->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_NSS_GENERATE_KEY_PAIR, privateKey);
0c41dc
+    publicKey->isFIPS = privateKey->isFIPS;
0c41dc
 
0c41dc
     *phPrivateKey = privateKey->handle;
0c41dc
     *phPublicKey = publicKey->handle;
0c41dc
     sftk_FreeObject(publicKey);
0c41dc
     sftk_FreeObject(privateKey);
0c41dc
 
0c41dc
     return CKR_OK;
0c41dc
 }
0c41dc
@@ -6990,16 +6997,17 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
0c41dc
     }
0c41dc
 
0c41dc
     /* HKDF-Extract(salt, base key value) */
0c41dc
     if (params->bExtract) {
0c41dc
         CK_BYTE *salt;
0c41dc
         CK_ULONG saltLen;
0c41dc
         HMACContext *hmac;
0c41dc
         unsigned int bufLen;
0c41dc
+        SFTKSource saltKeySource = SFTK_SOURCE_DEFAULT;
0c41dc
 
0c41dc
         switch (params->ulSaltType) {
0c41dc
             case CKF_HKDF_SALT_NULL:
0c41dc
                 saltLen = hashLen;
0c41dc
                 salt = hashbuf;
0c41dc
                 memset(salt, 0, saltLen);
0c41dc
                 break;
0c41dc
             case CKF_HKDF_SALT_DATA:
0c41dc
@@ -7026,29 +7034,54 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
0c41dc
                 if (isFIPS && (key->isFIPS == 0) && (saltKey->isFIPS == 1)) {
0c41dc
                     CK_MECHANISM mech;
0c41dc
                     mech.mechanism = CKM_HKDF_DERIVE;
0c41dc
                     mech.pParameter = params;
0c41dc
                     mech.ulParameterLen = sizeof(*params);
0c41dc
                     key->isFIPS = sftk_operationIsFIPS(saltKey->slot, &mech,
0c41dc
                                                        CKA_DERIVE, saltKey);
0c41dc
                 }
0c41dc
+                saltKeySource = saltKey->source;
0c41dc
                 saltKey_att = sftk_FindAttribute(saltKey, CKA_VALUE);
0c41dc
                 if (saltKey_att == NULL) {
0c41dc
                     sftk_FreeObject(saltKey);
0c41dc
                     return CKR_KEY_HANDLE_INVALID;
0c41dc
                 }
0c41dc
                 /* save the resulting salt */
0c41dc
                 salt = saltKey_att->attrib.pValue;
0c41dc
                 saltLen = saltKey_att->attrib.ulValueLen;
0c41dc
                 break;
0c41dc
             default:
0c41dc
                 return CKR_MECHANISM_PARAM_INVALID;
0c41dc
                 break;
0c41dc
         }
0c41dc
+        /* only TLS style usage is FIPS approved,
0c41dc
+         * turn off the FIPS indicator for other usages */
0c41dc
+        if (isFIPS && key && sourceKey) {
0c41dc
+            PRBool fipsOK = PR_FALSE;
0c41dc
+            /* case one: mix the kea with a previous or default
0c41dc
+             * salt */
0c41dc
+            if ((sourceKey->source == SFTK_SOURCE_KEA) &&
0c41dc
+                (saltKeySource == SFTK_SOURCE_HKDF_EXPAND) &&
0c41dc
+                (saltLen == rawHash->length)) {
0c41dc
+                fipsOK = PR_TRUE;
0c41dc
+            }
0c41dc
+            /* case two: restart, remix the previous secret as a salt */
0c41dc
+            if ((sourceKey->objclass == CKO_DATA) &&
0c41dc
+                (NSS_SecureMemcmpZero(sourceKeyBytes, sourceKeyLen) == 0) &&
0c41dc
+                (sourceKeyLen == rawHash->length) &&
0c41dc
+                (saltKeySource == SFTK_SOURCE_HKDF_EXPAND) &&
0c41dc
+                (saltLen == rawHash->length)) {
0c41dc
+                fipsOK = PR_TRUE;
0c41dc
+            }
0c41dc
+            if (!fipsOK) {
0c41dc
+                key->isFIPS = PR_FALSE;
0c41dc
+            }
0c41dc
+        }
0c41dc
+        if (key) key->source = SFTK_SOURCE_HKDF_EXTRACT;
0c41dc
 
0c41dc
         hmac = HMAC_Create(rawHash, salt, saltLen, isFIPS);
0c41dc
         if (saltKey_att) {
0c41dc
             sftk_FreeAttribute(saltKey_att);
0c41dc
         }
0c41dc
         if (saltKey) {
0c41dc
             sftk_FreeObject(saltKey);
0c41dc
         }
0c41dc
@@ -7076,16 +7109,40 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
0c41dc
         /* T(1) = HMAC-Hash(prk, "" | info | 0x01)
0c41dc
          * T(n) = HMAC-Hash(prk, T(n-1) | info | n
0c41dc
          * key material = T(1) | ... | T(n)
0c41dc
          */
0c41dc
         HMACContext *hmac;
0c41dc
         CK_BYTE bi;
0c41dc
         unsigned iterations;
0c41dc
 
0c41dc
+        /* only TLS style usage is FIPS approved,
0c41dc
+         * turn off the FIPS indicator for other usages */
0c41dc
+        if (isFIPS && key && key->isFIPS && sourceKey) {
0c41dc
+            unsigned char *info=&params->pInfo[3];
0c41dc
+            /* only one case,
0c41dc
+             *  1) Expand only
0c41dc
+             *  2) with a key whose source was
0c41dc
+             *  SFTK_SOURCE_HKDF_EXPAND or SFTK_SOURCE_HKDF_EXTRACT
0c41dc
+             *  3) source key length == rawHash->length
0c41dc
+             *  4) Info has tls or dtls
0c41dc
+             * If any of those conditions aren't met, then we turn
0c41dc
+             * off the fips indicator */
0c41dc
+            if (params->bExtract ||
0c41dc
+               ((sourceKey->source != SFTK_SOURCE_HKDF_EXTRACT) &&
0c41dc
+                (sourceKey->source != SFTK_SOURCE_HKDF_EXPAND)) ||
0c41dc
+               (sourceKeyLen != rawHash->length) ||
0c41dc
+               (params->ulInfoLen < 7) ||
0c41dc
+               ((PORT_Memcmp(info,"tls",3) != 0) &&
0c41dc
+               (PORT_Memcmp(info,"dtls",4) != 0))) {
0c41dc
+               key->isFIPS = PR_FALSE;
0c41dc
+            }
0c41dc
+        }
0c41dc
+        if (key) key->source = SFTK_SOURCE_HKDF_EXPAND;
0c41dc
+
0c41dc
         genLen = PR_ROUNDUP(keySize, hashLen);
0c41dc
         iterations = genLen / hashLen;
0c41dc
 
0c41dc
         if (genLen > sizeof(keyBlock)) {
0c41dc
             keyBlockAlloc = PORT_Alloc(genLen);
0c41dc
             if (keyBlockAlloc == NULL) {
0c41dc
                 return CKR_HOST_MEMORY;
0c41dc
             }
0c41dc
@@ -8434,16 +8491,17 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
0c41dc
 
0c41dc
             /* calculate private value - oct */
0c41dc
             rv = DH_Derive(&dhPublic, &dhPrime, &dhValue, &derived, keySize);
0c41dc
 
0c41dc
             SECITEM_ZfreeItem(&dhPrime, PR_FALSE);
0c41dc
             SECITEM_ZfreeItem(&dhValue, PR_FALSE);
0c41dc
 
0c41dc
             if (rv == SECSuccess) {
0c41dc
+                key->source = SFTK_SOURCE_KEA;
0c41dc
                 sftk_forceAttribute(key, CKA_VALUE, derived.data, derived.len);
0c41dc
                 SECITEM_ZfreeItem(&derived, PR_FALSE);
0c41dc
                 crv = CKR_OK;
0c41dc
             } else
0c41dc
                 crv = CKR_HOST_MEMORY;
0c41dc
 
0c41dc
             break;
0c41dc
         }
0c41dc
@@ -8564,16 +8622,17 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
0c41dc
                     }
0c41dc
                     PORT_Memcpy(&keyData[keySize - secretlen], secret, secretlen);
0c41dc
                     secret = keyData;
0c41dc
                 } else {
0c41dc
                     secret += (secretlen - keySize);
0c41dc
                 }
0c41dc
                 secretlen = keySize;
0c41dc
             }
0c41dc
+            key->source = SFTK_SOURCE_KEA;
0c41dc
 
0c41dc
             sftk_forceAttribute(key, CKA_VALUE, secret, secretlen);
0c41dc
             PORT_ZFree(tmp.data, tmp.len);
0c41dc
             if (keyData) {
0c41dc
                 PORT_ZFree(keyData, keySize);
0c41dc
             }
0c41dc
             break;
0c41dc
 
0c41dc
diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h
0c41dc
--- a/lib/softoken/pkcs11i.h
0c41dc
+++ b/lib/softoken/pkcs11i.h
0c41dc
@@ -147,16 +147,26 @@ typedef enum {
0c41dc
  */
0c41dc
 typedef enum {
0c41dc
     SFTK_DestroyFailure,
0c41dc
     SFTK_Destroyed,
0c41dc
     SFTK_Busy
0c41dc
 } SFTKFreeStatus;
0c41dc
 
0c41dc
 /*
0c41dc
+ * Source of various objects
0c41dc
+ */
0c41dc
+typedef enum {
0c41dc
+    SFTK_SOURCE_DEFAULT=0,
0c41dc
+    SFTK_SOURCE_KEA,
0c41dc
+    SFTK_SOURCE_HKDF_EXPAND,
0c41dc
+    SFTK_SOURCE_HKDF_EXTRACT
0c41dc
+} SFTKSource;
0c41dc
+
0c41dc
+/*
0c41dc
  * attribute values of an object.
0c41dc
  */
0c41dc
 struct SFTKAttributeStr {
0c41dc
     SFTKAttribute *next;
0c41dc
     SFTKAttribute *prev;
0c41dc
     PRBool freeAttr;
0c41dc
     PRBool freeData;
0c41dc
     /*must be called handle to make sftkqueue_find work */
0c41dc
@@ -189,16 +199,17 @@ struct SFTKObjectStr {
0c41dc
     CK_OBJECT_CLASS objclass;
0c41dc
     CK_OBJECT_HANDLE handle;
0c41dc
     int refCount;
0c41dc
     PZLock *refLock;
0c41dc
     SFTKSlot *slot;
0c41dc
     void *objectInfo;
0c41dc
     SFTKFree infoFree;
0c41dc
     PRBool isFIPS;
0c41dc
+    SFTKSource source;
0c41dc
 };
0c41dc
 
0c41dc
 struct SFTKTokenObjectStr {
0c41dc
     SFTKObject obj;
0c41dc
     SECItem dbKey;
0c41dc
 };
0c41dc
 
0c41dc
 struct SFTKSessionObjectStr {
0c41dc
diff --git a/lib/softoken/pkcs11u.c b/lib/softoken/pkcs11u.c
0c41dc
--- a/lib/softoken/pkcs11u.c
0c41dc
+++ b/lib/softoken/pkcs11u.c
0c41dc
@@ -1090,16 +1090,17 @@ sftk_NewObject(SFTKSlot *slot)
0c41dc
         sessObject->attrList[i].freeData = PR_FALSE;
0c41dc
     }
0c41dc
     sessObject->optimizeSpace = slot->optimizeSpace;
0c41dc
 
0c41dc
     object->handle = 0;
0c41dc
     object->next = object->prev = NULL;
0c41dc
     object->slot = slot;
0c41dc
     object->isFIPS = sftk_isFIPS(slot->slotID);
0c41dc
+    object->source = SFTK_SOURCE_DEFAULT;
0c41dc
 
0c41dc
     object->refCount = 1;
0c41dc
     sessObject->sessionList.next = NULL;
0c41dc
     sessObject->sessionList.prev = NULL;
0c41dc
     sessObject->sessionList.parent = object;
0c41dc
     sessObject->session = NULL;
0c41dc
     sessObject->wasDerived = PR_FALSE;
0c41dc
     if (!hasLocks)
0c41dc
@@ -1674,16 +1675,17 @@ fail:
0c41dc
 CK_RV
0c41dc
 sftk_CopyObject(SFTKObject *destObject, SFTKObject *srcObject)
0c41dc
 {
0c41dc
     SFTKAttribute *attribute;
0c41dc
     SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject);
0c41dc
     unsigned int i;
0c41dc
 
0c41dc
     destObject->isFIPS = srcObject->isFIPS;
0c41dc
+    destObject->source = srcObject->source;
0c41dc
     if (src_so == NULL) {
0c41dc
         return sftk_CopyTokenObject(destObject, srcObject);
0c41dc
     }
0c41dc
 
0c41dc
     PZ_Lock(src_so->attributeLock);
0c41dc
     for (i = 0; i < src_so->hashSize; i++) {
0c41dc
         attribute = src_so->head[i];
0c41dc
         do {
0c41dc
@@ -2059,16 +2061,17 @@ sftk_NewTokenObject(SFTKSlot *slot, SECI
0c41dc
     /* every object must have a class, if we can't get it, the object
0c41dc
      * doesn't exist */
0c41dc
     crv = handleToClass(slot, handle, &object->objclass);
0c41dc
     if (crv != CKR_OK) {
0c41dc
         goto loser;
0c41dc
     }
0c41dc
     object->slot = slot;
0c41dc
     object->isFIPS = sftk_isFIPS(slot->slotID);
0c41dc
+    object->source = SFTK_SOURCE_DEFAULT;
0c41dc
     object->objectInfo = NULL;
0c41dc
     object->infoFree = NULL;
0c41dc
     if (!hasLocks) {
0c41dc
         object->refLock = PZ_NewLock(nssILockRefLock);
0c41dc
     }
0c41dc
     if (object->refLock == NULL) {
0c41dc
         goto loser;
0c41dc
     }
0c41dc
@@ -2225,16 +2228,25 @@ sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE 
0c41dc
             break;
0c41dc
         case CKA_DERIVE:
0c41dc
             flags = CKF_DERIVE;
0c41dc
             break;
0c41dc
         /* fake attribute to select digesting */
0c41dc
         case CKA_DIGEST:
0c41dc
             flags = CKF_DIGEST;
0c41dc
             break;
0c41dc
+        /* fake attribute to select key gen */
0c41dc
+         case CKA_NSS_GENERATE:
0c41dc
+            flags = CKF_GENERATE;
0c41dc
+            break;
0c41dc
+        /* fake attribute to select key pair gen */
0c41dc
+        case CKA_NSS_GENERATE_KEY_PAIR:
0c41dc
+            flags = CKF_GENERATE_KEY_PAIR;
0c41dc
+            break;
0c41dc
+        /* fake attributes to to handle MESSAGE* flags */
0c41dc
         case CKA_NSS_MESSAGE | CKA_ENCRYPT:
0c41dc
             flags = CKF_MESSAGE_ENCRYPT;
0c41dc
             break;
0c41dc
         case CKA_NSS_MESSAGE | CKA_DECRYPT:
0c41dc
             flags = CKF_MESSAGE_DECRYPT;
0c41dc
             break;
0c41dc
         case CKA_NSS_MESSAGE | CKA_SIGN:
0c41dc
             flags = CKF_MESSAGE_SIGN;
0c41dc
@@ -2278,17 +2290,17 @@ sftk_quickGetECCCurveOid(SFTKObject *sou
0c41dc
 }
0c41dc
 
0c41dc
 /* This function currently only returns valid lengths for
0c41dc
  * FIPS approved ECC curves. If we want to make this generic
0c41dc
  * in the future, that Curve determination can be done in
0c41dc
  * the sftk_handleSpecial. Since it's currently only used
0c41dc
  * in FIPS indicators, it's currently only compiled with
0c41dc
  * the FIPS indicator code */
0c41dc
-static int
0c41dc
+static CK_ULONG
0c41dc
 sftk_getKeyLength(SFTKObject *source)
0c41dc
 {
0c41dc
     CK_KEY_TYPE keyType = CK_INVALID_HANDLE;
0c41dc
     CK_ATTRIBUTE_TYPE keyAttribute;
0c41dc
     CK_ULONG keyLength = 0;
0c41dc
     SFTKAttribute *attribute;
0c41dc
     CK_RV crv;
0c41dc