--- a/lib/freebl/fipsfreebl.c
+++ b/lib/freebl/fipsfreebl.c
@@ -12,16 +12,17 @@
#endif
#include "blapi.h"
#include "seccomon.h" /* Required for RSA and DSA. */
#include "secerr.h"
#include "prtypes.h"
#include "secitem.h"
#include "pkcs11t.h"
+#include "cmac.h"
#include "ec.h" /* Required for EC */
/*
* different platforms have different ways of calling and initial entry point
* when the dll/.so is loaded. Most platforms support either a posix pragma
* or the GCC attribute. Some platforms suppor a pre-defined name, and some
* platforms have a link line way of invoking this function.
@@ -94,16 +95,17 @@ BOOL WINAPI DllMain(
/* FIPS preprocessor directives for DES3-CBC and DES3-ECB. */
#define FIPS_DES3_ENCRYPT_LENGTH 8 /* 64-bits */
#define FIPS_DES3_DECRYPT_LENGTH 8 /* 64-bits */
/* FIPS preprocessor directives for AES-ECB and AES-CBC. */
#define FIPS_AES_BLOCK_SIZE 16 /* 128-bits */
#define FIPS_AES_ENCRYPT_LENGTH 16 /* 128-bits */
#define FIPS_AES_DECRYPT_LENGTH 16 /* 128-bits */
+#define FIPS_AES_CMAC_LENGTH 16 /* 128-bits */
#define FIPS_AES_128_KEY_SIZE 16 /* 128-bits */
#define FIPS_AES_192_KEY_SIZE 24 /* 192-bits */
#define FIPS_AES_256_KEY_SIZE 32 /* 256-bits */
/* FIPS preprocessor directives for message digests */
#define FIPS_KNOWN_HASH_MESSAGE_LENGTH 64 /* 512-bits */
/* FIPS preprocessor directives for RSA. */
@@ -305,16 +307,21 @@ freebl_fips_AES_PowerUpSelfTest(int aes_
static const PRUint8 aes_gcm128_known_ciphertext[] = {
0x63, 0xf4, 0x95, 0x28, 0xe6, 0x78, 0xee, 0x6e,
0x4f, 0xe0, 0xfc, 0x8d, 0xd7, 0xa2, 0xb1, 0xff,
0x0c, 0x97, 0x1b, 0x0a, 0xdd, 0x97, 0x75, 0xed,
0x8b, 0xde, 0xbf, 0x16, 0x5e, 0x57, 0x6b, 0x4f
};
+ static const PRUint8 aes_cmac128_known_ciphertext[] = {
+ 0x54, 0x11, 0xe2, 0x57, 0xbd, 0x2a, 0xdf, 0x9d,
+ 0x1a, 0x89, 0x72, 0x80, 0x84, 0x4c, 0x7e, 0x93
+ };
+
/* AES Known Ciphertext (192-bit key). */
static const PRUint8 aes_ecb192_known_ciphertext[] = {
0xa0, 0x18, 0x62, 0xed, 0x88, 0x19, 0xcb, 0x62,
0x88, 0x1d, 0x4d, 0xfe, 0x84, 0x02, 0x89, 0x0e
};
static const PRUint8 aes_cbc192_known_ciphertext[] = {
0x83, 0xf7, 0xa4, 0x76, 0xd1, 0x6f, 0x07, 0xbe,
@@ -323,16 +330,21 @@ freebl_fips_AES_PowerUpSelfTest(int aes_
static const PRUint8 aes_gcm192_known_ciphertext[] = {
0xc1, 0x0b, 0x92, 0x1d, 0x68, 0x21, 0xf4, 0x25,
0x41, 0x61, 0x20, 0x2d, 0x59, 0x7f, 0x53, 0xde,
0x93, 0x39, 0xab, 0x09, 0x76, 0x41, 0x57, 0x2b,
0x90, 0x2e, 0x44, 0xbb, 0x52, 0x03, 0xe9, 0x07
};
+ static const PRUint8 aes_cmac192_known_ciphertext[] = {
+ 0x0e, 0x07, 0x99, 0x1e, 0xf6, 0xee, 0xfa, 0x2c,
+ 0x1b, 0xfc, 0xce, 0x94, 0x92, 0x2d, 0xf1, 0xab
+ };
+
/* AES Known Ciphertext (256-bit key). */
static const PRUint8 aes_ecb256_known_ciphertext[] = {
0xdb, 0xa6, 0x52, 0x01, 0x8a, 0x70, 0xae, 0x66,
0x3a, 0x99, 0xd8, 0x95, 0x7f, 0xfb, 0x01, 0x67
};
static const PRUint8 aes_cbc256_known_ciphertext[] = {
0x37, 0xea, 0x07, 0x06, 0x31, 0x1c, 0x59, 0x27,
@@ -341,29 +353,39 @@ freebl_fips_AES_PowerUpSelfTest(int aes_
static const PRUint8 aes_gcm256_known_ciphertext[] = {
0x5d, 0x9e, 0xd2, 0xa2, 0x74, 0x9c, 0xd9, 0x1c,
0xd1, 0xc9, 0xee, 0x5d, 0xb6, 0xf2, 0xc9, 0xb6,
0x79, 0x27, 0x53, 0x02, 0xa3, 0xdc, 0x22, 0xce,
0xf4, 0xb0, 0xc1, 0x8c, 0x86, 0x51, 0xf5, 0xa1
};
+ static const PRUint8 aes_cmac256_known_ciphertext[] = {
+ 0xc1, 0x26, 0x69, 0x32, 0x51, 0x13, 0x65, 0xac,
+ 0x71, 0x23, 0xe4, 0xe7, 0xb9, 0x0c, 0x88, 0x9f
+
+ };
+
const PRUint8 *aes_ecb_known_ciphertext =
(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;
const PRUint8 *aes_cbc_known_ciphertext =
(aes_key_size == FIPS_AES_128_KEY_SIZE) ? aes_cbc128_known_ciphertext : (aes_key_size == FIPS_AES_192_KEY_SIZE) ? aes_cbc192_known_ciphertext : aes_cbc256_known_ciphertext;
const PRUint8 *aes_gcm_known_ciphertext =
(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;
+ const PRUint8 *aes_cmac_known_ciphertext =
+ (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;
+
/* AES variables. */
PRUint8 aes_computed_ciphertext[FIPS_AES_ENCRYPT_LENGTH * 2];
PRUint8 aes_computed_plaintext[FIPS_AES_DECRYPT_LENGTH * 2];
AESContext *aes_context;
+ CMACContext *cmac_context;
unsigned int aes_bytes_encrypted;
unsigned int aes_bytes_decrypted;
CK_NSS_GCM_PARAMS gcmParams;
SECStatus aes_status;
/*check if aes_key_size is 128, 192, or 256 bits */
if ((aes_key_size != FIPS_AES_128_KEY_SIZE) &&
(aes_key_size != FIPS_AES_192_KEY_SIZE) &&
@@ -542,16 +564,54 @@ freebl_fips_AES_PowerUpSelfTest(int aes_
if ((aes_status != SECSuccess) ||
(aes_bytes_decrypted != FIPS_AES_DECRYPT_LENGTH) ||
(PORT_Memcmp(aes_computed_plaintext, aes_known_plaintext,
FIPS_AES_DECRYPT_LENGTH) != 0)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return (SECFailure);
}
+ /******************************************************/
+ /* AES-CMAC Known Answer Encryption Test. */
+ /******************************************************/
+ cmac_context = CMAC_Create(CMAC_AES, aes_known_key, aes_key_size);
+
+ if (cmac_context == NULL) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return (SECFailure);
+ }
+
+ aes_status = CMAC_Begin(cmac_context);
+ if (aes_status != SECSuccess) {
+ CMAC_Destroy(cmac_context, PR_TRUE);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return (SECFailure);
+ }
+
+ aes_status = CMAC_Update(cmac_context, aes_known_plaintext,
+ FIPS_AES_DECRYPT_LENGTH);
+ if (aes_status != SECSuccess) {
+ CMAC_Destroy(cmac_context, PR_TRUE);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return (SECFailure);
+ }
+
+ aes_status = CMAC_Finish(cmac_context, aes_computed_ciphertext,
+ &aes_bytes_encrypted, FIPS_AES_CMAC_LENGTH);
+
+ CMAC_Destroy(cmac_context, PR_TRUE);
+
+ if ((aes_status != SECSuccess) ||
+ (aes_bytes_encrypted != FIPS_AES_CMAC_LENGTH) ||
+ (PORT_Memcmp(aes_computed_ciphertext, aes_cmac_known_ciphertext,
+ FIPS_AES_CMAC_LENGTH) != 0)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return (SECFailure);
+ }
+
return (SECSuccess);
}
/* Known Hash Message (512-bits). Used for all hashes (incl. SHA-N [N>1]). */
static const PRUint8 known_hash_message[] = {
"The test message for the MD2, MD5, and SHA-1 hashing algorithms."
};
@@ -738,16 +798,180 @@ freebl_fips_HMAC_PowerUpSelfTest(void)
SHA512_LENGTH) != 0)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return (SECFailure);
}
return (SECSuccess);
}
+SECStatus
+freebl_fips_TLS_PowerUpSelfTest(void)
+{
+ static const PRUint8 TLS_known_secret_key[] = {
+ "Firefox and ThunderBird are awesome!"
+ };
+
+ static const PRUint8 TLS_known_secret_key_length = sizeof TLS_known_secret_key;
+
+ /* known tls prf with sha1/md5 */
+ static const PRUint8 known_TLS_PRF[] = {
+ 0x87, 0x4c, 0xc0, 0xc5, 0x15, 0x14, 0x2b, 0xdc,
+ 0x73, 0x48, 0x9e, 0x88, 0x9d, 0xf5, 0x83, 0x2f,
+ 0x2d, 0x66, 0x1e, 0x78, 0x6c, 0x54, 0x78, 0x29,
+ 0xb9, 0xa4, 0x4c, 0x90, 0x5e, 0xa2, 0xe6, 0x5c,
+ 0xf1, 0x4f, 0xb5, 0x95, 0xa5, 0x54, 0xc0, 0x9f,
+ 0x84, 0x47, 0xb4, 0x4c, 0xda, 0xae, 0x19, 0x29,
+ 0x2b, 0x91, 0x2a, 0x81, 0x9d, 0x3a, 0x30, 0x40,
+ 0xc5, 0xdf, 0xbb, 0xfa, 0xd8, 0x4c, 0xbc, 0x18
+ };
+
+ /* known SHA256 tls mac */
+ static const PRUint8 known_TLS_SHA256[] = {
+ 0x66, 0xd6, 0x94, 0xd4, 0x0d, 0x32, 0x61, 0x38,
+ 0x26, 0xf6, 0x8b, 0xfe, 0x9e, 0xac, 0xa2, 0xf5,
+ 0x40, 0x52, 0x74, 0x3f, 0xbe, 0xb8, 0xca, 0x94,
+ 0xc3, 0x64, 0xd6, 0x02, 0xf5, 0x88, 0x98, 0x35,
+ 0x73, 0x9f, 0xce, 0xaa, 0x68, 0xe3, 0x7c, 0x93,
+ 0x30, 0x21, 0x45, 0xec, 0xe9, 0x8f, 0x1c, 0x7e,
+ 0xd1, 0x54, 0xf5, 0xbe, 0xff, 0xc8, 0xd7, 0x72,
+ 0x7f, 0x9c, 0x0c, 0x7f, 0xa9, 0xd3, 0x4a, 0xd2
+ };
+
+#ifdef NSS_FULL_POST
+ /* known SHA224 tls mac */
+ static const PRUint8 known_TLS_SHA224[] = {
+ 0xd8, 0x68, 0x15, 0xff, 0xa1, 0xa2, 0x5e, 0x16,
+ 0xce, 0xb1, 0xfd, 0xbd, 0xda, 0x39, 0xbc, 0xa7,
+ 0x27, 0x32, 0x78, 0x94, 0x66, 0xf0, 0x84, 0xcf,
+ 0x46, 0xc0, 0x22, 0x76, 0xdc, 0x6b, 0x2e, 0xed,
+ 0x1d, 0x2d, 0xd2, 0x93, 0xfd, 0xae, 0xca, 0xf9,
+ 0xe0, 0x4c, 0x17, 0x23, 0x22, 0x5a, 0x73, 0x93,
+ 0x20, 0x0a, 0xbd, 0xa0, 0x72, 0xf8, 0x8b, 0x74,
+ 0xfb, 0xf1, 0xab, 0xb7, 0xe0, 0xec, 0x34, 0xc9
+ };
+
+ /* known SHA384 tls mac */
+ static const PRUint8 known_TLS_SHA384[] = {
+ 0xb2, 0xac, 0x06, 0x10, 0xad, 0x50, 0xd5, 0xdc,
+ 0xdb, 0x01, 0xea, 0xa6, 0x2d, 0x8a, 0x34, 0xb6,
+ 0xeb, 0x84, 0xbc, 0x37, 0xc9, 0x9f, 0xa1, 0x9c,
+ 0xd5, 0xbd, 0x4e, 0x66, 0x16, 0x24, 0xe5, 0x3d,
+ 0xce, 0x74, 0xe0, 0x30, 0x41, 0x5c, 0xdb, 0xb7,
+ 0x52, 0x1d, 0x2d, 0x4d, 0x9b, 0xbe, 0x6b, 0x86,
+ 0xda, 0x8a, 0xca, 0x73, 0x39, 0xb4, 0xc7, 0x8f,
+ 0x03, 0xb1, 0xf9, 0x7e, 0x65, 0xae, 0x17, 0x10
+ };
+
+ /* known SHA512 tls mac */
+ static const PRUint8 known_TLS_SHA512[] = {
+ 0x73, 0x21, 0x4f, 0x40, 0x81, 0x1e, 0x90, 0xa1,
+ 0x16, 0x40, 0x1e, 0x33, 0x69, 0xc5, 0x00, 0xc7,
+ 0xc4, 0x81, 0xa3, 0x4f, 0xa7, 0xcc, 0x4a, 0xeb,
+ 0x1a, 0x66, 0x00, 0x82, 0x52, 0xe2, 0x2f, 0x69,
+ 0x14, 0x59, 0x05, 0x7c, 0xb0, 0x32, 0xce, 0xcc,
+ 0xb7, 0xc9, 0xab, 0x0f, 0x73, 0x00, 0xe5, 0x52,
+ 0x9d, 0x6b, 0x0e, 0x66, 0x4b, 0xb3, 0x0b, 0x0d,
+ 0x34, 0x53, 0x97, 0x13, 0x84, 0x18, 0x31, 0x7a
+ };
+#endif
+
+ SECStatus status;
+ PRUint8 tls_computed[HASH_LENGTH_MAX];
+ SECItem secret;
+ SECItem seed;
+ SECItem result;
+ const char *tls_label = "fips test label";
+
+ secret.data = (unsigned char *)TLS_known_secret_key;
+ secret.len = TLS_known_secret_key_length;
+ seed.data = (unsigned char *)known_hash_message;
+ seed.len = FIPS_KNOWN_HASH_MESSAGE_LENGTH;
+ result.data = tls_computed;
+ result.len = sizeof(tls_computed);
+
+ /***************************************************/
+ /* TLS 1.0 PRF Known Answer Test */
+ /***************************************************/
+
+ status = TLS_PRF(&secret, tls_label, &seed, &result, PR_TRUE);
+
+ if ((status != SECSuccess) ||
+ (result.len != HASH_LENGTH_MAX) ||
+ (PORT_Memcmp(tls_computed, known_TLS_PRF,
+ HASH_LENGTH_MAX) != 0)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return (SECFailure);
+ }
+
+ /***************************************************/
+ /* TLS 1.2 SHA-256 Known Answer Test. */
+ /***************************************************/
+
+ status = TLS_P_hash(HASH_AlgSHA256, &secret, tls_label,
+ &seed, &result, PR_TRUE);
+
+ if ((status != SECSuccess) ||
+ (result.len != HASH_LENGTH_MAX) ||
+ (PORT_Memcmp(tls_computed, known_TLS_SHA256,
+ HASH_LENGTH_MAX) != 0)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return (SECFailure);
+ }
+
+#ifdef NSS_FULL_POST
+ /***************************************************/
+ /* TLS 1.2 SHA-224 Known Answer Test. */
+ /***************************************************/
+
+ status = TLS_P_hash(HASH_AlgSHA224, &secret, tls_label,
+ &seed, &result, PR_TRUE);
+
+ if ((status != SECSuccess) ||
+ (result.len != HASH_LENGTH_MAX) ||
+ (PORT_Memcmp(tls_computed, known_TLS_SHA224,
+ HASH_LENGTH_MAX) != 0)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return (SECFailure);
+ }
+
+ /***************************************************/
+ /* TLS 1.2 SHA-384 Known Answer Test. */
+ /***************************************************/
+
+ status = TLS_P_hash(HASH_AlgSHA384, &secret, tls_label,
+ &seed, &result, PR_TRUE);
+
+ if ((status != SECSuccess) ||
+ (result.len != HASH_LENGTH_MAX) ||
+ (PORT_Memcmp(tls_computed, known_TLS_SHA384,
+ HASH_LENGTH_MAX) != 0)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return (SECFailure);
+ }
+
+ /***************************************************/
+ /* TLS 1.2 SHA-512 Known Answer Test. */
+ /***************************************************/
+
+ status = TLS_P_hash(HASH_AlgSHA512, &secret, tls_label,
+ &seed, &result, PR_TRUE);
+
+ if ((status != SECSuccess) ||
+ (result.len != HASH_LENGTH_MAX) ||
+ (PORT_Memcmp(tls_computed, known_TLS_SHA512,
+ HASH_LENGTH_MAX) != 0)) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return (SECFailure);
+ }
+#endif
+
+ return (SECSuccess);
+}
+
static SECStatus
freebl_fips_SHA_PowerUpSelfTest(void)
{
/* SHA-1 Known Digest Message (160-bits). */
static const PRUint8 sha1_known_digest[] = {
0x0a, 0x6d, 0x07, 0xba, 0x1e, 0xbd, 0x8a, 0x1b,
0x72, 0xf6, 0xc7, 0x22, 0xf1, 0x27, 0x9f, 0xf0,
0xe0, 0x68, 0x47, 0x7a
@@ -1837,16 +2061,22 @@ freebl_fipsPowerUpSelfTest(unsigned int
return rv;
/* HMAC SHA-X Power-Up SelfTest(s). */
rv = freebl_fips_HMAC_PowerUpSelfTest();
if (rv != SECSuccess)
return rv;
+ /* TLS PRF Power-Up SelfTest(s). */
+ rv = freebl_fips_TLS_PowerUpSelfTest();
+
+ if (rv != SECSuccess)
+ return rv;
+
/* NOTE: RSA can only be tested in full freebl. It requires access to
* the locking primitives */
/* RSA Power-Up SelfTest(s). */
rv = freebl_fips_RSA_PowerUpSelfTest();
if (rv != SECSuccess)
return rv;
--- a/lib/softoken/fipstest.c
+++ b/lib/softoken/fipstest.c
@@ -8,16 +8,17 @@
#ifndef NSS_FIPS_DISABLED
#include "seccomon.h"
#include "blapi.h"
#include "softoken.h"
#include "lowkeyi.h"
#include "secoid.h"
#include "secerr.h"
#include "pkcs11i.h"
+#include "lowpbe.h"
/*
* different platforms have different ways of calling and initial entry point
* when the dll/.so is loaded. Most platforms support either a posix pragma
* or the GCC attribute. Some platforms suppor a pre-defined name, and some
* platforms have a link line way of invoking this function.
*/
@@ -576,16 +577,116 @@ rsa_loser:
nsslowkey_DestroyPublicKey(rsa_public_key);
nsslowkey_DestroyPrivateKey(rsa_private_key);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return (SECFailure);
}
+static SECStatus
+sftk_fips_HKDF_PowerUpSelfTest(void)
+{
+ SECStatus status;
+ static const unsigned char base_key[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f
+ };
+ static const unsigned char known_hkdf_sha256_key[] = {
+ 0xdd, 0xdb, 0xeb, 0xe5, 0x6d, 0xd2, 0x96, 0xa4,
+ 0x07, 0xc5, 0x7d, 0xda, 0x31, 0x56, 0x8d, 0xa5,
+ 0x41, 0x3e, 0x90, 0xd4, 0xe6, 0x98, 0xeb, 0xf8,
+ 0x5a, 0x49, 0x7f, 0x38, 0xef, 0x01, 0x8a, 0xe5,
+ 0xda, 0x36, 0xe5, 0xcf, 0x21, 0xe3, 0x9f, 0xc3,
+ 0x32, 0xb3, 0x1e, 0xf6, 0xc5, 0x10, 0x4c, 0x86,
+ 0x53, 0x5e, 0x6f, 0xe0, 0x63, 0x6e, 0x43, 0x33,
+ 0x61, 0x35, 0xf4, 0x17, 0x10, 0x77, 0x75, 0x2a
+ };
+/* current NIST IG's say we only need to test one instance
+ * of kdfs, keep these others around in case the guidance
+ * changes */
+#ifdef NSS_FULL_POST
+ static const unsigned char known_hkdf_sha384_key[] = {
+ 0x35, 0x64, 0xc4, 0xa1, 0xcc, 0xc1, 0xdc, 0xe4,
+ 0xe2, 0xca, 0x51, 0xae, 0xe8, 0x92, 0x88, 0x30,
+ 0x8b, 0xb0, 0x2b, 0xac, 0x00, 0x15, 0xac, 0x15,
+ 0x97, 0xc9, 0xf4, 0x6b, 0xf6, 0x3f, 0x97, 0xea,
+ 0x48, 0x55, 0x38, 0x25, 0x06, 0x5d, 0x91, 0x64,
+ 0xbd, 0x09, 0xf3, 0x44, 0xbc, 0x82, 0xbe, 0xdb,
+ 0x5c, 0xd7, 0xf2, 0x24, 0xa5, 0x55, 0x8d, 0xa9,
+ 0xa8, 0x85, 0xde, 0x8c, 0x33, 0xe0, 0x4d, 0xc3
+ };
+ static const unsigned char known_hkdf_sha512_key[] = {
+ 0x63, 0x4e, 0xbc, 0x42, 0xb3, 0x56, 0x74, 0x7d,
+ 0x1b, 0x55, 0xf0, 0x34, 0x54, 0xcb, 0x6d, 0x58,
+ 0x39, 0x96, 0x10, 0xda, 0x03, 0x20, 0x8f, 0x77,
+ 0x0d, 0xb4, 0xf7, 0xf6, 0x67, 0x0d, 0x5b, 0x6b,
+ 0xd0, 0x30, 0xc4, 0xdd, 0x67, 0x61, 0x5d, 0x9a,
+ 0xf5, 0x18, 0x6e, 0x1b, 0x60, 0x97, 0xc2, 0x4d,
+ 0x23, 0x43, 0x69, 0xe6, 0x3b, 0xa5, 0xdf, 0xe9,
+ 0x7c, 0xf1, 0x87, 0x48, 0x6f, 0xb9, 0xd3, 0x02
+ };
+#endif
+ unsigned char outBytes[64] = { 0 };
+
+ CK_HKDF_PARAMS hkdf_params;
+
+ hkdf_params.bExpand = CK_TRUE;
+ hkdf_params.bExtract = CK_TRUE;
+ hkdf_params.ulSaltType = CKF_HKDF_SALT_DATA;
+ hkdf_params.pSalt = (CK_BYTE_PTR)base_key;
+ hkdf_params.ulSaltLen = sizeof(base_key);
+ hkdf_params.pInfo = (CK_BYTE_PTR)base_key;
+ hkdf_params.ulInfoLen = sizeof(base_key);
+
+ /**************************************************/
+ /* HKDF tests */
+ /**************************************************/
+
+ hkdf_params.prfHashMechanism = CKM_SHA256_HMAC;
+ status = sftk_HKDF(&hkdf_params, CK_INVALID_HANDLE, NULL,
+ base_key, 32, NULL, outBytes, sizeof(outBytes),
+ PR_TRUE, PR_TRUE);
+ if ((status != SECSuccess) ||
+ PORT_Memcmp(outBytes, known_hkdf_sha256_key, sizeof(outBytes)) != 0) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return (SECFailure);
+ }
+
+#ifdef NSS_FULL_POST
+ hkdf_params.prfHashMechanism = CKM_SHA384_HMAC;
+ status = sftk_HKDF(&hkdf_params, CK_INVALID_HANDLE, NULL,
+ base_key, 48, NULL, outBytes, sizeof(outBytes),
+ PR_TRUE, PR_TRUE);
+ if ((status != SECSuccess) ||
+ PORT_Memcmp(outBytes, known_hkdf_sha384_key, sizeof(outBytes)) != 0) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return (SECFailure);
+ }
+
+ hkdf_params.prfHashMechanism = CKM_SHA512_HMAC;
+ status = sftk_HKDF(&hkdf_params, CK_INVALID_HANDLE, NULL,
+ base_key, 64, NULL, outBytes, sizeof(outBytes),
+ PR_TRUE, PR_TRUE);
+ if ((status != SECSuccess) ||
+ PORT_Memcmp(outBytes, known_hkdf_sha512_key, sizeof(outBytes)) != 0) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return (SECFailure);
+ }
+#endif
+
+ return (SECSuccess);
+}
+
static PRBool sftk_self_tests_ran = PR_FALSE;
static PRBool sftk_self_tests_success = PR_FALSE;
/*
* This function is called at dll load time, the code tha makes this
* happen is platform specific on defined above.
*/
static void
@@ -626,16 +727,32 @@ sftk_startup_tests(void)
/* something is wrong with the library, fail without enabling
* the token */
return;
}
rv = sftk_fips_IKE_PowerUpSelfTests();
if (rv != SECSuccess) {
return;
}
+
+ rv = sftk_fips_SP800_108_PowerUpSelfTests();
+ if (rv != SECSuccess) {
+ return;
+ }
+
+ rv = sftk_fips_HKDF_PowerUpSelfTest();
+ if (rv != SECSuccess) {
+ return;
+ }
+
+ rv = sftk_fips_pbkdf_PowerUpSelfTests();
+ if (rv != SECSuccess) {
+ return;
+ }
+
sftk_self_tests_success = PR_TRUE;
}
/*
* this is called from nsc_Common_Initizialize entry points that gates access
* to * all other pkcs11 functions. This prevents softoken operation if our
* power on selftest failed.
*/
--- a/lib/softoken/kbkdf.c
+++ b/lib/softoken/kbkdf.c
@@ -85,17 +85,17 @@ kbkdf_LoadParameters(CK_MECHANISM_TYPE m
(*kdf_params) = *in_params;
}
return CKR_OK;
}
static CK_RV
-kbkdf_ValidateParameter(CK_MECHANISM_TYPE mech, CK_PRF_DATA_PARAM_PTR data)
+kbkdf_ValidateParameter(CK_MECHANISM_TYPE mech, const CK_PRF_DATA_PARAM *data)
{
/* This function validates that the passed data parameter (data) conforms
* to PKCS#11 v3.0's expectations for KDF parameters. This depends both on
* the type of this parameter (data->type) and on the KDF mechanism (mech)
* as certain parameters are context dependent (like Iteration Variable).
*/
/* If the parameter is missing a value when one is expected, then this
@@ -260,17 +260,17 @@ failure:
* key's template (ie the template defined by the content of pTemplate),
* the corresponding phKey value will be set to CK_INVALID_HANDLE to
* identify the offending template. */
*(key->phKey) = CK_INVALID_HANDLE;
return CKR_MECHANISM_PARAM_INVALID;
}
static CK_RV
-kbkdf_ValidateParameters(CK_MECHANISM_TYPE mech, CK_SP800_108_KDF_PARAMS_PTR params, CK_ULONG keySize)
+kbkdf_ValidateParameters(CK_MECHANISM_TYPE mech, const CK_SP800_108_KDF_PARAMS *params, CK_ULONG keySize)
{
CK_RV ret = CKR_MECHANISM_PARAM_INVALID;
int param_type_count[5] = { 0, 0, 0, 0, 0 };
size_t offset = 0;
/* Start with checking the prfType as a mechanism against a list of
* PRFs allowed by PKCS#11 v3.0. */
if (!(/* The following types aren't defined in NSS yet. */
@@ -339,17 +339,17 @@ kbkdf_ValidateParameters(CK_MECHANISM_TY
}
return CKR_OK;
}
/* [ section: parameter helpers ] */
static CK_VOID_PTR
-kbkdf_FindParameter(CK_SP800_108_KDF_PARAMS_PTR params, CK_PRF_DATA_TYPE type)
+kbkdf_FindParameter(const CK_SP800_108_KDF_PARAMS *params, CK_PRF_DATA_TYPE type)
{
for (size_t offset = 0; offset < params->ulNumberOfDataParams; offset++) {
if (params->pDataParams[offset].type == type) {
return params->pDataParams[offset].pValue;
}
}
return NULL;
@@ -387,17 +387,17 @@ kbkdf_GetDerivedKeySize(CK_DERIVED_KEY_P
}
/* Else, fall back to this mapping. We know kbkdf_ValidateDerived(...)
* passed, so this should return non-zero. */
return sftk_MapKeySize(keyType);
}
static CK_RV
-kbkdf_CalculateLength(CK_SP800_108_KDF_PARAMS_PTR params, sftk_MACCtx *ctx, CK_ULONG ret_key_size, PRUint64 *output_bitlen, size_t *buffer_length)
+kbkdf_CalculateLength(const CK_SP800_108_KDF_PARAMS *params, sftk_MACCtx *ctx, CK_ULONG ret_key_size, PRUint64 *output_bitlen, size_t *buffer_length)
{
/* Two cases: either we have additional derived keys or we don't. In the
* case that we don't, the length of the derivation is the size of the
* single derived key, and that is the length of the PRF buffer. Otherwise,
* we need to use the proper CK_SP800_108_DKM_LENGTH_METHOD to calculate
* the length of the output (in bits), with a separate value for the size
* of the PRF data buffer. This means that, under PKCS#11 with additional
* derived keys, we lie to the KDF about the _actual_ length of the PRF
@@ -460,17 +460,17 @@ kbkdf_CalculateLength(CK_SP800_108_KDF_P
* the size in bytes. However, output_bitlen needs to be in bits, so
* multiply by 8 here. */
*output_bitlen *= 8;
return CKR_OK;
}
static CK_RV
-kbkdf_CalculateIterations(CK_MECHANISM_TYPE mech, CK_SP800_108_KDF_PARAMS_PTR params, sftk_MACCtx *ctx, size_t buffer_length, PRUint32 *num_iterations)
+kbkdf_CalculateIterations(CK_MECHANISM_TYPE mech, const CK_SP800_108_KDF_PARAMS *params, sftk_MACCtx *ctx, size_t buffer_length, PRUint32 *num_iterations)
{
CK_SP800_108_COUNTER_FORMAT_PTR param_ptr = NULL;
PRUint64 iteration_count;
PRUint64 r = 32;
/* We need to know how many full iterations are required. This is done
* by rounding up the division of the PRF length into buffer_length.
* However, we're not guaranteed that the last output is a full PRF
@@ -514,17 +514,17 @@ kbkdf_CalculateIterations(CK_MECHANISM_T
}
*num_iterations = (PRUint32)iteration_count;
return CKR_OK;
}
static CK_RV
-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)
+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)
{
size_t offset = 0;
CK_RV ret = CKR_OK;
for (offset = 0; offset < params->ulNumberOfDataParams; offset++) {
CK_PRF_DATA_PARAM_PTR param = params->pDataParams + offset;
if (param->type == exclude) {
@@ -744,17 +744,17 @@ kbkdf_SaveKeys(CK_MECHANISM_TYPE mech, C
}
return CKR_OK;
}
/* [ section: KDFs ] */
static CK_RV
-kbkdf_CounterRaw(CK_SP800_108_KDF_PARAMS_PTR params, sftk_MACCtx *ctx, unsigned char *ret_buffer, size_t buffer_length, PRUint64 output_bitlen)
+kbkdf_CounterRaw(const CK_SP800_108_KDF_PARAMS *params, sftk_MACCtx *ctx, unsigned char *ret_buffer, size_t buffer_length, PRUint64 output_bitlen)
{
CK_RV ret = CKR_OK;
/* Counter variable for this KDF instance. */
PRUint32 counter;
/* Number of iterations required of this PRF necessary to reach the
* desired output length. */
@@ -832,17 +832,17 @@ kbkdf_CounterRaw(CK_SP800_108_KDF_PARAMS
}
}
}
return CKR_OK;
}
static CK_RV
-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)
+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)
{
CK_RV ret = CKR_OK;
/* Counter variable for this KDF instance. */
PRUint32 counter;
/* Number of iterations required of this PRF necessary to reach the
* desired output length. */
@@ -854,17 +854,17 @@ kbkdf_FeedbackRaw(CK_SP800_108_KDF_PARAM
/* Size of this block, in bytes. Defaults to ctx->mac_size except on
* the last iteration where it could be a partial block. */
size_t block_size = ctx->mac_size;
/* The last PRF invocation and/or the initial value; used for feedback
* chaining in this KDF. Note that we have to make it large enough to
* fit the output of the PRF, but we can delay its actual creation until
* the first PRF invocation. Until then, point to the IV value. */
- unsigned char *chaining_value = initial_value;
+ unsigned char *chaining_value = (unsigned char *)initial_value;
/* Size of the chaining value discussed above. Defaults to the size of
* the IV value. */
size_t chaining_length = initial_value_length;
/* Calculate the number of iterations required based on the size of the
* output buffer. */
ret = kbkdf_CalculateIterations(CKM_SP800_108_FEEDBACK_KDF, params, ctx, buffer_length, &num_iterations);
@@ -957,17 +957,17 @@ finish:
if (chaining_value != initial_value && chaining_value != NULL) {
PORT_ZFree(chaining_value, chaining_length);
}
return ret;
}
static CK_RV
-kbkdf_PipelineRaw(CK_SP800_108_KDF_PARAMS_PTR params, sftk_MACCtx *ctx, unsigned char *ret_buffer, size_t buffer_length, PRUint64 output_bitlen)
+kbkdf_PipelineRaw(const CK_SP800_108_KDF_PARAMS *params, sftk_MACCtx *ctx, unsigned char *ret_buffer, size_t buffer_length, PRUint64 output_bitlen)
{
CK_RV ret = CKR_OK;
/* Counter variable for this KDF instance. */
PRUint32 counter;
/* Number of iterations required of this PRF necessary to reach the
* desired output length. */
@@ -1104,41 +1104,27 @@ kbkdf_PipelineRaw(CK_SP800_108_KDF_PARAM
}
finish:
PORT_ZFree(chaining_value, chaining_length);
return ret;
}
-/* [ section: PKCS#11 entry ] */
-
-CK_RV
-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)
+static CK_RV
+kbkdf_RawDispatch(CK_MECHANISM_TYPE mech,
+ const CK_SP800_108_KDF_PARAMS *kdf_params,
+ const CK_BYTE *initial_value,
+ CK_ULONG initial_value_length,
+ SFTKObject *prf_key, const unsigned char *prf_key_bytes,
+ unsigned int prf_key_length, unsigned char **out_key_bytes,
+ size_t *out_key_length, unsigned int *mac_size,
+ CK_ULONG ret_key_size)
{
- /* This handles boilerplate common to all KBKDF types. Instead of placing
- * this in pkcs11c.c, place it here to reduce clutter. */
-
CK_RV ret;
-
- /* Assumptions about our calling environment. */
- PR_ASSERT(pMechanism != NULL && prf_key != NULL && ret_key != NULL);
-
- /* Validate that the caller passed parameters. */
- if (pMechanism->pParameter == NULL) {
- return CKR_MECHANISM_PARAM_INVALID;
- }
-
- /* Create a common set of parameters to use for all KDF types. This
- * separates out the KDF parameters from the Feedback-specific IV,
- * allowing us to use a common type for all calls. */
- CK_SP800_108_KDF_PARAMS kdf_params = { 0 };
- CK_BYTE_PTR initial_value = NULL;
- CK_ULONG initial_value_length = 0;
-
/* Context for our underlying PRF function.
*
* Zeroing context required unconditional call of sftk_MAC_Destroy.
*/
sftk_MACCtx ctx = { 0 };
/* We need one buffers large enough to fit the entire KDF key stream for
* all iterations of the PRF. This needs only include to the end of the
@@ -1163,80 +1149,370 @@ kbkdf_Dispatch(CK_MECHANISM_TYPE mech, C
* and size of keys (again, 2^32); this could easily exceed 256GB when
* counting the backing softoken key, the key data, template data, and
* the input parameters to this KDF.
*
* This is the L parameter in NIST SP800-108.
*/
PRUint64 output_bitlen = 0;
- /* Split Feedback-specific IV from remaining KDF parameters. */
- ret = kbkdf_LoadParameters(mech, pMechanism, &kdf_params, &initial_value, &initial_value_length);
- if (ret != CKR_OK) {
- goto finish;
- }
-
/* First validate our passed input parameters against PKCS#11 v3.0
* and NIST SP800-108 requirements. */
- ret = kbkdf_ValidateParameters(mech, &kdf_params, ret_key_size);
+ ret = kbkdf_ValidateParameters(mech, kdf_params, ret_key_size);
if (ret != CKR_OK) {
goto finish;
}
/* Initialize the underlying PRF state. */
- ret = sftk_MAC_Init(&ctx, kdf_params.prfType, prf_key);
+ if (prf_key) {
+ ret = sftk_MAC_Init(&ctx, kdf_params->prfType, prf_key);
+ } else {
+ ret = sftk_MAC_InitRaw(&ctx, kdf_params->prfType, prf_key_bytes,
+ prf_key_length, PR_TRUE);
+ }
if (ret != CKR_OK) {
goto finish;
}
/* Compute the size of our output buffer based on passed parameters and
* the output size of the underlying PRF. */
- ret = kbkdf_CalculateLength(&kdf_params, &ctx, ret_key_size, &output_bitlen, &buffer_length);
+ ret = kbkdf_CalculateLength(kdf_params, &ctx, ret_key_size, &output_bitlen, &buffer_length);
if (ret != CKR_OK) {
goto finish;
}
/* Allocate memory for the PRF output */
output_buffer = PORT_ZNewArray(unsigned char, buffer_length);
if (output_buffer == NULL) {
ret = CKR_HOST_MEMORY;
goto finish;
}
/* Call into the underlying KDF */
switch (mech) {
case CKM_NSS_SP800_108_COUNTER_KDF_DERIVE_DATA: /* fall through */
case CKM_SP800_108_COUNTER_KDF:
- ret = kbkdf_CounterRaw(&kdf_params, &ctx, output_buffer, buffer_length, output_bitlen);
+ ret = kbkdf_CounterRaw(kdf_params, &ctx, output_buffer, buffer_length, output_bitlen);
break;
case CKM_NSS_SP800_108_FEEDBACK_KDF_DERIVE_DATA: /* fall through */
case CKM_SP800_108_FEEDBACK_KDF:
- ret = kbkdf_FeedbackRaw(&kdf_params, initial_value, initial_value_length, &ctx, output_buffer, buffer_length, output_bitlen);
+ ret = kbkdf_FeedbackRaw(kdf_params, initial_value, initial_value_length, &ctx, output_buffer, buffer_length, output_bitlen);
break;
case CKM_NSS_SP800_108_DOUBLE_PIPELINE_KDF_DERIVE_DATA: /* fall through */
case CKM_SP800_108_DOUBLE_PIPELINE_KDF:
- ret = kbkdf_PipelineRaw(&kdf_params, &ctx, output_buffer, buffer_length, output_bitlen);
+ ret = kbkdf_PipelineRaw(kdf_params, &ctx, output_buffer, buffer_length, output_bitlen);
break;
default:
/* Shouldn't happen unless NIST introduces a new KBKDF type. */
PR_ASSERT(PR_FALSE);
ret = CKR_FUNCTION_FAILED;
}
/* Validate the above KDF succeeded. */
if (ret != CKR_OK) {
goto finish;
}
+ *out_key_bytes = output_buffer;
+ *out_key_length = buffer_length;
+ *mac_size = ctx.mac_size;
+
+ output_buffer = NULL; /* returning the buffer, don't zero and free it */
+
+finish:
+ PORT_ZFree(output_buffer, buffer_length);
+
+ /* Free the PRF. This should handle clearing all sensitive information. */
+ sftk_MAC_Destroy(&ctx, PR_FALSE);
+ return ret;
+}
+
+/* [ section: PKCS#11 entry ] */
+
+CK_RV
+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)
+{
+ /* This handles boilerplate common to all KBKDF types. Instead of placing
+ * this in pkcs11c.c, place it here to reduce clutter. */
+
+ CK_RV ret;
+
+ /* Assumptions about our calling environment. */
+ PR_ASSERT(pMechanism != NULL && prf_key != NULL && ret_key != NULL);
+
+ /* Validate that the caller passed parameters. */
+ if (pMechanism->pParameter == NULL) {
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
+
+ /* Create a common set of parameters to use for all KDF types. This
+ * separates out the KDF parameters from the Feedback-specific IV,
+ * allowing us to use a common type for all calls. */
+ CK_SP800_108_KDF_PARAMS kdf_params = { 0 };
+ CK_BYTE_PTR initial_value = NULL;
+ CK_ULONG initial_value_length = 0;
+ unsigned char *output_buffer = NULL;
+ size_t buffer_length = 0;
+ unsigned int mac_size = 0;
+
+ /* Split Feedback-specific IV from remaining KDF parameters. */
+ ret = kbkdf_LoadParameters(mech, pMechanism, &kdf_params, &initial_value, &initial_value_length);
+ if (ret != CKR_OK) {
+ goto finish;
+ }
+ /* let rawDispatch handle the rest. We split this out so we could
+ * handle the POST test without accessing pkcs #11 objects. */
+ ret = kbkdf_RawDispatch(mech, &kdf_params, initial_value,
+ initial_value_length, prf_key, NULL, 0,
+ &output_buffer, &buffer_length, &mac_size,
+ ret_key_size);
+ if (ret != CKR_OK) {
+ goto finish;
+ }
+
/* Write the output of the PRF into the appropriate keys. */
- ret = kbkdf_SaveKeys(mech, hSession, &kdf_params, output_buffer, buffer_length, ctx.mac_size, ret_key, ret_key_size);
+ ret = kbkdf_SaveKeys(mech, hSession, &kdf_params, output_buffer, buffer_length, mac_size, ret_key, ret_key_size);
if (ret != CKR_OK) {
goto finish;
}
finish:
PORT_ZFree(output_buffer, buffer_length);
- /* Free the PRF. This should handle clearing all sensitive information. */
- sftk_MAC_Destroy(&ctx, PR_FALSE);
-
return ret;
}
+
+struct sftk_SP800_Test_struct {
+ CK_MECHANISM_TYPE mech;
+ CK_SP800_108_KDF_PARAMS kdf_params;
+ unsigned int expected_mac_size;
+ unsigned int ret_key_length;
+ const unsigned char expected_key_bytes[64];
+};
+
+static const CK_SP800_108_COUNTER_FORMAT counter_32 = { 0, 32 };
+static const CK_PRF_DATA_PARAM counter_32_data =
+ { CK_SP800_108_ITERATION_VARIABLE, (CK_VOID_PTR)&counter_32, sizeof(counter_32) };
+
+#ifdef NSS_FULL_POST
+static const CK_SP800_108_COUNTER_FORMAT counter_16 = { 0, 16 };
+static const CK_PRF_DATA_PARAM counter_16_data =
+ { CK_SP800_108_ITERATION_VARIABLE, (CK_VOID_PTR)&counter_16, sizeof(counter_16) };
+static const CK_PRF_DATA_PARAM counter_null_data =
+ { CK_SP800_108_ITERATION_VARIABLE, NULL, 0 };
+#endif
+
+static const struct sftk_SP800_Test_struct sftk_SP800_Tests[] =
+ {
+#ifdef NSS_FULL_POST
+ {
+ CKM_SP800_108_COUNTER_KDF,
+ { CKM_AES_CMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_16_data, 0, NULL },
+ 16,
+ 64,
+ { 0x7b, 0x1c, 0xe7, 0xf3, 0x14, 0x67, 0x15, 0xdd,
+ 0xde, 0x0c, 0x09, 0x46, 0x3f, 0x47, 0x7b, 0xa6,
+ 0xb8, 0xba, 0x40, 0x07, 0x7c, 0xe3, 0x19, 0x53,
+ 0x26, 0xac, 0x4c, 0x2e, 0x2b, 0x37, 0x41, 0xe4,
+ 0x1b, 0x01, 0x3f, 0x2f, 0x2d, 0x16, 0x95, 0xee,
+ 0xeb, 0x7e, 0x72, 0x7d, 0xa4, 0xab, 0x2e, 0x67,
+ 0x1d, 0xef, 0x6f, 0xa2, 0xc6, 0xee, 0x3c, 0xcf,
+ 0xef, 0x88, 0xfd, 0x5c, 0x1d, 0x7b, 0xa0, 0x5a },
+ },
+ {
+ CKM_SP800_108_COUNTER_KDF,
+ { CKM_SHA384_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_32_data, 0, NULL },
+ 48,
+ 64,
+ { 0xe6, 0x62, 0xa4, 0x32, 0x5c, 0xe4, 0xc2, 0x28,
+ 0x73, 0x8a, 0x5d, 0x94, 0xe7, 0x05, 0xe0, 0x5a,
+ 0x71, 0x61, 0xb2, 0x3c, 0x51, 0x28, 0x03, 0x1d,
+ 0xa7, 0xf5, 0x10, 0x83, 0x34, 0xdb, 0x11, 0x73,
+ 0x92, 0xa6, 0x79, 0x74, 0x81, 0x5d, 0x22, 0x7e,
+ 0x8d, 0xf2, 0x59, 0x14, 0x56, 0x60, 0xcf, 0xb2,
+ 0xb3, 0xfd, 0x46, 0xfd, 0x9b, 0x74, 0xfe, 0x4a,
+ 0x09, 0x30, 0x4a, 0xdf, 0x07, 0x43, 0xfe, 0x85 },
+ },
+ {
+ CKM_SP800_108_COUNTER_KDF,
+ { CKM_SHA512_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_32_data, 0, NULL },
+ 64,
+ 64,
+ { 0xb0, 0x78, 0x36, 0xe1, 0x15, 0xd6, 0xf0, 0xac,
+ 0x68, 0x7b, 0x42, 0xd3, 0xb6, 0x82, 0x51, 0xad,
+ 0x95, 0x0a, 0x69, 0x88, 0x84, 0xc2, 0x2e, 0x07,
+ 0x34, 0x62, 0x8d, 0x42, 0x72, 0x0f, 0x22, 0xe6,
+ 0xd5, 0x7f, 0x80, 0x15, 0xe6, 0x84, 0x00, 0x65,
+ 0xef, 0x64, 0x77, 0x29, 0xd6, 0x3b, 0xc7, 0x9a,
+ 0x15, 0x6d, 0x36, 0xf3, 0x96, 0xc9, 0x14, 0x3f,
+ 0x2d, 0x4a, 0x7c, 0xdb, 0xc3, 0x6c, 0x3d, 0x6a },
+ },
+ {
+ CKM_SP800_108_FEEDBACK_KDF,
+ { CKM_AES_CMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL },
+ 16,
+ 64,
+ { 0xc0, 0xa0, 0x23, 0x96, 0x16, 0x4d, 0xd6, 0xbd,
+ 0x2a, 0x75, 0x8e, 0x72, 0xf5, 0xc3, 0xa0, 0xb8,
+ 0x78, 0x83, 0x15, 0x21, 0x34, 0xd3, 0xd8, 0x71,
+ 0xc9, 0xe7, 0x4b, 0x20, 0xb7, 0x65, 0x5b, 0x13,
+ 0xbc, 0x85, 0x54, 0xe3, 0xb6, 0xee, 0x73, 0xd5,
+ 0xf2, 0xa0, 0x94, 0x1a, 0x79, 0x66, 0x3b, 0x1e,
+ 0x67, 0x3e, 0x69, 0xa4, 0x12, 0x40, 0xa9, 0xda,
+ 0x8d, 0x14, 0xb1, 0xce, 0xf1, 0x4b, 0x79, 0x4e },
+ },
+ {
+ CKM_SP800_108_FEEDBACK_KDF,
+ { CKM_SHA256_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL },
+ 32,
+ 64,
+ { 0x99, 0x9b, 0x08, 0x79, 0x14, 0x2e, 0x58, 0x34,
+ 0xd7, 0x92, 0xa7, 0x7e, 0x7f, 0xc2, 0xf0, 0x34,
+ 0xa3, 0x4e, 0x33, 0xf0, 0x63, 0x95, 0x2d, 0xad,
+ 0xbf, 0x3b, 0xcb, 0x6d, 0x4e, 0x07, 0xd9, 0xe9,
+ 0xbd, 0xbd, 0x77, 0x54, 0xe1, 0xa3, 0x36, 0x26,
+ 0xcd, 0xb1, 0xf9, 0x2d, 0x80, 0x68, 0xa2, 0x01,
+ 0x4e, 0xbf, 0x35, 0xec, 0x65, 0xae, 0xfd, 0x71,
+ 0xa6, 0xd7, 0x62, 0x26, 0x2c, 0x3f, 0x73, 0x63 },
+ },
+ {
+ CKM_SP800_108_FEEDBACK_KDF,
+ { CKM_SHA384_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL },
+ 48,
+ 64,
+ { 0xc8, 0x7a, 0xf8, 0xd9, 0x6b, 0x90, 0x82, 0x35,
+ 0xea, 0xf5, 0x2c, 0x8f, 0xce, 0xaa, 0x3b, 0xa5,
+ 0x68, 0xd3, 0x7f, 0xae, 0x31, 0x93, 0xe6, 0x69,
+ 0x0c, 0xd1, 0x74, 0x7f, 0x8f, 0xc2, 0xe2, 0x33,
+ 0x93, 0x45, 0x23, 0xba, 0xb3, 0x73, 0xc9, 0x2c,
+ 0xd6, 0xd2, 0x10, 0x16, 0xe9, 0x9f, 0x9e, 0xe8,
+ 0xc1, 0x0e, 0x29, 0x95, 0x3d, 0x16, 0x68, 0x24,
+ 0x40, 0x4d, 0x40, 0x21, 0x41, 0xa6, 0xc8, 0xdb },
+ },
+ {
+ CKM_SP800_108_FEEDBACK_KDF,
+ { CKM_SHA512_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL },
+ 64,
+ 64,
+ { 0x81, 0x39, 0x12, 0xc2, 0xf9, 0x31, 0x24, 0x7c,
+ 0x71, 0x12, 0x97, 0x08, 0x82, 0x76, 0x83, 0x55,
+ 0x8c, 0x82, 0xf3, 0x09, 0xd6, 0x1b, 0x7a, 0xa2,
+ 0x6e, 0x71, 0x6b, 0xad, 0x46, 0x57, 0x60, 0x89,
+ 0x38, 0xcf, 0x63, 0xfa, 0xf4, 0x38, 0x27, 0xef,
+ 0xf0, 0xaf, 0x75, 0x4e, 0xc2, 0xe0, 0x31, 0xdb,
+ 0x59, 0x7d, 0x19, 0xc9, 0x6d, 0xbb, 0xed, 0x95,
+ 0xaf, 0x3e, 0xd8, 0x33, 0x76, 0xab, 0xec, 0xfa },
+ },
+ {
+ CKM_SP800_108_DOUBLE_PIPELINE_KDF,
+ { CKM_AES_CMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL },
+ 16,
+ 64,
+ { 0x3e, 0xa8, 0xbf, 0x77, 0x84, 0x90, 0xb0, 0x3a,
+ 0x89, 0x16, 0x32, 0x01, 0x92, 0xd3, 0x1f, 0x1b,
+ 0xc1, 0x06, 0xc5, 0x32, 0x62, 0x03, 0x50, 0x16,
+ 0x3b, 0xb9, 0xa7, 0xdc, 0xb5, 0x68, 0x6a, 0xbb,
+ 0xbb, 0x7d, 0x63, 0x69, 0x24, 0x6e, 0x09, 0xd6,
+ 0x6f, 0x80, 0x57, 0x65, 0xc5, 0x62, 0x33, 0x96,
+ 0x69, 0xe6, 0xab, 0x65, 0x36, 0xd0, 0xe2, 0x5c,
+ 0xd7, 0xbd, 0xe4, 0x68, 0x13, 0xd6, 0xb1, 0x46 },
+ },
+ {
+ CKM_SP800_108_DOUBLE_PIPELINE_KDF,
+ { CKM_SHA256_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL },
+ 32,
+ 64,
+ { 0xeb, 0x28, 0xd9, 0x2c, 0x19, 0x33, 0xb9, 0x2a,
+ 0xf9, 0xac, 0x85, 0xbd, 0xf4, 0xdb, 0xfa, 0x88,
+ 0x73, 0xf4, 0x36, 0x08, 0xdb, 0xfe, 0x13, 0xd1,
+ 0x5a, 0xec, 0x7b, 0x68, 0x13, 0x53, 0xb3, 0xd1,
+ 0x31, 0xf2, 0x83, 0xae, 0x9f, 0x75, 0x47, 0xb6,
+ 0x6d, 0x3c, 0x20, 0x16, 0x47, 0x9c, 0x27, 0x66,
+ 0xec, 0xa9, 0xdf, 0x0c, 0xda, 0x2a, 0xf9, 0xf4,
+ 0x55, 0x74, 0xde, 0x9d, 0x3f, 0xe3, 0x5e, 0x14 },
+ },
+ {
+ CKM_SP800_108_DOUBLE_PIPELINE_KDF,
+ { CKM_SHA384_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL },
+ 48,
+ 64,
+ { 0xa5, 0xca, 0x32, 0x40, 0x00, 0x93, 0xb2, 0xcc,
+ 0x78, 0x3c, 0xa6, 0xc4, 0xaf, 0xa8, 0xb3, 0xd0,
+ 0xa4, 0x6b, 0xb5, 0x31, 0x35, 0x87, 0x33, 0xa2,
+ 0x6a, 0x6b, 0xe1, 0xff, 0xea, 0x1d, 0x6e, 0x9e,
+ 0x0b, 0xde, 0x8b, 0x92, 0x15, 0xd6, 0x56, 0x2f,
+ 0xb6, 0x1a, 0xd7, 0xd2, 0x01, 0x3e, 0x28, 0x2e,
+ 0xfa, 0x84, 0x3c, 0xc0, 0xe8, 0xbe, 0x94, 0xc0,
+ 0x06, 0xbd, 0xbf, 0x87, 0x1f, 0xb8, 0x64, 0xc2 },
+ },
+ {
+ CKM_SP800_108_DOUBLE_PIPELINE_KDF,
+ { CKM_SHA512_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_null_data, 0, NULL },
+ 64,
+ 64,
+ { 0x3f, 0xd9, 0x4e, 0x80, 0x58, 0x21, 0xc8, 0xea,
+ 0x22, 0x17, 0xcf, 0x7d, 0xce, 0xfd, 0xec, 0x03,
+ 0xb9, 0xe4, 0xa2, 0xf7, 0xc0, 0xf1, 0x68, 0x81,
+ 0x53, 0x71, 0xb7, 0x42, 0x14, 0x4e, 0x5b, 0x09,
+ 0x05, 0x31, 0xb9, 0x27, 0x18, 0x2d, 0x23, 0xf8,
+ 0x9c, 0x3d, 0x4e, 0xd0, 0xdd, 0xf3, 0x1e, 0x4b,
+ 0xf2, 0xf9, 0x1a, 0x5d, 0x00, 0x66, 0x22, 0x83,
+ 0xae, 0x3c, 0x53, 0xd2, 0x54, 0x4b, 0x06, 0x4c },
+ },
+#endif
+ {
+ CKM_SP800_108_COUNTER_KDF,
+ { CKM_SHA256_HMAC, 1, (CK_PRF_DATA_PARAM_PTR)&counter_32_data, 0, NULL },
+ 32,
+ 64,
+ { 0xfb, 0x2b, 0xb5, 0xde, 0xce, 0x5a, 0x2b, 0xdc,
+ 0x25, 0x8f, 0x54, 0x17, 0x4b, 0x5a, 0xa7, 0x90,
+ 0x64, 0x36, 0xeb, 0x43, 0x1f, 0x1d, 0xf9, 0x23,
+ 0xb2, 0x22, 0x29, 0xa0, 0xfa, 0x2e, 0x21, 0xb6,
+ 0xb7, 0xfb, 0x27, 0x0a, 0x1c, 0xa6, 0x58, 0x43,
+ 0xa1, 0x16, 0x44, 0x29, 0x4b, 0x1c, 0xb3, 0x72,
+ 0xd5, 0x98, 0x9d, 0x27, 0xd5, 0x75, 0x25, 0xbf,
+ 0x23, 0x61, 0x40, 0x48, 0xbb, 0x0b, 0x49, 0x8e },
+ }
+ };
+
+SECStatus
+sftk_fips_SP800_108_PowerUpSelfTests(void)
+{
+ int i;
+ CK_RV crv;
+
+ const unsigned char prf_key[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78
+ };
+ for (i = 0; i < PR_ARRAY_SIZE(sftk_SP800_Tests); i++) {
+ const struct sftk_SP800_Test_struct *test = &sftk_SP800_Tests[i];
+ unsigned char *output_buffer;
+ size_t buffer_length;
+ unsigned int mac_size;
+
+ crv = kbkdf_RawDispatch(test->mech, &test->kdf_params,
+ prf_key, test->expected_mac_size,
+ NULL, prf_key, test->expected_mac_size,
+ &output_buffer, &buffer_length, &mac_size,
+ test->ret_key_length);
+ if (crv != CKR_OK) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ if ((mac_size != test->expected_mac_size) ||
+ (buffer_length != test->ret_key_length) ||
+ (output_buffer == NULL) ||
+ (PORT_Memcmp(output_buffer, test->expected_key_bytes, buffer_length) != 0)) {
+ PORT_ZFree(output_buffer, buffer_length);
+ return SECFailure;
+ }
+ PORT_ZFree(output_buffer, buffer_length);
+ }
+ return SECSuccess;
+}
--- a/lib/softoken/lowpbe.c
+++ b/lib/softoken/lowpbe.c
@@ -1738,8 +1738,72 @@ nsspkcs5_CreateAlgorithmID(PLArenaPool *
SECOID_DestroyAlgorithmID(ret_algid, PR_TRUE);
ret_algid = NULL;
}
loser:
return ret_algid;
}
+
+#define TEST_KEY "pbkdf test key"
+SECStatus
+sftk_fips_pbkdf_PowerUpSelfTests(void)
+{
+ SECItem *result;
+ SECItem inKey;
+ NSSPKCS5PBEParameter pbe_params;
+ unsigned char iteration_count = 5;
+ unsigned char keyLen = 64;
+ char *inKeyData = TEST_KEY;
+ static const unsigned char saltData[] =
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
+ static const unsigned char pbkdf_known_answer[] = {
+ 0x31, 0xf0, 0xe5, 0x39, 0x9f, 0x39, 0xb9, 0x29,
+ 0x68, 0xac, 0xf2, 0xe9, 0x53, 0x9b, 0xb4, 0x9c,
+ 0x28, 0x59, 0x8b, 0x5c, 0xd8, 0xd4, 0x02, 0x37,
+ 0x18, 0x22, 0xc1, 0x92, 0xd0, 0xfa, 0x72, 0x90,
+ 0x2c, 0x8d, 0x19, 0xd4, 0x56, 0xfb, 0x16, 0xfa,
+ 0x8d, 0x5c, 0x06, 0x33, 0xd1, 0x5f, 0x17, 0xb1,
+ 0x22, 0xd9, 0x9c, 0xaf, 0x5e, 0x3f, 0xf3, 0x66,
+ 0xc6, 0x14, 0xfe, 0x83, 0xfa, 0x1a, 0x2a, 0xc5
+ };
+
+ sftk_PBELockInit();
+
+ inKey.data = (unsigned char *)inKeyData;
+ inKey.len = sizeof(TEST_KEY) - 1;
+
+ pbe_params.salt.data = (unsigned char *)saltData;
+ pbe_params.salt.len = sizeof(saltData);
+ /* the interation and keyLength are used as intermediate
+ * values when decoding the Algorithm ID, set them for completeness,
+ * but they are not used */
+ pbe_params.iteration.data = &iteration_count;
+ pbe_params.iteration.len = 1;
+ pbe_params.keyLength.data = &keyLen;
+ pbe_params.keyLength.len = 1;
+ /* pkcs5v2 stores the key in the AlgorithmID, so we don't need to
+ * generate it here */
+ pbe_params.ivLen = 0;
+ pbe_params.ivData = NULL;
+ /* keyID is only used by pkcs12 extensions to pkcs5v1 */
+ pbe_params.keyID = pbeBitGenCipherKey;
+ /* Algorithm is used by the decryption code after get get our key */
+ pbe_params.encAlg = SEC_OID_AES_256_CBC;
+ /* these are the fields actually used in nsspkcs5_ComputeKeyAndIV
+ * for NSSPKCS5_PBKDF2 */
+ pbe_params.iter = iteration_count;
+ pbe_params.keyLen = keyLen;
+ pbe_params.hashType = HASH_AlgSHA256;
+ pbe_params.pbeType = NSSPKCS5_PBKDF2;
+ pbe_params.is2KeyDES = PR_FALSE;
+
+ result = nsspkcs5_ComputeKeyAndIV(&pbe_params, &inKey, NULL, PR_FALSE);
+ if ((result == NULL) || (result->len != sizeof(pbkdf_known_answer)) ||
+ (PORT_Memcmp(result->data, pbkdf_known_answer, sizeof(pbkdf_known_answer)) != 0)) {
+ SECITEM_FreeItem(result, PR_TRUE);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ SECITEM_FreeItem(result, PR_TRUE);
+ return SECSuccess;
+}
--- a/lib/softoken/lowpbe.h
+++ b/lib/softoken/lowpbe.h
@@ -98,11 +98,15 @@ nsspkcs5_ComputeKeyAndIV(NSSPKCS5PBEPara
/* Destroys PBE parameter */
extern void
nsspkcs5_DestroyPBEParameter(NSSPKCS5PBEParameter *param);
HASH_HashType HASH_FromHMACOid(SECOidTag oid);
SECOidTag HASH_HMACOidFromHash(HASH_HashType);
+/* fips selftest */
+extern SECStatus
+sftk_fips_pbkdf_PowerUpSelfTests(void);
+
SEC_END_PROTOS
#endif
--- a/lib/softoken/pkcs11c.c
+++ b/lib/softoken/pkcs11c.c
@@ -6851,32 +6851,32 @@ sftk_DeriveEncrypt(SFTKCipher encrypt, v
}
crv = sftk_forceAttribute(key, CKA_VALUE, tmpdata, keySize);
return crv;
}
CK_RV
sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_SESSION_HANDLE hSession,
- SFTKObject *sourceKey, unsigned char *sourceKeyBytes,
- int sourceKeyLen, SFTKObject *key, int keySize,
- PRBool canBeData, PRBool isFIPS)
+ SFTKObject *sourceKey, const unsigned char *sourceKeyBytes,
+ int sourceKeyLen, SFTKObject *key, unsigned char *outKeyBytes,
+ int keySize, PRBool canBeData, PRBool isFIPS)
{
SFTKSession *session;
SFTKAttribute *saltKey_att = NULL;
const SECHashObject *rawHash;
unsigned hashLen;
unsigned genLen = 0;
unsigned char hashbuf[HASH_LENGTH_MAX];
unsigned char keyBlock[9 * SFTK_MAX_MAC_LENGTH];
unsigned char *keyBlockAlloc = NULL; /* allocated keyBlock */
unsigned char *keyBlockData = keyBlock; /* pointer to current keyBlock */
- unsigned char *prk; /* psuedo-random key */
+ const unsigned char *prk; /* psuedo-random key */
CK_ULONG prkLen;
- unsigned char *okm; /* output keying material */
+ const unsigned char *okm; /* output keying material */
HASH_HashType hashType = GetHashTypeFromMechanism(params->prfHashMechanism);
SFTKObject *saltKey = NULL;
CK_RV crv = CKR_OK;
/* Spec says it should be the base hash, but also accept the HMAC */
if (hashType == HASH_AlgNULL) {
hashType = sftk_HMACMechanismToHash(params->prfHashMechanism);
}
@@ -6891,19 +6891,24 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
(params->bExpand && params->ulInfoLen > 0 && !params->pInfo)) {
return CKR_MECHANISM_PARAM_INVALID;
}
if ((params->bExpand && keySize == 0) ||
(!params->bExpand && keySize > hashLen) ||
(params->bExpand && keySize > 255 * hashLen)) {
return CKR_TEMPLATE_INCONSISTENT;
}
- crv = sftk_DeriveSensitiveCheck(sourceKey, key, canBeData);
- if (crv != CKR_OK)
- return crv;
+
+ /* sourceKey is NULL if we are called from the POST, skip the
+ * sensitiveCheck */
+ if (sourceKey != NULL) {
+ crv = sftk_DeriveSensitiveCheck(sourceKey, key, canBeData);
+ if (crv != CKR_OK)
+ return crv;
+ }
/* HKDF-Extract(salt, base key value) */
if (params->bExtract) {
CK_BYTE *salt;
CK_ULONG saltLen;
HMACContext *hmac;
unsigned int bufLen;
@@ -7009,19 +7014,25 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
HMAC_Update(hmac, &bi, 1);
HMAC_Finish(hmac, &keyBlockData[(bi - 1) * hashLen], &len,
hashLen);
PORT_Assert(len == hashLen);
}
HMAC_Destroy(hmac, PR_TRUE);
okm = &keyBlockData[0];
}
- /* key material = prk */
- crv = sftk_forceAttribute(key, CKA_VALUE, okm, keySize);
- PORT_Memset(okm, 0, genLen);
+ /* key material = okm */
+ crv = CKR_OK;
+ if (key) {
+ crv = sftk_forceAttribute(key, CKA_VALUE, okm, keySize);
+ } else {
+ PORT_Assert(outKeyBytes != NULL);
+ PORT_Memcpy(outKeyBytes, okm, keySize);
+ }
+ PORT_Memset(keyBlockData, 0, genLen);
PORT_Memset(hashbuf, 0, sizeof(hashbuf));
PORT_Free(keyBlockAlloc);
return CKR_OK;
}
/*
* SSL Key generation given pre master secret
*/
@@ -8563,28 +8574,28 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
hkdfParams.ulSaltLen = params->ulSaltLen;
hkdfParams.hSaltKey = CK_INVALID_HANDLE;
hkdfParams.pInfo = params->pInfo;
hkdfParams.ulInfoLen = params->ulInfoLen;
hkdfParams.prfHashMechanism = hashMech;
crv = sftk_HKDF(&hkdfParams, hSession, sourceKey,
att->attrib.pValue, att->attrib.ulValueLen,
- key, keySize, PR_FALSE, isFIPS);
+ key, NULL, keySize, PR_FALSE, isFIPS);
} break;
case CKM_HKDF_DERIVE:
case CKM_HKDF_DATA: /* only difference is the class of key */
if ((pMechanism->pParameter == NULL) ||
(pMechanism->ulParameterLen != sizeof(CK_HKDF_PARAMS))) {
crv = CKR_MECHANISM_PARAM_INVALID;
break;
}
crv = sftk_HKDF((CK_HKDF_PARAMS_PTR)pMechanism->pParameter,
hSession, sourceKey, att->attrib.pValue,
- att->attrib.ulValueLen, key, keySize, PR_TRUE,
+ att->attrib.ulValueLen, key, NULL, keySize, PR_TRUE,
isFIPS);
break;
case CKM_NSS_JPAKE_ROUND2_SHA1:
hashType = HASH_AlgSHA1;
goto jpake2;
case CKM_NSS_JPAKE_ROUND2_SHA256:
hashType = HASH_AlgSHA256;
goto jpake2;
--- a/lib/softoken/pkcs11i.h
+++ b/lib/softoken/pkcs11i.h
@@ -895,28 +895,37 @@ sftk_TLSPRFInit(SFTKSessionContext *cont
unsigned int out_len);
/* PKCS#11 MAC implementation. See sftk_MACCtxStr declaration above for
* calling semantics for these functions. */
HASH_HashType sftk_HMACMechanismToHash(CK_MECHANISM_TYPE mech);
CK_RV sftk_MAC_Create(CK_MECHANISM_TYPE mech, SFTKObject *key, sftk_MACCtx **ret_ctx);
CK_RV sftk_MAC_Init(sftk_MACCtx *ctx, CK_MECHANISM_TYPE mech, SFTKObject *key);
CK_RV sftk_MAC_InitRaw(sftk_MACCtx *ctx, CK_MECHANISM_TYPE mech, const unsigned char *key, unsigned int key_len, PRBool isFIPS);
-CK_RV sftk_MAC_Update(sftk_MACCtx *ctx, CK_BYTE_PTR data, unsigned int data_len);
+CK_RV sftk_MAC_Update(sftk_MACCtx *ctx, const CK_BYTE *data, unsigned int data_len);
CK_RV sftk_MAC_Finish(sftk_MACCtx *ctx, CK_BYTE_PTR result, unsigned int *result_len, unsigned int max_result_len);
CK_RV sftk_MAC_Reset(sftk_MACCtx *ctx);
void sftk_MAC_Destroy(sftk_MACCtx *ctx, PRBool free_it);
/* constant time helpers */
unsigned int sftk_CKRVToMask(CK_RV rv);
CK_RV sftk_CheckCBCPadding(CK_BYTE_PTR pBuf, unsigned int bufLen,
unsigned int blockSize, unsigned int *outPadSize);
/* NIST 800-108 (kbkdf.c) implementations */
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);
+extern SECStatus sftk_fips_SP800_108_PowerUpSelfTests(void);
+
+/* export the HKDF function for use in PowerupSelfTests */
+CK_RV sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_SESSION_HANDLE hSession,
+ SFTKObject *sourceKey, const unsigned char *sourceKeyBytes,
+ int sourceKeyLen, SFTKObject *key,
+ unsigned char *outKeyBytes, int keySize,
+ PRBool canBeData, PRBool isFIPS);
+
char **NSC_ModuleDBFunc(unsigned long function, char *parameters, void *args);
/* dh verify functions */
/* verify that dhPrime matches one of our known primes, and if so return
* it's subprime value */
const SECItem *sftk_VerifyDH_Prime(SECItem *dhPrime);
/* check if dhSubPrime claims dhPrime is a safe prime. */
SECStatus sftk_IsSafePrime(SECItem *dhPrime, SECItem *dhSubPrime, PRBool *isSafe);
--- a/lib/softoken/sftkhmac.c
+++ b/lib/softoken/sftkhmac.c
@@ -350,17 +350,17 @@ sftk_MAC_Reset(sftk_MACCtx *ctx)
PR_ASSERT(PR_FALSE);
return CKR_FUNCTION_FAILED;
}
return CKR_OK;
}
CK_RV
-sftk_MAC_Update(sftk_MACCtx *ctx, CK_BYTE_PTR data, unsigned int data_len)
+sftk_MAC_Update(sftk_MACCtx *ctx, const CK_BYTE *data, unsigned int data_len)
{
switch (ctx->mech) {
case CKM_MD2_HMAC:
case CKM_MD5_HMAC:
case CKM_SHA_1_HMAC:
case CKM_SHA224_HMAC:
case CKM_SHA256_HMAC:
case CKM_SHA384_HMAC:
--- a/lib/softoken/sftkike.c
+++ b/lib/softoken/sftkike.c
@@ -850,20 +850,22 @@ fail:
* T2 = prf(K, T1 | S | 0x02)
* T3 = prf(K, T3 | S | 0x03)
* T4 = prf(K, T4 | S | 0x04)
* .
* Tn = prf(K, T(n-1) | n)
* K = inKey, S = seedKey | seedData
*/
-CK_RV
-sftk_ike_prf_plus(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey,
- const CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS *params, SFTKObject *outKey,
- unsigned int keySize)
+static CK_RV
+sftk_ike_prf_plus_raw(CK_SESSION_HANDLE hSession,
+ const unsigned char *inKeyData, CK_ULONG inKeyLen,
+ const CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS *params,
+ unsigned char **outKeyDataPtr, unsigned int *outKeySizePtr,
+ unsigned int keySize)
{
SFTKAttribute *seedValue = NULL;
SFTKObject *seedKeyObj = NULL;
unsigned char *outKeyData = NULL;
unsigned int outKeySize;
unsigned char *thisKey;
unsigned char *lastKey = NULL;
unsigned char currentByte = 0;
@@ -919,18 +921,17 @@ sftk_ike_prf_plus(CK_SESSION_HANDLE hSes
/* if currentByte is 255, we'll overflow when we increment it below.
* This can only happen if keysize > 255*macSize. In that case
* the application has asked for too much key material, so return
* an error */
if (currentByte == 255) {
crv = CKR_KEY_SIZE_RANGE;
goto fail;
}
- crv = prf_init(&context, inKey->attrib.pValue,
- inKey->attrib.ulValueLen);
+ crv = prf_init(&context, inKeyData, inKeyLen);
if (crv != CKR_OK) {
goto fail;
}
if (lastKey) {
crv = prf_update(&context, lastKey, macSize);
if (crv != CKR_OK) {
goto fail;
@@ -959,31 +960,57 @@ sftk_ike_prf_plus(CK_SESSION_HANDLE hSes
}
crv = prf_final(&context, thisKey, macSize);
if (crv != CKR_OK) {
goto fail;
}
lastKey = thisKey;
thisKey += macSize;
}
- crv = sftk_forceAttribute(outKey, CKA_VALUE, outKeyData, keySize);
+ *outKeyDataPtr = outKeyData;
+ *outKeySizePtr = outKeySize;
+ outKeyData = NULL; /* don't free it here, our caller will free it */
fail:
if (outKeyData) {
PORT_ZFree(outKeyData, outKeySize);
}
if (seedValue) {
sftk_FreeAttribute(seedValue);
}
if (seedKeyObj) {
sftk_FreeObject(seedKeyObj);
}
prf_free(&context);
return crv;
}
+/*
+ * ike prf + with code to deliever results tosoftoken objects.
+ */
+CK_RV
+sftk_ike_prf_plus(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey,
+ const CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS *params, SFTKObject *outKey,
+ unsigned int keySize)
+{
+ unsigned char *outKeyData = NULL;
+ unsigned int outKeySize;
+ CK_RV crv;
+
+ crv = sftk_ike_prf_plus_raw(hSession, inKey->attrib.pValue,
+ inKey->attrib.ulValueLen, params,
+ &outKeyData, &outKeySize, keySize);
+ if (crv != CKR_OK) {
+ return crv;
+ }
+
+ crv = sftk_forceAttribute(outKey, CKA_VALUE, outKeyData, keySize);
+ PORT_ZFree(outKeyData, outKeySize);
+ return crv;
+}
+
/* sftk_aes_xcbc_new_keys:
*
* aes xcbc creates 3 new keys from the input key. The first key will be the
* base key of the underlying cbc. The sign code hooks directly into encrypt
* so we'll have to create a full PKCS #11 key with handle for that key. The
* caller needs to delete the key when it's through setting up the context.
*
* The other two keys will be stored in the sign context until we need them
@@ -1289,17 +1316,31 @@ sftk_fips_IKE_PowerUpSelfTests(void)
0x58, 0xd4, 0x04, 0x18, 0xde, 0xa9, 0x80, 0x96,
0xe5, 0x19, 0xbc, 0x78, 0x41, 0xe3, 0xdb, 0x3d,
0xd9, 0x36, 0x58, 0xd1, 0x18, 0xc3, 0xe8, 0x3b,
0x50, 0x2f, 0x39, 0x8e, 0xcb, 0x13, 0x61, 0xec,
0x77, 0xd3, 0x8a, 0x88, 0x55, 0xef, 0xff, 0x40,
0x7f, 0x6f, 0x77, 0x2e, 0x5d, 0x65, 0xb5, 0x8e,
0xb1, 0x13, 0x40, 0x96, 0xe8, 0x47, 0x8d, 0x2b
};
+ static const PRUint8 ike_known_sha256_prf_plus[] = {
+ 0xe6, 0xf1, 0x9b, 0x4a, 0x02, 0xe9, 0x73, 0x72,
+ 0x93, 0x9f, 0xdb, 0x46, 0x1d, 0xb1, 0x49, 0xcb,
+ 0x53, 0x08, 0x98, 0x3d, 0x41, 0x36, 0xfa, 0x8b,
+ 0x47, 0x04, 0x49, 0x11, 0x0d, 0x6e, 0x96, 0x1d,
+ 0xab, 0xbe, 0x94, 0x28, 0xa0, 0xb7, 0x9c, 0xa3,
+ 0x29, 0xe1, 0x40, 0xf8, 0xf8, 0x88, 0xb9, 0xb5,
+ 0x40, 0xd4, 0x54, 0x4d, 0x25, 0xab, 0x94, 0xd4,
+ 0x98, 0xd8, 0x00, 0xbf, 0x6f, 0xef, 0xe8, 0x39
+ };
SECStatus rv;
+ CK_RV crv;
+ unsigned char *outKeyData = NULL;
+ unsigned int outKeySize;
+ CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS ike_params;
rv = prf_test(CKM_AES_XCBC_MAC,
ike_xcbc_known_key, sizeof(ike_xcbc_known_key),
ike_xcbc_known_plain_text, sizeof(ike_xcbc_known_plain_text),
ike_xcbc_known_mac, sizeof(ike_xcbc_known_mac));
if (rv != SECSuccess)
return rv;
rv = prf_test(CKM_AES_XCBC_MAC,
@@ -1340,10 +1381,28 @@ sftk_fips_IKE_PowerUpSelfTests(void)
ike_sha384_known_mac, sizeof(ike_sha384_known_mac));
if (rv != SECSuccess)
return rv;
rv = prf_test(CKM_SHA512_HMAC,
ike_sha512_known_key, sizeof(ike_sha512_known_key),
ike_sha512_known_plain_text,
sizeof(ike_sha512_known_plain_text),
ike_sha512_known_mac, sizeof(ike_sha512_known_mac));
+
+ ike_params.prfMechanism = CKM_SHA256_HMAC;
+ ike_params.bHasSeedKey = PR_FALSE;
+ ike_params.hSeedKey = CK_INVALID_HANDLE;
+ ike_params.pSeedData = (CK_BYTE_PTR)ike_sha256_known_plain_text;
+ ike_params.ulSeedDataLen = sizeof(ike_sha256_known_plain_text);
+ crv = sftk_ike_prf_plus_raw(CK_INVALID_HANDLE, ike_sha256_known_key,
+ sizeof(ike_sha256_known_key), &ike_params,
+ &outKeyData, &outKeySize, 64);
+ if ((crv != CKR_OK) ||
+ (outKeySize != sizeof(ike_known_sha256_prf_plus)) ||
+ (PORT_Memcmp(outKeyData, ike_known_sha256_prf_plus,
+ sizeof(ike_known_sha256_prf_plus)) != 0)) {
+ PORT_ZFree(outKeyData, outKeySize);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ PORT_ZFree(outKeyData, outKeySize);
return rv;
}