Blame SOURCES/nss-3.53.1-cmac-kdf-selftests.patch

5f43a7
diff --git a/lib/freebl/fipsfreebl.c b/lib/freebl/fipsfreebl.c
5f43a7
--- a/lib/freebl/fipsfreebl.c
5f43a7
+++ b/lib/freebl/fipsfreebl.c
5f43a7
@@ -17,6 +17,7 @@
5f43a7
 #include "prtypes.h"
5f43a7
 #include "secitem.h"
5f43a7
 #include "pkcs11t.h"
5f43a7
+#include "cmac.h"
5f43a7
 
5f43a7
 #include "ec.h" /* Required for EC */
5f43a7
 
5f43a7
@@ -99,6 +100,7 @@
5f43a7
 #define FIPS_AES_BLOCK_SIZE 16     /* 128-bits */
5f43a7
 #define FIPS_AES_ENCRYPT_LENGTH 16 /* 128-bits */
5f43a7
 #define FIPS_AES_DECRYPT_LENGTH 16 /* 128-bits */
5f43a7
+#define FIPS_AES_CMAC_LENGTH 16    /* 128-bits */
5f43a7
 #define FIPS_AES_128_KEY_SIZE 16   /* 128-bits */
5f43a7
 #define FIPS_AES_192_KEY_SIZE 24   /* 192-bits */
5f43a7
 #define FIPS_AES_256_KEY_SIZE 32   /* 256-bits */
5f43a7
@@ -310,6 +312,11 @@
5f43a7
         0x8b, 0xde, 0xbf, 0x16, 0x5e, 0x57, 0x6b, 0x4f
5f43a7
     };
5f43a7
 
5f43a7
+    static const PRUint8 aes_cmac128_known_ciphertext[] = {
5f43a7
+        0x54, 0x11, 0xe2, 0x57, 0xbd, 0x2a, 0xdf, 0x9d,
5f43a7
+        0x1a, 0x89, 0x72, 0x80, 0x84, 0x4c, 0x7e, 0x93
5f43a7
+    };
5f43a7
+
5f43a7
     /* AES Known Ciphertext (192-bit key). */
5f43a7
     static const PRUint8 aes_ecb192_known_ciphertext[] = {
5f43a7
         0xa0, 0x18, 0x62, 0xed, 0x88, 0x19, 0xcb, 0x62,
5f43a7
@@ -328,6 +335,11 @@
5f43a7
         0x90, 0x2e, 0x44, 0xbb, 0x52, 0x03, 0xe9, 0x07
5f43a7
     };
5f43a7
 
5f43a7
+    static const PRUint8 aes_cmac192_known_ciphertext[] = {
5f43a7
+        0x0e, 0x07, 0x99, 0x1e, 0xf6, 0xee, 0xfa, 0x2c,
5f43a7
+        0x1b, 0xfc, 0xce, 0x94, 0x92, 0x2d, 0xf1, 0xab
5f43a7
+    };
5f43a7
+
5f43a7
     /* AES Known Ciphertext (256-bit key). */
5f43a7
     static const PRUint8 aes_ecb256_known_ciphertext[] = {
5f43a7
         0xdb, 0xa6, 0x52, 0x01, 0x8a, 0x70, 0xae, 0x66,
5f43a7
@@ -346,6 +358,12 @@
5f43a7
         0xf4, 0xb0, 0xc1, 0x8c, 0x86, 0x51, 0xf5, 0xa1
5f43a7
     };
5f43a7
 
5f43a7
+    static const PRUint8 aes_cmac256_known_ciphertext[] = {
5f43a7
+        0xc1, 0x26, 0x69, 0x32, 0x51, 0x13, 0x65, 0xac,
5f43a7
+        0x71, 0x23, 0xe4, 0xe7, 0xb9, 0x0c, 0x88, 0x9f
5f43a7
+
5f43a7
+    };
5f43a7
+
5f43a7
     const PRUint8 *aes_ecb_known_ciphertext =
5f43a7
         (aes_key_size == FIPS_AES_128_KEY_SIZE) ? aes_ecb128_known_ciphertext : (aes_key_size == FIPS_AES_192_KEY_SIZE) ? aes_ecb192_known_ciphertext : aes_ecb256_known_ciphertext;
5f43a7
 
5f43a7
@@ -355,10 +373,14 @@
5f43a7
     const PRUint8 *aes_gcm_known_ciphertext =
5f43a7
         (aes_key_size == FIPS_AES_128_KEY_SIZE) ? aes_gcm128_known_ciphertext : (aes_key_size == FIPS_AES_192_KEY_SIZE) ? aes_gcm192_known_ciphertext : aes_gcm256_known_ciphertext;
5f43a7
 
5f43a7
+    const PRUint8 *aes_cmac_known_ciphertext =
5f43a7
+        (aes_key_size == FIPS_AES_128_KEY_SIZE) ? aes_cmac128_known_ciphertext : (aes_key_size == FIPS_AES_192_KEY_SIZE) ? aes_cmac192_known_ciphertext : aes_cmac256_known_ciphertext;
5f43a7
+
5f43a7
     /* AES variables. */
5f43a7
     PRUint8 aes_computed_ciphertext[FIPS_AES_ENCRYPT_LENGTH * 2];
5f43a7
     PRUint8 aes_computed_plaintext[FIPS_AES_DECRYPT_LENGTH * 2];
5f43a7
     AESContext *aes_context;
5f43a7
+    CMACContext *cmac_context;
5f43a7
     unsigned int aes_bytes_encrypted;
5f43a7
     unsigned int aes_bytes_decrypted;
5f43a7
     CK_NSS_GCM_PARAMS gcmParams;
5f43a7
@@ -547,6 +569,44 @@
5f43a7
         return (SECFailure);
5f43a7
     }
5f43a7
 
5f43a7
+    /******************************************************/
5f43a7
+    /* AES-CMAC Known Answer Encryption Test.             */
5f43a7
+    /******************************************************/
5f43a7
+    cmac_context = CMAC_Create(CMAC_AES, aes_known_key, aes_key_size);
5f43a7
+
5f43a7
+    if (cmac_context == NULL) {
5f43a7
+        PORT_SetError(SEC_ERROR_NO_MEMORY);
5f43a7
+        return (SECFailure);
5f43a7
+    }
5f43a7
+
5f43a7
+    aes_status = CMAC_Begin(cmac_context);
5f43a7
+    if (aes_status != SECSuccess) {
5f43a7
+        CMAC_Destroy(cmac_context, PR_TRUE);
5f43a7
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
5f43a7
+        return (SECFailure);
5f43a7
+    }
5f43a7
+
5f43a7
+    aes_status = CMAC_Update(cmac_context, aes_known_plaintext,
5f43a7
+                             FIPS_AES_DECRYPT_LENGTH);
5f43a7
+    if (aes_status != SECSuccess) {
5f43a7
+        CMAC_Destroy(cmac_context, PR_TRUE);
5f43a7
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
5f43a7
+        return (SECFailure);
5f43a7
+    }
5f43a7
+
5f43a7
+    aes_status = CMAC_Finish(cmac_context, aes_computed_ciphertext,
5f43a7
+                             &aes_bytes_encrypted, FIPS_AES_CMAC_LENGTH);
5f43a7
+
5f43a7
+    CMAC_Destroy(cmac_context, PR_TRUE);
5f43a7
+
5f43a7
+    if ((aes_status != SECSuccess) ||
5f43a7
+        (aes_bytes_encrypted != FIPS_AES_CMAC_LENGTH) ||
5f43a7
+        (PORT_Memcmp(aes_computed_ciphertext, aes_cmac_known_ciphertext,
5f43a7
+                     FIPS_AES_CMAC_LENGTH) != 0)) {
5f43a7
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
5f43a7
+        return (SECFailure);
5f43a7
+    }
5f43a7
+
5f43a7
     return (SECSuccess);
5f43a7
 }
5f43a7
 
5f43a7
@@ -743,6 +803,170 @@
5f43a7
     return (SECSuccess);
5f43a7
 }
5f43a7
 
