diff --git a/lib/freebl/fipsfreebl.c b/lib/freebl/fipsfreebl.c --- a/lib/freebl/fipsfreebl.c +++ b/lib/freebl/fipsfreebl.c @@ -17,6 +17,7 @@ #include "prtypes.h" #include "secitem.h" #include "pkcs11t.h" +#include "cmac.h" #include "ec.h" /* Required for EC */ @@ -99,6 +100,7 @@ #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 */ @@ -310,6 +312,11 @@ 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, @@ -328,6 +335,11 @@ 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, @@ -346,6 +358,12 @@ 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; @@ -355,10 +373,14 @@ 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; @@ -547,6 +569,44 @@ 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); } @@ -743,6 +803,170 @@ 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) { @@ -1842,6 +2066,12 @@ 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). */ diff --git a/lib/softoken/fipstest.c b/lib/softoken/fipstest.c --- a/lib/softoken/fipstest.c +++ b/lib/softoken/fipstest.c @@ -13,6 +13,7 @@ #include "secoid.h" #include "secerr.h" #include "pkcs11i.h" +#include "lowpbe.h" /* * different platforms have different ways of calling and initial entry point @@ -581,6 +582,106 @@ 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; @@ -631,6 +732,22 @@ 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; } diff --git a/lib/softoken/kbkdf.c b/lib/softoken/kbkdf.c --- a/lib/softoken/kbkdf.c +++ b/lib/softoken/kbkdf.c @@ -90,7 +90,7 @@ } 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 @@ -265,7 +265,7 @@ } 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 }; @@ -344,7 +344,7 @@ /* [ 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) { @@ -392,7 +392,7 @@ } 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 @@ -465,7 +465,7 @@ } 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; @@ -519,7 +519,7 @@ } 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; @@ -749,7 +749,7 @@ /* [ 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; @@ -837,7 +837,7 @@ } 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; @@ -859,7 +859,7 @@ * 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. */ @@ -962,7 +962,7 @@ } 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; @@ -1109,31 +1109,17 @@ 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. @@ -1168,28 +1154,27 @@ */ 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; } @@ -1205,15 +1190,15 @@ 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. */ @@ -1226,8 +1211,65 @@ 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; } @@ -1235,8 +1277,242 @@ 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; +} diff --git a/lib/softoken/lowpbe.h b/lib/softoken/lowpbe.h --- a/lib/softoken/lowpbe.h +++ b/lib/softoken/lowpbe.h @@ -103,6 +103,10 @@ HASH_HashType HASH_FromHMACOid(SECOidTag oid); SECOidTag HASH_HMACOidFromHash(HASH_HashType); +/* fips selftest */ +extern SECStatus +sftk_fips_pbkdf_PowerUpSelfTests(void); + SEC_END_PROTOS #endif diff --git a/lib/softoken/lowpbe.c b/lib/softoken/lowpbe.c --- a/lib/softoken/lowpbe.c +++ b/lib/softoken/lowpbe.c @@ -1743,3 +1743,67 @@ 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; +} diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c --- a/lib/softoken/pkcs11c.c +++ b/lib/softoken/pkcs11c.c @@ -6856,9 +6856,9 @@ 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; @@ -6869,9 +6869,9 @@ 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; @@ -6896,9 +6896,14 @@ (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) { @@ -7014,9 +7019,15 @@ 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; @@ -8568,7 +8579,7 @@ 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 */ @@ -8579,7 +8590,7 @@ } 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: diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h --- a/lib/softoken/pkcs11i.h +++ b/lib/softoken/pkcs11i.h @@ -900,7 +900,7 @@ 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); @@ -912,6 +912,15 @@ /* 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 */ diff --git a/lib/softoken/sftkhmac.c b/lib/softoken/sftkhmac.c --- a/lib/softoken/sftkhmac.c +++ b/lib/softoken/sftkhmac.c @@ -355,7 +355,7 @@ } 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: diff --git a/lib/softoken/sftkike.c b/lib/softoken/sftkike.c --- a/lib/softoken/sftkike.c +++ b/lib/softoken/sftkike.c @@ -855,10 +855,12 @@ * 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; @@ -924,8 +926,7 @@ 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; } @@ -964,7 +965,9 @@ 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); @@ -979,6 +982,30 @@ 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 @@ -1294,7 +1321,21 @@ 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), @@ -1345,5 +1386,23 @@ 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; }