5f43a7
+SECStatus
5f43a7
+freebl_fips_TLS_PowerUpSelfTest(void)
5f43a7
+{
5f43a7
+    static const PRUint8 TLS_known_secret_key[] = {
5f43a7
+        "Firefox and ThunderBird are awesome!"
5f43a7
+    };
5f43a7
+
5f43a7
+    static const PRUint8 TLS_known_secret_key_length = sizeof TLS_known_secret_key;
5f43a7
+
5f43a7
+    /* known tls prf with sha1/md5 */
5f43a7
+    static const PRUint8 known_TLS_PRF[] = {
5f43a7
+        0x87, 0x4c, 0xc0, 0xc5, 0x15, 0x14, 0x2b, 0xdc,
5f43a7
+        0x73, 0x48, 0x9e, 0x88, 0x9d, 0xf5, 0x83, 0x2f,
5f43a7
+        0x2d, 0x66, 0x1e, 0x78, 0x6c, 0x54, 0x78, 0x29,
5f43a7
+        0xb9, 0xa4, 0x4c, 0x90, 0x5e, 0xa2, 0xe6, 0x5c,
5f43a7
+        0xf1, 0x4f, 0xb5, 0x95, 0xa5, 0x54, 0xc0, 0x9f,
5f43a7
+        0x84, 0x47, 0xb4, 0x4c, 0xda, 0xae, 0x19, 0x29,
5f43a7
+        0x2b, 0x91, 0x2a, 0x81, 0x9d, 0x3a, 0x30, 0x40,
5f43a7
+        0xc5, 0xdf, 0xbb, 0xfa, 0xd8, 0x4c, 0xbc, 0x18
5f43a7
+    };
5f43a7
+
5f43a7
+    /* known SHA256 tls mac */
5f43a7
+    static const PRUint8 known_TLS_SHA256[] = {
5f43a7
+        0x66, 0xd6, 0x94, 0xd4, 0x0d, 0x32, 0x61, 0x38,
5f43a7
+        0x26, 0xf6, 0x8b, 0xfe, 0x9e, 0xac, 0xa2, 0xf5,
5f43a7
+        0x40, 0x52, 0x74, 0x3f, 0xbe, 0xb8, 0xca, 0x94,
5f43a7
+        0xc3, 0x64, 0xd6, 0x02, 0xf5, 0x88, 0x98, 0x35,
5f43a7
+        0x73, 0x9f, 0xce, 0xaa, 0x68, 0xe3, 0x7c, 0x93,
5f43a7
+        0x30, 0x21, 0x45, 0xec, 0xe9, 0x8f, 0x1c, 0x7e,
5f43a7
+        0xd1, 0x54, 0xf5, 0xbe, 0xff, 0xc8, 0xd7, 0x72,
5f43a7
+        0x7f, 0x9c, 0x0c, 0x7f, 0xa9, 0xd3, 0x4a, 0xd2
5f43a7
+    };
5f43a7
+
5f43a7
+#ifdef NSS_FULL_POST
5f43a7
+    /* known SHA224 tls mac */
5f43a7
+    static const PRUint8 known_TLS_SHA224[] = {
5f43a7
+        0xd8, 0x68, 0x15, 0xff, 0xa1, 0xa2, 0x5e, 0x16,
5f43a7
+        0xce, 0xb1, 0xfd, 0xbd, 0xda, 0x39, 0xbc, 0xa7,
5f43a7
+        0x27, 0x32, 0x78, 0x94, 0x66, 0xf0, 0x84, 0xcf,
5f43a7
+        0x46, 0xc0, 0x22, 0x76, 0xdc, 0x6b, 0x2e, 0xed,
5f43a7
+        0x1d, 0x2d, 0xd2, 0x93, 0xfd, 0xae, 0xca, 0xf9,
5f43a7
+        0xe0, 0x4c, 0x17, 0x23, 0x22, 0x5a, 0x73, 0x93,
5f43a7
+        0x20, 0x0a, 0xbd, 0xa0, 0x72, 0xf8, 0x8b, 0x74,
5f43a7
+        0xfb, 0xf1, 0xab, 0xb7, 0xe0, 0xec, 0x34, 0xc9
5f43a7
+    };
5f43a7
+
5f43a7
+    /* known SHA384 tls mac */
5f43a7
+    static const PRUint8 known_TLS_SHA384[] = {
5f43a7
+        0xb2, 0xac, 0x06, 0x10, 0xad, 0x50, 0xd5, 0xdc,
5f43a7
+        0xdb, 0x01, 0xea, 0xa6, 0x2d, 0x8a, 0x34, 0xb6,
5f43a7
+        0xeb, 0x84, 0xbc, 0x37, 0xc9, 0x9f, 0xa1, 0x9c,
5f43a7
+        0xd5, 0xbd, 0x4e, 0x66, 0x16, 0x24, 0xe5, 0x3d,
5f43a7
+        0xce, 0x74, 0xe0, 0x30, 0x41, 0x5c, 0xdb, 0xb7,
5f43a7
+        0x52, 0x1d, 0x2d, 0x4d, 0x9b, 0xbe, 0x6b, 0x86,
5f43a7
+        0xda, 0x8a, 0xca, 0x73, 0x39, 0xb4, 0xc7, 0x8f,
5f43a7
+        0x03, 0xb1, 0xf9, 0x7e, 0x65, 0xae, 0x17, 0x10
5f43a7
+    };
5f43a7
+
5f43a7
+    /* known SHA512 tls mac */
5f43a7
+    static const PRUint8 known_TLS_SHA512[] = {
5f43a7
+        0x73, 0x21, 0x4f, 0x40, 0x81, 0x1e, 0x90, 0xa1,
5f43a7
+        0x16, 0x40, 0x1e, 0x33, 0x69, 0xc5, 0x00, 0xc7,
5f43a7
+        0xc4, 0x81, 0xa3, 0x4f, 0xa7, 0xcc, 0x4a, 0xeb,
5f43a7
+        0x1a, 0x66, 0x00, 0x82, 0x52, 0xe2, 0x2f, 0x69,
5f43a7
+        0x14, 0x59, 0x05, 0x7c, 0xb0, 0x32, 0xce, 0xcc,
5f43a7
+        0xb7, 0xc9, 0xab, 0x0f, 0x73, 0x00, 0xe5, 0x52,
5f43a7
+        0x9d, 0x6b, 0x0e, 0x66, 0x4b, 0xb3, 0x0b, 0x0d,
5f43a7
+        0x34, 0x53, 0x97, 0x13, 0x84, 0x18, 0x31, 0x7a
5f43a7
+    };
5f43a7
+#endif
5f43a7
+
5f43a7
+    SECStatus status;
5f43a7
+    PRUint8 tls_computed[HASH_LENGTH_MAX];
5f43a7
+    SECItem secret;
5f43a7
+    SECItem seed;
5f43a7
+    SECItem result;
5f43a7
+    const char *tls_label = "fips test label";
5f43a7
+
5f43a7
+    secret.data = (unsigned char *)TLS_known_secret_key;
5f43a7
+    secret.len = TLS_known_secret_key_length;
5f43a7
+    seed.data = (unsigned char *)known_hash_message;
5f43a7
+    seed.len = FIPS_KNOWN_HASH_MESSAGE_LENGTH;
5f43a7
+    result.data = tls_computed;
5f43a7
+    result.len = sizeof(tls_computed);
5f43a7
+
5f43a7
+    /***************************************************/
5f43a7
+    /* TLS 1.0 PRF Known Answer Test                   */
5f43a7
+    /***************************************************/
5f43a7
+
5f43a7
+    status = TLS_PRF(&secret, tls_label, &seed, &result, PR_TRUE);
5f43a7
+
5f43a7
+    if ((status != SECSuccess) ||
5f43a7
+        (result.len != HASH_LENGTH_MAX) ||
5f43a7
+        (PORT_Memcmp(tls_computed, known_TLS_PRF,
5f43a7
+                     HASH_LENGTH_MAX) != 0)) {
5f43a7
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
5f43a7
+        return (SECFailure);
5f43a7
+    }
5f43a7
+
5f43a7
+    /***************************************************/
5f43a7
+    /* TLS 1.2 SHA-256 Known Answer Test.              */
5f43a7
+    /***************************************************/
5f43a7
+
5f43a7
+    status = TLS_P_hash(HASH_AlgSHA256, &secret, tls_label,
5f43a7
+                        &seed, &result, PR_TRUE);
5f43a7
+
5f43a7
+    if ((status != SECSuccess) ||
5f43a7
+        (result.len != HASH_LENGTH_MAX) ||
5f43a7
+        (PORT_Memcmp(tls_computed, known_TLS_SHA256,
5f43a7
+                     HASH_LENGTH_MAX) != 0)) {
5f43a7
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
5f43a7
+        return (SECFailure);
5f43a7
+    }
5f43a7
+
5f43a7
+#ifdef NSS_FULL_POST
5f43a7
+    /***************************************************/
5f43a7
+    /* TLS 1.2 SHA-224 Known Answer Test.              */
5f43a7
+    /***************************************************/
5f43a7
+
5f43a7
+    status = TLS_P_hash(HASH_AlgSHA224, &secret, tls_label,
5f43a7
+                        &seed, &result, PR_TRUE);
5f43a7
+
5f43a7
+    if ((status != SECSuccess) ||
5f43a7
+        (result.len != HASH_LENGTH_MAX) ||
5f43a7
+        (PORT_Memcmp(tls_computed, known_TLS_SHA224,
5f43a7
+                     HASH_LENGTH_MAX) != 0)) {
5f43a7
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
5f43a7
+        return (SECFailure);
5f43a7
+    }
5f43a7
+
5f43a7
+    /***************************************************/
5f43a7
+    /* TLS 1.2 SHA-384 Known Answer Test.              */
5f43a7
+    /***************************************************/
5f43a7
+
5f43a7
+    status = TLS_P_hash(HASH_AlgSHA384, &secret, tls_label,
5f43a7
+                        &seed, &result, PR_TRUE);
5f43a7
+
5f43a7
+    if ((status != SECSuccess) ||
5f43a7
+        (result.len != HASH_LENGTH_MAX) ||
5f43a7
+        (PORT_Memcmp(tls_computed, known_TLS_SHA384,
5f43a7
+                     HASH_LENGTH_MAX) != 0)) {
5f43a7
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
5f43a7
+        return (SECFailure);
5f43a7
+    }
5f43a7
+
5f43a7
+    /***************************************************/
5f43a7
+    /* TLS 1.2 SHA-512 Known Answer Test.              */
5f43a7
+    /***************************************************/
5f43a7
+
5f43a7
+    status = TLS_P_hash(HASH_AlgSHA512, &secret, tls_label,
5f43a7
+                        &seed, &result, PR_TRUE);
5f43a7
+
5f43a7
+    if ((status != SECSuccess) ||
5f43a7
+        (result.len != HASH_LENGTH_MAX) ||
5f43a7
+        (PORT_Memcmp(tls_computed, known_TLS_SHA512,
5f43a7
+                     HASH_LENGTH_MAX) != 0)) {
5f43a7
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
5f43a7
+        return (SECFailure);
5f43a7
+    }
5f43a7
+#endif
5f43a7
+
5f43a7
+    return (SECSuccess);
5f43a7
+}
5f43a7
+
5f43a7
 static SECStatus
5f43a7
 freebl_fips_SHA_PowerUpSelfTest(void)
5f43a7
 {
5f43a7
@@ -1842,6 +2066,12 @@
5f43a7
         if (rv != SECSuccess)
5f43a7
             return rv;
5f43a7
 
5f43a7
+        /* TLS PRF Power-Up SelfTest(s). */
5f43a7
+        rv = freebl_fips_TLS_PowerUpSelfTest();
5f43a7
+
5f43a7
+        if (rv != SECSuccess)
5f43a7
+            return rv;
5f43a7
+
5f43a7
         /* NOTE: RSA can only be tested in full freebl. It requires access to
5f43a7
          * the locking primitives */
5f43a7
         /* RSA Power-Up SelfTest(s). */
5f43a7
diff --git a/lib/softoken/fipstest.c b/lib/softoken/fipstest.c
5f43a7
--- a/lib/softoken/fipstest.c
5f43a7
+++ b/lib/softoken/fipstest.c
5f43a7
@@ -13,6 +13,7 @@
5f43a7
 #include "secoid.h"
5f43a7
 #include "secerr.h"
5f43a7
 #include "pkcs11i.h"
5f43a7
+#include "lowpbe.h"
5f43a7
 
5f43a7
 /*
5f43a7
  * different platforms have different ways of calling and initial entry point
5f43a7
@@ -581,6 +582,106 @@
5f43a7
     return (SECFailure);
5f43a7
 }
5f43a7
 
5f43a7
+static SECStatus
5f43a7
+sftk_fips_HKDF_PowerUpSelfTest(void)
5f43a7
+{
5f43a7
+    SECStatus status;
5f43a7
+    static const unsigned char base_key[] = {
5f43a7
+        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
5f43a7
+        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
5f43a7
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
5f43a7
+        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
5f43a7
+        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
5f43a7
+        0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
5f43a7
+        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
5f43a7
+        0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
5f43a7
+    };
5f43a7
+    static const unsigned char known_hkdf_sha256_key[] = {
5f43a7
+        0xdd, 0xdb, 0xeb, 0xe5, 0x6d, 0xd2, 0x96, 0xa4,
5f43a7
+        0x07, 0xc5, 0x7d, 0xda, 0x31, 0x56, 0x8d, 0xa5,
5f43a7
+        0x41, 0x3e, 0x90, 0xd4, 0xe6, 0x98, 0xeb, 0xf8,
5f43a7
+        0x5a, 0x49, 0x7f, 0x38, 0xef, 0x01, 0x8a, 0xe5,
5f43a7
+        0xda, 0x36, 0xe5, 0xcf, 0x21, 0xe3, 0x9f, 0xc3,
5f43a7
+        0x32, 0xb3, 0x1e, 0xf6, 0xc5, 0x10, 0x4c, 0x86,
5f43a7
+        0x53, 0x5e, 0x6f, 0xe0, 0x63, 0x6e, 0x43, 0x33,
5f43a7
+        0x61, 0x35, 0xf4, 0x17, 0x10, 0x77, 0x75, 0x2a
5f43a7
+    };
5f43a7
+/* current NIST IG's say we only need to test one instance
5f43a7
+ * of kdfs, keep these others around in case the guidance
5f43a7
+ * changes */
5f43a7
+#ifdef NSS_FULL_POST
5f43a7
+    static const unsigned char known_hkdf_sha384_key[] = {
5f43a7
+        0x35, 0x64, 0xc4, 0xa1, 0xcc, 0xc1, 0xdc, 0xe4,
5f43a7
+        0xe2, 0xca, 0x51, 0xae, 0xe8, 0x92, 0x88, 0x30,
5f43a7
+        0x8b, 0xb0, 0x2b, 0xac, 0x00, 0x15, 0xac, 0x15,
5f43a7
+        0x97, 0xc9, 0xf4, 0x6b, 0xf6, 0x3f, 0x97, 0xea,
5f43a7
+        0x48, 0x55, 0x38, 0x25, 0x06, 0x5d, 0x91, 0x64,
5f43a7
+        0xbd, 0x09, 0xf3, 0x44, 0xbc, 0x82, 0xbe, 0xdb,
5f43a7
+        0x5c, 0xd7, 0xf2, 0x24, 0xa5, 0x55, 0x8d, 0xa9,
5f43a7
+        0xa8, 0x85, 0xde, 0x8c, 0x33, 0xe0, 0x4d, 0xc3
5f43a7
+    };
5f43a7
+    static const unsigned char known_hkdf_sha512_key[] = {
5f43a7
+        0x63, 0x4e, 0xbc, 0x42, 0xb3, 0x56, 0x74, 0x7d,
5f43a7
+        0x1b, 0x55, 0xf0, 0x34, 0x54, 0xcb, 0x6d, 0x58,
5f43a7
+        0x39, 0x96, 0x10, 0xda, 0x03, 0x20, 0x8f, 0x77,
5f43a7
+        0x0d, 0xb4, 0xf7, 0xf6, 0x67, 0x0d, 0x5b, 0x6b,
5f43a7
+        0xd0, 0x30, 0xc4, 0xdd, 0x67, 0x61, 0x5d, 0x9a,
5f43a7
+        0xf5, 0x18, 0x6e, 0x1b, 0x60, 0x97, 0xc2, 0x4d,
5f43a7
+        0x23, 0x43, 0x69, 0xe6, 0x3b, 0xa5, 0xdf, 0xe9,
5f43a7
+        0x7c, 0xf1, 0x87, 0x48, 0x6f, 0xb9, 0xd3, 0x02
5f43a7
+    };
5f43a7
+#endif
5f43a7
+    unsigned char outBytes[64] = { 0 };
5f43a7
+
5f43a7
+    CK_HKDF_PARAMS hkdf_params;
5f43a7
+
5f43a7
+    hkdf_params.bExpand = CK_TRUE;
5f43a7
+    hkdf_params.bExtract = CK_TRUE;
5f43a7
+    hkdf_params.ulSaltType = CKF_HKDF_SALT_DATA;
5f43a7
+    hkdf_params.pSalt = (CK_BYTE_PTR)base_key;
5f43a7
+    hkdf_params.ulSaltLen = sizeof(base_key);
5f43a7
+    hkdf_params.pInfo = (CK_BYTE_PTR)base_key;
5f43a7
+    hkdf_params.ulInfoLen = sizeof(base_key);
5f43a7
+
5f43a7
+    /**************************************************/
5f43a7
+    /* HKDF tests                                     */
5f43a7
+    /**************************************************/
5f43a7
+
5f43a7
+    hkdf_params.prfHashMechanism = CKM_SHA256_HMAC;
5f43a7
+    status = sftk_HKDF(&hkdf_params, CK_INVALID_HANDLE, NULL,
5f43a7
+                       base_key, 32, NULL, outBytes, sizeof(outBytes),
5f43a7
+                       PR_TRUE, PR_TRUE);
5f43a7
+    if ((status != SECSuccess) ||
5f43a7
+        PORT_Memcmp(outBytes, known_hkdf_sha256_key, sizeof(outBytes)) != 0) {
5f43a7
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
5f43a7
+        return (SECFailure);
5f43a7
+    }
5f43a7
+
5f43a7
+#ifdef NSS_FULL_POST
5f43a7
+    hkdf_params.prfHashMechanism = CKM_SHA384_HMAC;
5f43a7
+    status = sftk_HKDF(&hkdf_params, CK_INVALID_HANDLE, NULL,
5f43a7
+                       base_key, 48, NULL, outBytes, sizeof(outBytes),
5f43a7
+                       PR_TRUE, PR_TRUE);
5f43a7
+    if ((status != SECSuccess) ||
5f43a7
+        PORT_Memcmp(outBytes, known_hkdf_sha384_key, sizeof(outBytes)) != 0) {
5f43a7
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
5f43a7
+        return (SECFailure);
5f43a7
+    }
5f43a7
+
5f43a7
+    hkdf_params.prfHashMechanism = CKM_SHA512_HMAC;
5f43a7
+    status = sftk_HKDF(&hkdf_params, CK_INVALID_HANDLE, NULL,
5f43a7
+                       base_key, 64, NULL, outBytes, sizeof(outBytes),
5f43a7
+                       PR_TRUE, PR_TRUE);
5f43a7
+    if ((status != SECSuccess) ||
5f43a7
+        PORT_Memcmp(outBytes, known_hkdf_sha512_key, sizeof(outBytes)) != 0) {
5f43a7
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
5f43a7
+        return (SECFailure);
5f43a7
+    }
5f43a7
+#endif
5f43a7
+
5f43a7
+    return (SECSuccess);
5f43a7
+}
5f43a7
+
5f43a7
 static PRBool sftk_self_tests_ran = PR_FALSE;
5f43a7
 static PRBool sftk_self_tests_success = PR_FALSE;
5f43a7
 
5f43a7
@@ -631,6 +732,22 @@
5f43a7
     if (rv != SECSuccess) {
5f43a7
         return;
5f43a7
     }
5f43a7
+
5f43a7
+    rv = sftk_fips_SP800_108_PowerUpSelfTests();
5f43a7
+    if (rv != SECSuccess) {
5f43a7
+        return;
5f43a7
+    }
5f43a7
+
5f43a7
+    rv = sftk_fips_HKDF_PowerUpSelfTest();
5f43a7
+    if (rv != SECSuccess) {
5f43a7
+        return;
5f43a7
+    }
5f43a7
+
5f43a7
+    rv = sftk_fips_pbkdf_PowerUpSelfTests();
5f43a7
+    if (rv != SECSuccess) {
5f43a7
+        return;
5f43a7
+    }
5f43a7
+
5f43a7
     sftk_self_tests_success = PR_TRUE;
5f43a7
 }
5f43a7
 
5f43a7
diff --git a/lib/softoken/kbkdf.c b/lib/softoken/kbkdf.c
5f43a7
--- a/lib/softoken/kbkdf.c
5f43a7
+++ b/lib/softoken/kbkdf.c
5f43a7
@@ -90,7 +90,7 @@
5f43a7
 }
5f43a7
 
5f43a7
 static CK_RV
5f43a7
-kbkdf_ValidateParameter(CK_MECHANISM_TYPE mech, CK_PRF_DATA_PARAM_PTR data)
5f43a7
+kbkdf_ValidateParameter(CK_MECHANISM_TYPE mech, const CK_PRF_DATA_PARAM *data)
5f43a7
 {
5f43a7
     /* This function validates that the passed data parameter (data) conforms
5f43a7
      * to PKCS#11 v3.0's expectations for KDF parameters. This depends both on
5f43a7
@@ -265,7 +265,7 @@
5f43a7
 }
5f43a7
 
5f43a7
 static CK_RV
5f43a7
-kbkdf_ValidateParameters(CK_MECHANISM_TYPE mech, CK_SP800_108_KDF_PARAMS_PTR params, CK_ULONG keySize)
5f43a7
+kbkdf_ValidateParameters(CK_MECHANISM_TYPE mech, const CK_SP800_108_KDF_PARAMS *params, CK_ULONG keySize)
5f43a7
 {
5f43a7
     CK_RV ret = CKR_MECHANISM_PARAM_INVALID;
5f43a7
     int param_type_count[5] = { 0, 0, 0, 0, 0 };
5f43a7
@@ -344,7 +344,7 @@
5f43a7
 /* [ section: parameter helpers ] */
5f43a7
 
5f43a7
 static CK_VOID_PTR
5f43a7
-kbkdf_FindParameter(CK_SP800_108_KDF_PARAMS_PTR params, CK_PRF_DATA_TYPE type)
5f43a7
+kbkdf_FindParameter(const CK_SP800_108_KDF_PARAMS *params, CK_PRF_DATA_TYPE type)
5f43a7
 {
5f43a7
     for (size_t offset = 0; offset < params->ulNumberOfDataParams; offset++) {
5f43a7
         if (params->pDataParams[offset].type == type) {
5f43a7
@@ -392,7 +392,7 @@
5f43a7
 }
5f43a7
 
5f43a7
 static CK_RV
5f43a7
-kbkdf_CalculateLength(CK_SP800_108_KDF_PARAMS_PTR params, sftk_MACCtx *ctx, CK_ULONG ret_key_size, PRUint64 *output_bitlen, size_t *buffer_length)
5f43a7
+kbkdf_CalculateLength(const CK_SP800_108_KDF_PARAMS *params, sftk_MACCtx *ctx, CK_ULONG ret_key_size, PRUint64 *output_bitlen, size_t *buffer_length)
5f43a7
 {
5f43a7
     /* Two cases: either we have additional derived keys or we don't. In the
5f43a7
      * case that we don't, the length of the derivation is the size of the
5f43a7
@@ -465,7 +465,7 @@
5f43a7
 }
5f43a7
 
5f43a7
 static CK_RV
5f43a7
-kbkdf_CalculateIterations(CK_MECHANISM_TYPE mech, CK_SP800_108_KDF_PARAMS_PTR params, sftk_MACCtx *ctx, size_t buffer_length, PRUint32 *num_iterations)
5f43a7
+kbkdf_CalculateIterations(CK_MECHANISM_TYPE mech, const CK_SP800_108_KDF_PARAMS *params, sftk_MACCtx *ctx, size_t buffer_length, PRUint32 *num_iterations)
5f43a7
 {
5f43a7
     CK_SP800_108_COUNTER_FORMAT_PTR param_ptr = NULL;
5f43a7
     PRUint64 iteration_count;
5f43a7
@@ -519,7 +519,7 @@
5f43a7
 }
5f43a7
 
5f43a7
 static CK_RV
5f43a7
-kbkdf_AddParameters(CK_MECHANISM_TYPE mech, sftk_MACCtx *ctx, CK_SP800_108_KDF_PARAMS *params, PRUint32 counter, PRUint64 length, unsigned char *chaining_prf, size_t chaining_prf_len, CK_PRF_DATA_TYPE exclude)
5f43a7
+kbkdf_AddParameters(CK_MECHANISM_TYPE mech, sftk_MACCtx *ctx, const CK_SP800_108_KDF_PARAMS *params, PRUint32 counter, PRUint64 length, const unsigned char *chaining_prf, size_t chaining_prf_len, CK_PRF_DATA_TYPE exclude)
5f43a7
 {
5f43a7
     size_t offset = 0;
5f43a7
     CK_RV ret = CKR_OK;
5f43a7
@@ -749,7 +749,7 @@
5f43a7
 /* [ section: KDFs ] */
5f43a7
 
5f43a7
 static CK_RV
5f43a7
-kbkdf_CounterRaw(CK_SP800_108_KDF_PARAMS_PTR params, sftk_MACCtx *ctx, unsigned char *ret_buffer, size_t buffer_length, PRUint64 output_bitlen)
5f43a7
+kbkdf_CounterRaw(const CK_SP800_108_KDF_PARAMS *params, sftk_MACCtx *ctx, unsigned char *ret_buffer, size_t buffer_length, PRUint64 output_bitlen)
5f43a7
 {
5f43a7
     CK_RV ret = CKR_OK;
5f43a7
 
5f43a7
@@ -837,7 +837,7 @@
5f43a7
 }
5f43a7
 
5f43a7
 static CK_RV
5f43a7
-kbkdf_FeedbackRaw(CK_SP800_108_KDF_PARAMS_PTR params, unsigned char *initial_value, CK_ULONG initial_value_length, sftk_MACCtx *ctx, unsigned char *ret_buffer, size_t buffer_length, PRUint64 output_bitlen)
5f43a7
+kbkdf_FeedbackRaw(const CK_SP800_108_KDF_PARAMS *params, const unsigned char *initial_value, CK_ULONG initial_value_length, sftk_MACCtx *ctx, unsigned char *ret_buffer, size_t buffer_length, PRUint64 output_bitlen)
5f43a7
 {
5f43a7
     CK_RV ret = CKR_OK;
5f43a7
 
5f43a7
@@ -859,7 +859,7 @@
5f43a7
      * chaining in this KDF. Note that we have to make it large enough to
5f43a7
      * fit the output of the PRF, but we can delay its actual creation until
5f43a7
      * the first PRF invocation. Until then, point to the IV value. */
5f43a7
-    unsigned char *chaining_value = initial_value;
5f43a7
+    unsigned char *chaining_value = (unsigned char *)initial_value;
5f43a7
 
5f43a7
     /* Size of the chaining value discussed above. Defaults to the size of
5f43a7
      * the IV value. */
5f43a7
@@ -962,7 +962,7 @@
5f43a7
 }
5f43a7
 
5f43a7
 static CK_RV
5f43a7
-kbkdf_PipelineRaw(CK_SP800_108_KDF_PARAMS_PTR params, sftk_MACCtx *ctx, unsigned char *ret_buffer, size_t buffer_length, PRUint64 output_bitlen)
5f43a7
+kbkdf_PipelineRaw(const CK_SP800_108_KDF_PARAMS *params, sftk_MACCtx *ctx, unsigned char *ret_buffer, size_t buffer_length, PRUint64 output_bitlen)
5f43a7
 {
5f43a7
     CK_RV ret = CKR_OK;
5f43a7
 
5f43a7
@@ -1109,31 +1109,17 @@
5f43a7
     return ret;
5f43a7
 }
5f43a7
 
5f43a7
-/* [ section: PKCS#11 entry ] */
5f43a7
-
5f43a7
-CK_RV
5f43a7
-kbkdf_Dispatch(CK_MECHANISM_TYPE mech, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, SFTKObject *prf_key, SFTKObject *ret_key, CK_ULONG ret_key_size)
5f43a7
+static CK_RV
5f43a7
+kbkdf_RawDispatch(CK_MECHANISM_TYPE mech,
5f43a7
+                  const CK_SP800_108_KDF_PARAMS *kdf_params,
5f43a7
+                  const CK_BYTE *initial_value,
5f43a7
+                  CK_ULONG initial_value_length,
5f43a7
+                  SFTKObject *prf_key, const unsigned char *prf_key_bytes,
5f43a7
+                  unsigned int prf_key_length, unsigned char **out_key_bytes,
5f43a7
+                  size_t *out_key_length, unsigned int *mac_size,
5f43a7
+                  CK_ULONG ret_key_size)
5f43a7
 {
5f43a7
-    /* This handles boilerplate common to all KBKDF types. Instead of placing
5f43a7
-     * this in pkcs11c.c, place it here to reduce clutter. */
5f43a7
-
5f43a7
     CK_RV ret;
5f43a7
-
5f43a7
-    /* Assumptions about our calling environment. */
5f43a7
-    PR_ASSERT(pMechanism != NULL && prf_key != NULL && ret_key != NULL);
5f43a7
-
5f43a7
-    /* Validate that the caller passed parameters. */
5f43a7
-    if (pMechanism->pParameter == NULL) {
5f43a7
-        return CKR_MECHANISM_PARAM_INVALID;
5f43a7
-    }
5f43a7
-
5f43a7
-    /* Create a common set of parameters to use for all KDF types. This
5f43a7
-     * separates out the KDF parameters from the Feedback-specific IV,
5f43a7
-     * allowing us to use a common type for all calls. */
5f43a7
-    CK_SP800_108_KDF_PARAMS kdf_params = { 0 };
5f43a7
-    CK_BYTE_PTR initial_value = NULL;
5f43a7
-    CK_ULONG initial_value_length = 0;
5f43a7
-
5f43a7
     /* Context for our underlying PRF function.
5f43a7
      *
5f43a7
      * Zeroing context required unconditional call of sftk_MAC_Destroy.
5f43a7
@@ -1168,28 +1154,27 @@
5f43a7
      */
5f43a7
     PRUint64 output_bitlen = 0;
5f43a7
 
5f43a7
-    /* Split Feedback-specific IV from remaining KDF parameters. */
5f43a7
-    ret = kbkdf_LoadParameters(mech, pMechanism, &kdf_params, &initial_value, &initial_value_length);
5f43a7
-    if (ret != CKR_OK) {
5f43a7
-        goto finish;
5f43a7
-    }
5f43a7
-
5f43a7
     /* First validate our passed input parameters against PKCS#11 v3.0
5f43a7
      * and NIST SP800-108 requirements. */
5f43a7
-    ret = kbkdf_ValidateParameters(mech, &kdf_params, ret_key_size);
5f43a7
+    ret = kbkdf_ValidateParameters(mech, kdf_params, ret_key_size);
5f43a7
     if (ret != CKR_OK) {
5f43a7
         goto finish;
5f43a7
     }
5f43a7
 
5f43a7
     /* Initialize the underlying PRF state. */
5f43a7
-    ret = sftk_MAC_Init(&ctx, kdf_params.prfType, prf_key);
5f43a7
+    if (prf_key) {
5f43a7
+        ret = sftk_MAC_Init(&ctx, kdf_params->prfType, prf_key);
5f43a7
+    } else {
5f43a7
+        ret = sftk_MAC_InitRaw(&ctx, kdf_params->prfType, prf_key_bytes,
5f43a7
+                               prf_key_length, PR_TRUE);
5f43a7
+    }
5f43a7
     if (ret != CKR_OK) {
5f43a7
         goto finish;
5f43a7
     }
5f43a7
 
5f43a7
     /* Compute the size of our output buffer based on passed parameters and
5f43a7
      * the output size of the underlying PRF. */
5f43a7
-    ret = kbkdf_CalculateLength(&kdf_params, &ctx, ret_key_size, &output_bitlen, &buffer_length);
5f43a7
+    ret = kbkdf_CalculateLength(kdf_params, &ctx, ret_key_size, &output_bitlen, &buffer_length);
5f43a7
     if (ret != CKR_OK) {
5f43a7
         goto finish;
5f43a7
     }
5f43a7
@@ -1205,15 +1190,15 @@
5f43a7
     switch (mech) {
5f43a7
         case CKM_NSS_SP800_108_COUNTER_KDF_DERIVE_DATA: /* fall through */
5f43a7
         case CKM_SP800_108_COUNTER_KDF:
5f43a7
-            ret = kbkdf_CounterRaw(&kdf_params, &ctx, output_buffer, buffer_length, output_bitlen);
5f43a7
+            ret = kbkdf_CounterRaw(kdf_params, &ctx, output_buffer, buffer_length, output_bitlen);
5f43a7
             break;
5f43a7
         case CKM_NSS_SP800_108_FEEDBACK_KDF_DERIVE_DATA: /* fall through */
5f43a7
         case CKM_SP800_108_FEEDBACK_KDF:
5f43a7
-            ret = kbkdf_FeedbackRaw(&kdf_params, initial_value, initial_value_length, &ctx, output_buffer, buffer_length, output_bitlen);
5f43a7
+            ret = kbkdf_FeedbackRaw(kdf_params, initial_value, initial_value_length, &ctx, output_buffer, buffer_length, output_bitlen);
5f43a7
             break;
5f43a7
         case CKM_NSS_SP800_108_DOUBLE_PIPELINE_KDF_DERIVE_DATA: /* fall through */
5f43a7
         case CKM_SP800_108_DOUBLE_PIPELINE_KDF:
5f43a7
-            ret = kbkdf_PipelineRaw(&kdf_params, &ctx, output_buffer, buffer_length, output_bitlen);
5f43a7
+            ret = kbkdf_PipelineRaw(kdf_params, &ctx, output_buffer, buffer_length, output_bitlen);
5f43a7
             break;
5f43a7
         default:
5f43a7
             /* Shouldn't happen unless NIST introduces a new KBKDF type. */
5f43a7
@@ -1226,8 +1211,65 @@
5f43a7
         goto finish;
5f43a7
     }
5f43a7
 
5f43a7
+    *out_key_bytes = output_buffer;
5f43a7
+    *out_key_length = buffer_length;
5f43a7
+    *mac_size = ctx.mac_size;
5f43a7
+
5f43a7
+    output_buffer = NULL; /* returning the buffer, don't zero and free it */
5f43a7
+
5f43a7
+finish:
5f43a7
+    PORT_ZFree(output_buffer, buffer_length);
5f43a7
+
5f43a7
+    /* Free the PRF. This should handle clearing all sensitive information. */
5f43a7
+    sftk_MAC_Destroy(&ctx, PR_FALSE);
5f43a7
+    return ret;
5f43a7
+}
5f43a7
+
5f43a7
+/* [ section: PKCS#11 entry ] */
5f43a7
+
5f43a7
+CK_RV
5f43a7
+kbkdf_Dispatch(CK_MECHANISM_TYPE mech, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, SFTKObject *prf_key, SFTKObject *ret_key, CK_ULONG ret_key_size)
5f43a7
+{
5f43a7
+    /* This handles boilerplate common to all KBKDF types. Instead of placing
5f43a7
+     * this in pkcs11c.c, place it here to reduce clutter. */
5f43a7
+
5f43a7
+    CK_RV ret;
5f43a7
+
5f43a7
+    /* Assumptions about our calling environment. */
5f43a7
+    PR_ASSERT(pMechanism != NULL && prf_key != NULL && ret_key != NULL);
5f43a7
+
5f43a7
+    /* Validate that the caller passed parameters. */
5f43a7
+    if (pMechanism->pParameter == NULL) {
5f43a7
+        return CKR_MECHANISM_PARAM_INVALID;
5f43a7
+    }
5f43a7
+
5f43a7
+    /* Create a common set of parameters to use for all KDF types. This
5f43a7
+     * separates out the KDF parameters from the Feedback-specific IV,
5f43a7
+     * allowing us to use a common type for all calls. */
5f43a7
+    CK_SP800_108_KDF_PARAMS kdf_params = { 0 };
5f43a7
+    CK_BYTE_PTR initial_value = NULL;
5f43a7
+    CK_ULONG initial_value_length = 0;
5f43a7
+    unsigned char *output_buffer = NULL;
5f43a7
+    size_t buffer_length = 0;
5f43a7
+    unsigned int mac_size = 0;
5f43a7
+
5f43a7
+    /* Split Feedback-specific IV from remaining KDF parameters. */
5f43a7
+    ret = kbkdf_LoadParameters(mech, pMechanism, &kdf_params, &initial_value, &initial_value_length);
5f43a7
+    if (ret != CKR_OK) {
5f43a7
+        goto finish;
5f43a7
+    }
5f43a7
+    /* let rawDispatch handle the rest. We split this out so we could
5f43a7
+     * handle the POST test without accessing pkcs #11 objects. */
5f43a7
+    ret = kbkdf_RawDispatch(mech, &kdf_params, initial_value,
5f43a7
+                            initial_value_length, prf_key, NULL, 0,
5f43a7
+                            &output_buffer, &buffer_length, &mac_size,
5f43a7
+                            ret_key_size);
5f43a7
+    if (ret != CKR_OK) {
5f43a7
+        goto finish;
5f43a7
+    }
5f43a7
+
5f43a7
     /* Write the output of the PRF into the appropriate keys. */
5f43a7
-    ret = kbkdf_SaveKeys(mech, hSession, &kdf_params, output_buffer, buffer_length, ctx.mac_size, ret_key, ret_key_size);
5f43a7
+    ret = kbkdf_SaveKeys(mech, hSession, &kdf_params, output_buffer, buffer_length, mac_size, ret_key, ret_key_size);
5f43a7
     if (ret != CKR_OK) {
5f43a7
         goto finish;
5f43a7
     }
5f43a7
@@ -1235,8 +1277,242 @@
5f43a7
 finish:
5f43a7
     PORT_ZFree(output_buffer, buffer_length);
5f43a7
 
5f43a7
-    /* Free the PRF. This should handle clearing all sensitive information. */
5f43a7
-    sftk_MAC_Destroy(&ctx, PR_FALSE);
5f43a7
-
5f43a7
     return ret;
5f43a7
 }
5f43a7
+
5f43a7
+struct sftk_SP800_Test_struct {
5f43a7
+    CK_MECHANISM_TYPE mech;
5f43a7
+    CK_SP800_108_KDF_PARAMS kdf_params;
5f43a7
+    unsigned int expected_mac_size;
5f43a7
+    unsigned int ret_key_length;
5f43a7
+    const unsigned char expected_key_bytes[64];
5f43a7
+};
5f43a7
+
5f43a7
+static const CK_SP800_108_COUNTER_FORMAT counter_32 = { 0, 32 };
5f43a7
+static const CK_PRF_DATA_PARAM counter_32_data =
5f43a7
+    { CK_SP800_108_ITERATION_VARIABLE, (CK_VOID_PTR)&counter_32, sizeof(counter_32) };
5f43a7
+
5f43a7
+#ifdef NSS_FULL_POST
5f43a7
+static const CK_SP800_108_COUNTER_FORMAT counter_16 = { 0, 16 };
5f43a7
+static const CK_PRF_DATA_PARAM counter_16_data =
5f43a7
+    { CK_SP800_108_ITERATION_VARIABLE, (CK_VOID_PTR)&counter_16, sizeof(counter_16) };
5f43a7
+static const CK_PRF_DATA_PARAM counter_null_data =
5f43a7
+    { CK_SP800_108_ITERATION_VARIABLE, NULL, 0 };
5f43a7
+#endif
5f43a7
+
5f43a7
+static const struct sftk_SP800_Test_struct sftk_SP800_Tests[] =
5f43a7
+    {
5f43a7
+#ifdef NSS_FULL_POST
5f43a7
+      {
5f43a7
+          CKM_SP800_108_COUNTER_KDF,
5f43a7
+          { CKM_AES_CMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_16_data, 0, NULL },
5f43a7
+          16,
5f43a7
+          64,
5f43a7
+          { 0x7b, 0x1c, 0xe7, 0xf3, 0x14, 0x67, 0x15, 0xdd,
5f43a7
+            0xde, 0x0c, 0x09, 0x46, 0x3f, 0x47, 0x7b, 0xa6,
5f43a7
+            0xb8, 0xba, 0x40, 0x07, 0x7c, 0xe3, 0x19, 0x53,
5f43a7
+            0x26, 0xac, 0x4c, 0x2e, 0x2b, 0x37, 0x41, 0xe4,
5f43a7
+            0x1b, 0x01, 0x3f, 0x2f, 0x2d, 0x16, 0x95, 0xee,
5f43a7
+            0xeb, 0x7e, 0x72, 0x7d, 0xa4, 0xab, 0x2e, 0x67,
5f43a7
+            0x1d, 0xef, 0x6f, 0xa2, 0xc6, 0xee, 0x3c, 0xcf,
5f43a7
+            0xef, 0x88, 0xfd, 0x5c, 0x1d, 0x7b, 0xa0, 0x5a },
5f43a7
+      },
5f43a7
+      {
5f43a7
+          CKM_SP800_108_COUNTER_KDF,
5f43a7
+          { CKM_SHA384_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_32_data, 0, NULL },
5f43a7
+          48,
5f43a7
+          64,
5f43a7
+          { 0xe6, 0x62, 0xa4, 0x32, 0x5c, 0xe4, 0xc2, 0x28,
5f43a7
+            0x73, 0x8a, 0x5d, 0x94, 0xe7, 0x05, 0xe0, 0x5a,
5f43a7
+            0x71, 0x61, 0xb2, 0x3c, 0x51, 0x28, 0x03, 0x1d,
5f43a7
+            0xa7, 0xf5, 0x10, 0x83, 0x34, 0xdb, 0x11, 0x73,
5f43a7
+            0x92, 0xa6, 0x79, 0x74, 0x81, 0x5d, 0x22, 0x7e,
5f43a7
+            0x8d, 0xf2, 0x59, 0x14, 0x56, 0x60, 0xcf, 0xb2,
5f43a7
+            0xb3, 0xfd, 0x46, 0xfd, 0x9b, 0x74, 0xfe, 0x4a,
5f43a7
+            0x09, 0x30, 0x4a, 0xdf, 0x07, 0x43, 0xfe, 0x85 },
5f43a7
+      },
5f43a7
+      {
5f43a7
+          CKM_SP800_108_COUNTER_KDF,
5f43a7
+          { CKM_SHA512_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_32_data, 0, NULL },
5f43a7
+          64,
5f43a7
+          64,
5f43a7
+          { 0xb0, 0x78, 0x36, 0xe1, 0x15, 0xd6, 0xf0, 0xac,
5f43a7
+            0x68, 0x7b, 0x42, 0xd3, 0xb6, 0x82, 0x51, 0xad,
5f43a7
+            0x95, 0x0a, 0x69, 0x88, 0x84, 0xc2, 0x2e, 0x07,
5f43a7
+            0x34, 0x62, 0x8d, 0x42, 0x72, 0x0f, 0x22, 0xe6,
5f43a7
+            0xd5, 0x7f, 0x80, 0x15, 0xe6, 0x84, 0x00, 0x65,
5f43a7
+            0xef, 0x64, 0x77, 0x29, 0xd6, 0x3b, 0xc7, 0x9a,
5f43a7
+            0x15, 0x6d, 0x36, 0xf3, 0x96, 0xc9, 0x14, 0x3f,
5f43a7
+            0x2d, 0x4a, 0x7c, 0xdb, 0xc3, 0x6c, 0x3d, 0x6a },
5f43a7
+      },
5f43a7
+      {
5f43a7
+          CKM_SP800_108_FEEDBACK_KDF,
5f43a7
+          { CKM_AES_CMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL },
5f43a7
+          16,
5f43a7
+          64,
5f43a7
+          { 0xc0, 0xa0, 0x23, 0x96, 0x16, 0x4d, 0xd6, 0xbd,
5f43a7
+            0x2a, 0x75, 0x8e, 0x72, 0xf5, 0xc3, 0xa0, 0xb8,
5f43a7
+            0x78, 0x83, 0x15, 0x21, 0x34, 0xd3, 0xd8, 0x71,
5f43a7
+            0xc9, 0xe7, 0x4b, 0x20, 0xb7, 0x65, 0x5b, 0x13,
5f43a7
+            0xbc, 0x85, 0x54, 0xe3, 0xb6, 0xee, 0x73, 0xd5,
5f43a7
+            0xf2, 0xa0, 0x94, 0x1a, 0x79, 0x66, 0x3b, 0x1e,
5f43a7
+            0x67, 0x3e, 0x69, 0xa4, 0x12, 0x40, 0xa9, 0xda,
5f43a7
+            0x8d, 0x14, 0xb1, 0xce, 0xf1, 0x4b, 0x79, 0x4e },
5f43a7
+      },
5f43a7
+      {
5f43a7
+          CKM_SP800_108_FEEDBACK_KDF,
5f43a7
+          { CKM_SHA256_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL },
5f43a7
+          32,
5f43a7
+          64,
5f43a7
+          { 0x99, 0x9b, 0x08, 0x79, 0x14, 0x2e, 0x58, 0x34,
5f43a7
+            0xd7, 0x92, 0xa7, 0x7e, 0x7f, 0xc2, 0xf0, 0x34,
5f43a7
+            0xa3, 0x4e, 0x33, 0xf0, 0x63, 0x95, 0x2d, 0xad,
5f43a7
+            0xbf, 0x3b, 0xcb, 0x6d, 0x4e, 0x07, 0xd9, 0xe9,
5f43a7
+            0xbd, 0xbd, 0x77, 0x54, 0xe1, 0xa3, 0x36, 0x26,
5f43a7
+            0xcd, 0xb1, 0xf9, 0x2d, 0x80, 0x68, 0xa2, 0x01,
5f43a7
+            0x4e, 0xbf, 0x35, 0xec, 0x65, 0xae, 0xfd, 0x71,
5f43a7
+            0xa6, 0xd7, 0x62, 0x26, 0x2c, 0x3f, 0x73, 0x63 },
5f43a7
+      },
5f43a7
+      {
5f43a7
+          CKM_SP800_108_FEEDBACK_KDF,
5f43a7
+          { CKM_SHA384_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL },
5f43a7
+          48,
5f43a7
+          64,
5f43a7
+          { 0xc8, 0x7a, 0xf8, 0xd9, 0x6b, 0x90, 0x82, 0x35,
5f43a7
+            0xea, 0xf5, 0x2c, 0x8f, 0xce, 0xaa, 0x3b, 0xa5,
5f43a7
+            0x68, 0xd3, 0x7f, 0xae, 0x31, 0x93, 0xe6, 0x69,
5f43a7
+            0x0c, 0xd1, 0x74, 0x7f, 0x8f, 0xc2, 0xe2, 0x33,
5f43a7
+            0x93, 0x45, 0x23, 0xba, 0xb3, 0x73, 0xc9, 0x2c,
5f43a7
+            0xd6, 0xd2, 0x10, 0x16, 0xe9, 0x9f, 0x9e, 0xe8,
5f43a7
+            0xc1, 0x0e, 0x29, 0x95, 0x3d, 0x16, 0x68, 0x24,
5f43a7
+            0x40, 0x4d, 0x40, 0x21, 0x41, 0xa6, 0xc8, 0xdb },
5f43a7
+      },
5f43a7
+      {
5f43a7
+          CKM_SP800_108_FEEDBACK_KDF,
5f43a7
+          { CKM_SHA512_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL },
5f43a7
+          64,
5f43a7
+          64,
5f43a7
+          { 0x81, 0x39, 0x12, 0xc2, 0xf9, 0x31, 0x24, 0x7c,
5f43a7
+            0x71, 0x12, 0x97, 0x08, 0x82, 0x76, 0x83, 0x55,
5f43a7
+            0x8c, 0x82, 0xf3, 0x09, 0xd6, 0x1b, 0x7a, 0xa2,
5f43a7
+            0x6e, 0x71, 0x6b, 0xad, 0x46, 0x57, 0x60, 0x89,
5f43a7
+            0x38, 0xcf, 0x63, 0xfa, 0xf4, 0x38, 0x27, 0xef,
5f43a7
+            0xf0, 0xaf, 0x75, 0x4e, 0xc2, 0xe0, 0x31, 0xdb,
5f43a7
+            0x59, 0x7d, 0x19, 0xc9, 0x6d, 0xbb, 0xed, 0x95,
5f43a7
+            0xaf, 0x3e, 0xd8, 0x33, 0x76, 0xab, 0xec, 0xfa },
5f43a7
+      },
5f43a7
+      {
5f43a7
+          CKM_SP800_108_DOUBLE_PIPELINE_KDF,
5f43a7
+          { CKM_AES_CMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL },
5f43a7
+          16,
5f43a7
+          64,
5f43a7
+          { 0x3e, 0xa8, 0xbf, 0x77, 0x84, 0x90, 0xb0, 0x3a,
5f43a7
+            0x89, 0x16, 0x32, 0x01, 0x92, 0xd3, 0x1f, 0x1b,
5f43a7
+            0xc1, 0x06, 0xc5, 0x32, 0x62, 0x03, 0x50, 0x16,
5f43a7
+            0x3b, 0xb9, 0xa7, 0xdc, 0xb5, 0x68, 0x6a, 0xbb,
5f43a7
+            0xbb, 0x7d, 0x63, 0x69, 0x24, 0x6e, 0x09, 0xd6,
5f43a7
+            0x6f, 0x80, 0x57, 0x65, 0xc5, 0x62, 0x33, 0x96,
5f43a7
+            0x69, 0xe6, 0xab, 0x65, 0x36, 0xd0, 0xe2, 0x5c,
5f43a7
+            0xd7, 0xbd, 0xe4, 0x68, 0x13, 0xd6, 0xb1, 0x46 },
5f43a7
+      },
5f43a7
+      {
5f43a7
+          CKM_SP800_108_DOUBLE_PIPELINE_KDF,
5f43a7
+          { CKM_SHA256_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL },
5f43a7
+          32,
5f43a7
+          64,
5f43a7
+          { 0xeb, 0x28, 0xd9, 0x2c, 0x19, 0x33, 0xb9, 0x2a,
5f43a7
+            0xf9, 0xac, 0x85, 0xbd, 0xf4, 0xdb, 0xfa, 0x88,
5f43a7
+            0x73, 0xf4, 0x36, 0x08, 0xdb, 0xfe, 0x13, 0xd1,
5f43a7
+            0x5a, 0xec, 0x7b, 0x68, 0x13, 0x53, 0xb3, 0xd1,
5f43a7
+            0x31, 0xf2, 0x83, 0xae, 0x9f, 0x75, 0x47, 0xb6,
5f43a7
+            0x6d, 0x3c, 0x20, 0x16, 0x47, 0x9c, 0x27, 0x66,
5f43a7
+            0xec, 0xa9, 0xdf, 0x0c, 0xda, 0x2a, 0xf9, 0xf4,
5f43a7
+            0x55, 0x74, 0xde, 0x9d, 0x3f, 0xe3, 0x5e, 0x14 },
5f43a7
+      },
5f43a7
+      {
5f43a7
+          CKM_SP800_108_DOUBLE_PIPELINE_KDF,
5f43a7
+          { CKM_SHA384_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL },
5f43a7
+          48,
5f43a7
+          64,
5f43a7
+          { 0xa5, 0xca, 0x32, 0x40, 0x00, 0x93, 0xb2, 0xcc,
5f43a7
+            0x78, 0x3c, 0xa6, 0xc4, 0xaf, 0xa8, 0xb3, 0xd0,
5f43a7
+            0xa4, 0x6b, 0xb5, 0x31, 0x35, 0x87, 0x33, 0xa2,
5f43a7
+            0x6a, 0x6b, 0xe1, 0xff, 0xea, 0x1d, 0x6e, 0x9e,
5f43a7
+            0x0b, 0xde, 0x8b, 0x92, 0x15, 0xd6, 0x56, 0x2f,
5f43a7
+            0xb6, 0x1a, 0xd7, 0xd2, 0x01, 0x3e, 0x28, 0x2e,
5f43a7
+            0xfa, 0x84, 0x3c, 0xc0, 0xe8, 0xbe, 0x94, 0xc0,
5f43a7
+            0x06, 0xbd, 0xbf, 0x87, 0x1f, 0xb8, 0x64, 0xc2 },
5f43a7
+      },
5f43a7
+      {
5f43a7
+          CKM_SP800_108_DOUBLE_PIPELINE_KDF,
5f43a7
+          { CKM_SHA512_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL },
5f43a7
+          64,
5f43a7
+          64,
5f43a7
+          { 0x3f, 0xd9, 0x4e, 0x80, 0x58, 0x21, 0xc8, 0xea,
5f43a7
+            0x22, 0x17, 0xcf, 0x7d, 0xce, 0xfd, 0xec, 0x03,
5f43a7
+            0xb9, 0xe4, 0xa2, 0xf7, 0xc0, 0xf1, 0x68, 0x81,
5f43a7
+            0x53, 0x71, 0xb7, 0x42, 0x14, 0x4e, 0x5b, 0x09,
5f43a7
+            0x05, 0x31, 0xb9, 0x27, 0x18, 0x2d, 0x23, 0xf8,
5f43a7
+            0x9c, 0x3d, 0x4e, 0xd0, 0xdd, 0xf3, 0x1e, 0x4b,
5f43a7
+            0xf2, 0xf9, 0x1a, 0x5d, 0x00, 0x66, 0x22, 0x83,
5f43a7
+            0xae, 0x3c, 0x53, 0xd2, 0x54, 0x4b, 0x06, 0x4c },
5f43a7
+      },
5f43a7
+#endif
5f43a7
+      {
5f43a7
+          CKM_SP800_108_COUNTER_KDF,
5f43a7
+          { CKM_SHA256_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_32_data, 0, NULL },
5f43a7
+          32,
5f43a7
+          64,
5f43a7
+          { 0xfb, 0x2b, 0xb5, 0xde, 0xce, 0x5a, 0x2b, 0xdc,
5f43a7
+            0x25, 0x8f, 0x54, 0x17, 0x4b, 0x5a, 0xa7, 0x90,
5f43a7
+            0x64, 0x36, 0xeb, 0x43, 0x1f, 0x1d, 0xf9, 0x23,
5f43a7
+            0xb2, 0x22, 0x29, 0xa0, 0xfa, 0x2e, 0x21, 0xb6,
5f43a7
+            0xb7, 0xfb, 0x27, 0x0a, 0x1c, 0xa6, 0x58, 0x43,
5f43a7
+            0xa1, 0x16, 0x44, 0x29, 0x4b, 0x1c, 0xb3, 0x72,
5f43a7
+            0xd5, 0x98, 0x9d, 0x27, 0xd5, 0x75, 0x25, 0xbf,
5f43a7
+            0x23, 0x61, 0x40, 0x48, 0xbb, 0x0b, 0x49, 0x8e },
5f43a7
+      }
5f43a7
+    };
5f43a7
+
5f43a7
+SECStatus
5f43a7
+sftk_fips_SP800_108_PowerUpSelfTests(void)
5f43a7
+{
5f43a7
+    int i;
5f43a7
+    CK_RV crv;
5f43a7
+
5f43a7
+    const unsigned char prf_key[] = {
5f43a7
+        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
5f43a7
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
5f43a7
+        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
5f43a7
+        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
5f43a7
+        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
5f43a7
+        0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
5f43a7
+        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
5f43a7
+        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78
5f43a7
+    };
5f43a7
+    for (i = 0; i < PR_ARRAY_SIZE(sftk_SP800_Tests); i++) {
5f43a7
+        const struct sftk_SP800_Test_struct *test = &sftk_SP800_Tests[i];
5f43a7
+        unsigned char *output_buffer;
5f43a7
+        size_t buffer_length;
5f43a7
+        unsigned int mac_size;
5f43a7
+
5f43a7
+        crv = kbkdf_RawDispatch(test->mech, &test->kdf_params,
5f43a7
+                                prf_key, test->expected_mac_size,
5f43a7
+                                NULL, prf_key, test->expected_mac_size,
5f43a7
+                                &output_buffer, &buffer_length, &mac_size,
5f43a7
+                                test->ret_key_length);
5f43a7
+        if (crv != CKR_OK) {
5f43a7
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
5f43a7
+            return SECFailure;
5f43a7
+        }
5f43a7
+        if ((mac_size != test->expected_mac_size) ||
5f43a7
+            (buffer_length != test->ret_key_length) ||
5f43a7
+            (output_buffer == NULL) ||
5f43a7
+            (PORT_Memcmp(output_buffer, test->expected_key_bytes, buffer_length) != 0)) {
5f43a7
+            PORT_ZFree(output_buffer, buffer_length);
5f43a7
+            return SECFailure;
5f43a7
+        }
5f43a7
+        PORT_ZFree(output_buffer, buffer_length);
5f43a7
+    }
5f43a7
+    return SECSuccess;
5f43a7
+}
5f43a7
diff --git a/lib/softoken/lowpbe.h b/lib/softoken/lowpbe.h
5f43a7
--- a/lib/softoken/lowpbe.h
5f43a7
+++ b/lib/softoken/lowpbe.h
5f43a7
@@ -103,6 +103,10 @@
5f43a7
 HASH_HashType HASH_FromHMACOid(SECOidTag oid);
5f43a7
 SECOidTag HASH_HMACOidFromHash(HASH_HashType);
5f43a7
 
5f43a7
+/* fips selftest */
5f43a7
+extern SECStatus
5f43a7
+sftk_fips_pbkdf_PowerUpSelfTests(void);
5f43a7
+
5f43a7
 SEC_END_PROTOS
5f43a7
 
5f43a7
 #endif
5f43a7
diff --git a/lib/softoken/lowpbe.c b/lib/softoken/lowpbe.c
5f43a7
--- a/lib/softoken/lowpbe.c
5f43a7
+++ b/lib/softoken/lowpbe.c
5f43a7
@@ -1743,3 +1743,67 @@
5f43a7
 
5f43a7
     return ret_algid;
5f43a7
 }
5f43a7
+
5f43a7
+#define TEST_KEY "pbkdf test key"
5f43a7
+SECStatus
5f43a7
+sftk_fips_pbkdf_PowerUpSelfTests(void)
5f43a7
+{
5f43a7
+    SECItem *result;
5f43a7
+    SECItem inKey;
5f43a7
+    NSSPKCS5PBEParameter pbe_params;
5f43a7
+    unsigned char iteration_count = 5;
5f43a7
+    unsigned char keyLen = 64;
5f43a7
+    char *inKeyData = TEST_KEY;
5f43a7
+    static const unsigned char saltData[] =
5f43a7
+        { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
5f43a7
+    static const unsigned char pbkdf_known_answer[] = {
5f43a7
+        0x31, 0xf0, 0xe5, 0x39, 0x9f, 0x39, 0xb9, 0x29,
5f43a7
+        0x68, 0xac, 0xf2, 0xe9, 0x53, 0x9b, 0xb4, 0x9c,
5f43a7
+        0x28, 0x59, 0x8b, 0x5c, 0xd8, 0xd4, 0x02, 0x37,
5f43a7
+        0x18, 0x22, 0xc1, 0x92, 0xd0, 0xfa, 0x72, 0x90,
5f43a7
+        0x2c, 0x8d, 0x19, 0xd4, 0x56, 0xfb, 0x16, 0xfa,
5f43a7
+        0x8d, 0x5c, 0x06, 0x33, 0xd1, 0x5f, 0x17, 0xb1,
5f43a7
+        0x22, 0xd9, 0x9c, 0xaf, 0x5e, 0x3f, 0xf3, 0x66,
5f43a7
+        0xc6, 0x14, 0xfe, 0x83, 0xfa, 0x1a, 0x2a, 0xc5
5f43a7
+    };
5f43a7
+
5f43a7
+    sftk_PBELockInit();
5f43a7
+
5f43a7
+    inKey.data = (unsigned char *)inKeyData;
5f43a7
+    inKey.len = sizeof(TEST_KEY) - 1;
5f43a7
+
5f43a7
+    pbe_params.salt.data = (unsigned char *)saltData;
5f43a7
+    pbe_params.salt.len = sizeof(saltData);
5f43a7
+    /* the interation and keyLength are used as intermediate
5f43a7
+     * values when decoding the Algorithm ID, set them for completeness,
5f43a7
+     * but they are not used */
5f43a7
+    pbe_params.iteration.data = &iteration_count;
5f43a7
+    pbe_params.iteration.len = 1;
5f43a7
+    pbe_params.keyLength.data = &keyLen;
5f43a7
+    pbe_params.keyLength.len = 1;
5f43a7
+    /* pkcs5v2 stores the key in the AlgorithmID, so we don't need to
5f43a7
+     * generate it here */
5f43a7
+    pbe_params.ivLen = 0;
5f43a7
+    pbe_params.ivData = NULL;
5f43a7
+    /* keyID is only used by pkcs12 extensions to pkcs5v1 */
5f43a7
+    pbe_params.keyID = pbeBitGenCipherKey;
5f43a7
+    /* Algorithm is used by the decryption code after get get our key */
5f43a7
+    pbe_params.encAlg = SEC_OID_AES_256_CBC;
5f43a7
+    /* these are the fields actually used in nsspkcs5_ComputeKeyAndIV
5f43a7
+     * for NSSPKCS5_PBKDF2 */
5f43a7
+    pbe_params.iter = iteration_count;
5f43a7
+    pbe_params.keyLen = keyLen;
5f43a7
+    pbe_params.hashType = HASH_AlgSHA256;
5f43a7
+    pbe_params.pbeType = NSSPKCS5_PBKDF2;
5f43a7
+    pbe_params.is2KeyDES = PR_FALSE;
5f43a7
+
5f43a7
+    result = nsspkcs5_ComputeKeyAndIV(&pbe_params, &inKey, NULL, PR_FALSE);
5f43a7
+    if ((result == NULL) || (result->len != sizeof(pbkdf_known_answer)) ||
5f43a7
+        (PORT_Memcmp(result->data, pbkdf_known_answer, sizeof(pbkdf_known_answer)) != 0)) {
5f43a7
+        SECITEM_FreeItem(result, PR_TRUE);
5f43a7
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
5f43a7
+        return SECFailure;
5f43a7
+    }
5f43a7
+    SECITEM_FreeItem(result, PR_TRUE);
5f43a7
+    return SECSuccess;
5f43a7
+}
5f43a7
diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
5f43a7
--- a/lib/softoken/pkcs11c.c
5f43a7
+++ b/lib/softoken/pkcs11c.c
5f43a7
@@ -6856,9 +6856,9 @@
5f43a7
 
5f43a7
 CK_RV
5f43a7
 sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_SESSION_HANDLE hSession,
5f43a7
-          SFTKObject *sourceKey, unsigned char *sourceKeyBytes,
5f43a7
-          int sourceKeyLen, SFTKObject *key, int keySize,
5f43a7
-          PRBool canBeData, PRBool isFIPS)
5f43a7
+          SFTKObject *sourceKey, const unsigned char *sourceKeyBytes,
5f43a7
+          int sourceKeyLen, SFTKObject *key, unsigned char *outKeyBytes,
5f43a7
+          int keySize, PRBool canBeData, PRBool isFIPS)
5f43a7
 {
5f43a7
     SFTKSession *session;
5f43a7
     SFTKAttribute *saltKey_att = NULL;
5f43a7
@@ -6869,9 +6869,9 @@
5f43a7
     unsigned char keyBlock[9 * SFTK_MAX_MAC_LENGTH];
5f43a7
     unsigned char *keyBlockAlloc = NULL;    /* allocated keyBlock */
5f43a7
     unsigned char *keyBlockData = keyBlock; /* pointer to current keyBlock */
5f43a7
-    unsigned char *prk;                     /* psuedo-random key */
5f43a7
+    const unsigned char *prk;               /* psuedo-random key */
5f43a7
     CK_ULONG prkLen;
5f43a7
-    unsigned char *okm; /* output keying material */
5f43a7
+    const unsigned char *okm; /* output keying material */
5f43a7
     HASH_HashType hashType = GetHashTypeFromMechanism(params->prfHashMechanism);
5f43a7
     SFTKObject *saltKey = NULL;
5f43a7
     CK_RV crv = CKR_OK;
5f43a7
@@ -6896,9 +6896,14 @@
5f43a7
         (params->bExpand && keySize > 255 * hashLen)) {
5f43a7
         return CKR_TEMPLATE_INCONSISTENT;
5f43a7
     }
5f43a7
-    crv = sftk_DeriveSensitiveCheck(sourceKey, key, canBeData);
5f43a7
-    if (crv != CKR_OK)
5f43a7
-        return crv;
5f43a7
+
5f43a7
+    /* sourceKey is NULL if we are called from the POST, skip the
5f43a7
+     * sensitiveCheck */
5f43a7
+    if (sourceKey != NULL) {
5f43a7
+        crv = sftk_DeriveSensitiveCheck(sourceKey, key, canBeData);
5f43a7
+        if (crv != CKR_OK)
5f43a7
+            return crv;
5f43a7
+    }
5f43a7
 
5f43a7
     /* HKDF-Extract(salt, base key value) */
5f43a7
     if (params->bExtract) {
5f43a7
@@ -7014,9 +7019,15 @@
5f43a7
         HMAC_Destroy(hmac, PR_TRUE);
5f43a7
         okm = &keyBlockData[0];
5f43a7
     }
5f43a7
-    /* key material = prk */
5f43a7
-    crv = sftk_forceAttribute(key, CKA_VALUE, okm, keySize);
5f43a7
-    PORT_Memset(okm, 0, genLen);
5f43a7
+    /* key material = okm */
5f43a7
+    crv = CKR_OK;
5f43a7
+    if (key) {
5f43a7
+        crv = sftk_forceAttribute(key, CKA_VALUE, okm, keySize);
5f43a7
+    } else {
5f43a7
+        PORT_Assert(outKeyBytes != NULL);
5f43a7
+        PORT_Memcpy(outKeyBytes, okm, keySize);
5f43a7
+    }
5f43a7
+    PORT_Memset(keyBlockData, 0, genLen);
5f43a7
     PORT_Memset(hashbuf, 0, sizeof(hashbuf));
5f43a7
     PORT_Free(keyBlockAlloc);
5f43a7
     return CKR_OK;
5f43a7
@@ -8568,7 +8579,7 @@
5f43a7
 
5f43a7
             crv = sftk_HKDF(&hkdfParams, hSession, sourceKey,
5f43a7
                             att->attrib.pValue, att->attrib.ulValueLen,
5f43a7
-                            key, keySize, PR_FALSE, isFIPS);
5f43a7
+                            key, NULL, keySize, PR_FALSE, isFIPS);
5f43a7
         } break;
5f43a7
         case CKM_HKDF_DERIVE:
5f43a7
         case CKM_HKDF_DATA: /* only difference is the class of key */
5f43a7
@@ -8579,7 +8590,7 @@
5f43a7
             }
5f43a7
             crv = sftk_HKDF((CK_HKDF_PARAMS_PTR)pMechanism->pParameter,
5f43a7
                             hSession, sourceKey, att->attrib.pValue,
5f43a7
-                            att->attrib.ulValueLen, key, keySize, PR_TRUE,
5f43a7
+                            att->attrib.ulValueLen, key, NULL, keySize, PR_TRUE,
5f43a7
                             isFIPS);
5f43a7
             break;
5f43a7
         case CKM_NSS_JPAKE_ROUND2_SHA1:
5f43a7
diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h
5f43a7
--- a/lib/softoken/pkcs11i.h
5f43a7
+++ b/lib/softoken/pkcs11i.h
5f43a7
@@ -900,7 +900,7 @@
5f43a7
 CK_RV sftk_MAC_Create(CK_MECHANISM_TYPE mech, SFTKObject *key, sftk_MACCtx **ret_ctx);
5f43a7
 CK_RV sftk_MAC_Init(sftk_MACCtx *ctx, CK_MECHANISM_TYPE mech, SFTKObject *key);
5f43a7
 CK_RV sftk_MAC_InitRaw(sftk_MACCtx *ctx, CK_MECHANISM_TYPE mech, const unsigned char *key, unsigned int key_len, PRBool isFIPS);
5f43a7
-CK_RV sftk_MAC_Update(sftk_MACCtx *ctx, CK_BYTE_PTR data, unsigned int data_len);
5f43a7
+CK_RV sftk_MAC_Update(sftk_MACCtx *ctx, const CK_BYTE *data, unsigned int data_len);
5f43a7
 CK_RV sftk_MAC_Finish(sftk_MACCtx *ctx, CK_BYTE_PTR result, unsigned int *result_len, unsigned int max_result_len);
5f43a7
 CK_RV sftk_MAC_Reset(sftk_MACCtx *ctx);
5f43a7
 void sftk_MAC_Destroy(sftk_MACCtx *ctx, PRBool free_it);
5f43a7
@@ -912,6 +912,15 @@
5f43a7
 
5f43a7
 /* NIST 800-108 (kbkdf.c) implementations */
5f43a7
 extern CK_RV kbkdf_Dispatch(CK_MECHANISM_TYPE mech, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, SFTKObject *base_key, SFTKObject *ret_key, CK_ULONG keySize);
5f43a7
+extern SECStatus sftk_fips_SP800_108_PowerUpSelfTests(void);
5f43a7
+
5f43a7
+/* export the HKDF function for use in PowerupSelfTests */
5f43a7
+CK_RV sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_SESSION_HANDLE hSession,
5f43a7
+                SFTKObject *sourceKey, const unsigned char *sourceKeyBytes,
5f43a7
+                int sourceKeyLen, SFTKObject *key,
5f43a7
+                unsigned char *outKeyBytes, int keySize,
5f43a7
+                PRBool canBeData, PRBool isFIPS);
5f43a7
+
5f43a7
 char **NSC_ModuleDBFunc(unsigned long function, char *parameters, void *args);
5f43a7
 
5f43a7
 /* dh verify functions */
5f43a7
diff --git a/lib/softoken/sftkhmac.c b/lib/softoken/sftkhmac.c
5f43a7
--- a/lib/softoken/sftkhmac.c
5f43a7
+++ b/lib/softoken/sftkhmac.c
5f43a7
@@ -355,7 +355,7 @@
5f43a7
 }
5f43a7
 
5f43a7
 CK_RV
5f43a7
-sftk_MAC_Update(sftk_MACCtx *ctx, CK_BYTE_PTR data, unsigned int data_len)
5f43a7
+sftk_MAC_Update(sftk_MACCtx *ctx, const CK_BYTE *data, unsigned int data_len)
5f43a7
 {
5f43a7
     switch (ctx->mech) {
5f43a7
         case CKM_MD2_HMAC:
5f43a7
diff --git a/lib/softoken/sftkike.c b/lib/softoken/sftkike.c
5f43a7
--- a/lib/softoken/sftkike.c
5f43a7
+++ b/lib/softoken/sftkike.c
5f43a7
@@ -855,10 +855,12 @@
5f43a7
  * K = inKey, S = seedKey | seedData
5f43a7
  */
5f43a7
 
5f43a7
-CK_RV
5f43a7
-sftk_ike_prf_plus(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey,
5f43a7
-                  const CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS *params, SFTKObject *outKey,
5f43a7
-                  unsigned int keySize)
5f43a7
+static CK_RV
5f43a7
+sftk_ike_prf_plus_raw(CK_SESSION_HANDLE hSession,
5f43a7
+                      const unsigned char *inKeyData, CK_ULONG inKeyLen,
5f43a7
+                      const CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS *params,
5f43a7
+                      unsigned char **outKeyDataPtr, unsigned int *outKeySizePtr,
5f43a7
+                      unsigned int keySize)
5f43a7
 {
5f43a7
     SFTKAttribute *seedValue = NULL;
5f43a7
     SFTKObject *seedKeyObj = NULL;
5f43a7
@@ -924,8 +926,7 @@
5f43a7
             crv = CKR_KEY_SIZE_RANGE;
5f43a7
             goto fail;
5f43a7
         }
5f43a7
-        crv = prf_init(&context, inKey->attrib.pValue,
5f43a7
-                       inKey->attrib.ulValueLen);
5f43a7
+        crv = prf_init(&context, inKeyData, inKeyLen);
5f43a7
         if (crv != CKR_OK) {
5f43a7
             goto fail;
5f43a7
         }
5f43a7
@@ -964,7 +965,9 @@
5f43a7
         lastKey = thisKey;
5f43a7
         thisKey += macSize;
5f43a7
     }
5f43a7
-    crv = sftk_forceAttribute(outKey, CKA_VALUE, outKeyData, keySize);
5f43a7
+    *outKeyDataPtr = outKeyData;
5f43a7
+    *outKeySizePtr = outKeySize;
5f43a7
+    outKeyData = NULL; /* don't free it here, our caller will free it */
5f43a7
 fail:
5f43a7
     if (outKeyData) {
5f43a7
         PORT_ZFree(outKeyData, outKeySize);
5f43a7
@@ -979,6 +982,30 @@
5f43a7
     return crv;
5f43a7
 }
5f43a7
 
5f43a7
+/*
5f43a7
+ * ike prf + with code to deliever results tosoftoken objects.
5f43a7
+ */
5f43a7
+CK_RV
5f43a7
+sftk_ike_prf_plus(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey,
5f43a7
+                  const CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS *params, SFTKObject *outKey,
5f43a7
+                  unsigned int keySize)
5f43a7
+{
5f43a7
+    unsigned char *outKeyData = NULL;
5f43a7
+    unsigned int outKeySize;
5f43a7
+    CK_RV crv;
5f43a7
+
5f43a7
+    crv = sftk_ike_prf_plus_raw(hSession, inKey->attrib.pValue,
5f43a7
+                                inKey->attrib.ulValueLen, params,
5f43a7
+                                &outKeyData, &outKeySize, keySize);
5f43a7
+    if (crv != CKR_OK) {
5f43a7
+        return crv;
5f43a7
+    }
5f43a7
+
5f43a7
+    crv = sftk_forceAttribute(outKey, CKA_VALUE, outKeyData, keySize);
5f43a7
+    PORT_ZFree(outKeyData, outKeySize);
5f43a7
+    return crv;
5f43a7
+}
5f43a7
+
5f43a7
 /* sftk_aes_xcbc_new_keys:
5f43a7
  *
5f43a7
  * aes xcbc creates 3 new keys from the input key. The first key will be the
5f43a7
@@ -1294,7 +1321,21 @@
5f43a7
         0x7f, 0x6f, 0x77, 0x2e, 0x5d, 0x65, 0xb5, 0x8e,
5f43a7
         0xb1, 0x13, 0x40, 0x96, 0xe8, 0x47, 0x8d, 0x2b
5f43a7
     };
5f43a7
+    static const PRUint8 ike_known_sha256_prf_plus[] = {
5f43a7
+        0xe6, 0xf1, 0x9b, 0x4a, 0x02, 0xe9, 0x73, 0x72,
5f43a7
+        0x93, 0x9f, 0xdb, 0x46, 0x1d, 0xb1, 0x49, 0xcb,
5f43a7
+        0x53, 0x08, 0x98, 0x3d, 0x41, 0x36, 0xfa, 0x8b,
5f43a7
+        0x47, 0x04, 0x49, 0x11, 0x0d, 0x6e, 0x96, 0x1d,
5f43a7
+        0xab, 0xbe, 0x94, 0x28, 0xa0, 0xb7, 0x9c, 0xa3,
5f43a7
+        0x29, 0xe1, 0x40, 0xf8, 0xf8, 0x88, 0xb9, 0xb5,
5f43a7
+        0x40, 0xd4, 0x54, 0x4d, 0x25, 0xab, 0x94, 0xd4,
5f43a7
+        0x98, 0xd8, 0x00, 0xbf, 0x6f, 0xef, 0xe8, 0x39
5f43a7
+    };
5f43a7
     SECStatus rv;
5f43a7
+    CK_RV crv;
5f43a7
+    unsigned char *outKeyData = NULL;
5f43a7
+    unsigned int outKeySize;
5f43a7
+    CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS ike_params;
5f43a7
 
5f43a7
     rv = prf_test(CKM_AES_XCBC_MAC,
5f43a7
                   ike_xcbc_known_key, sizeof(ike_xcbc_known_key),
5f43a7
@@ -1345,5 +1386,23 @@
5f43a7
                   ike_sha512_known_plain_text,
5f43a7
                   sizeof(ike_sha512_known_plain_text),
5f43a7
                   ike_sha512_known_mac, sizeof(ike_sha512_known_mac));
5f43a7
+
5f43a7
+    ike_params.prfMechanism = CKM_SHA256_HMAC;
5f43a7
+    ike_params.bHasSeedKey = PR_FALSE;
5f43a7
+    ike_params.hSeedKey = CK_INVALID_HANDLE;
5f43a7
+    ike_params.pSeedData = (CK_BYTE_PTR)ike_sha256_known_plain_text;
5f43a7
+    ike_params.ulSeedDataLen = sizeof(ike_sha256_known_plain_text);
5f43a7
+    crv = sftk_ike_prf_plus_raw(CK_INVALID_HANDLE, ike_sha256_known_key,
5f43a7
+                                sizeof(ike_sha256_known_key), &ike_params,
5f43a7
+                                &outKeyData, &outKeySize, 64);
5f43a7
+    if ((crv != CKR_OK) ||
5f43a7
+        (outKeySize != sizeof(ike_known_sha256_prf_plus)) ||
5f43a7
+        (PORT_Memcmp(outKeyData, ike_known_sha256_prf_plus,
5f43a7
+                     sizeof(ike_known_sha256_prf_plus)) != 0)) {
5f43a7
+        PORT_ZFree(outKeyData, outKeySize);
5f43a7
+        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
5f43a7
+        return SECFailure;
5f43a7
+    }
5f43a7
+    PORT_ZFree(outKeyData, outKeySize);
5f43a7
     return rv;
5f43a7
 }
5f43a7