diff -up ./gtests/common/testvectors_base/test-structs.h.orig ./gtests/common/testvectors_base/test-structs.h --- ./gtests/common/testvectors_base/test-structs.h.orig 2020-06-16 15:50:59.000000000 -0700 +++ ./gtests/common/testvectors_base/test-structs.h 2020-12-05 10:54:36.648849921 -0800 @@ -66,6 +66,31 @@ typedef struct EcdhTestVectorStr { bool valid; } EcdhTestVector; +enum class IkeTestType { + ikeGxy, /* CKM_NSS_IKE_PRF_DERIVE case 1 */ + ikeV1Psk, /* CKM_NSS_IKE_PRF_DERIVE case 2 */ + ikeV2Rekey, /* CKM_NSS_IKE_PRF_DERIVE case 3 */ + ikeV1, /* CKM_NSS_IKE1_PRF_DERIVE */ + ikeV1AppB, /* CKM_NSS_IKE1_PRF_APP_B_DERIVE base mode */ + ikeV1AppBQuick, /* CKM_NSS_IKE1_PRF_APP_B_DERIVE quick mode */ + ikePlus /* CKM_NSS_IKE_PRF_DERIVE */ +}; + +typedef struct IkeTestVectorStr { + uint32_t id; + IkeTestType test_type; + std::string ikm; + std::string gxykm; + std::string prevkm; + std::string okm; + std::string Ni; + std::string Nr; + std::string seed_data; + uint8_t key_number; + uint32_t size; + bool valid; +} IkeTestVector; + typedef struct RsaSignatureTestVectorStr { SECOidTag hash_oid; uint32_t id; diff -up ./gtests/common/testvectors/ike-sha1-vectors.h.orig ./gtests/common/testvectors/ike-sha1-vectors.h --- ./gtests/common/testvectors/ike-sha1-vectors.h.orig 2020-12-05 10:54:36.649849926 -0800 +++ ./gtests/common/testvectors/ike-sha1-vectors.h 2020-12-05 11:01:09.170017713 -0800 @@ -0,0 +1,114 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* This file is generated from sources in nss/gtests/common/wycheproof + * automatically and should not be touched manually. + * Generation is trigged by calling python3 genTestVectors.py */ + +#ifndef ike_sha1_vectors_h__ +#define ike_sha1_vectors_h__ + +#include "testvectors_base/test-structs.h" + +const IkeTestVector kIkeSha1ProofVectors[] = { + // these vectors are from this NIST samples + {1, IkeTestType::ikeGxy, + "8ba4cbc73c0187301dc19a975823854dbd641c597f637f8d053a83b9514673eb", + "", "", "707197817fb2d90cf54d1842606bdea59b9f4823", + "69a62284195f1680", "80c94ba25c8abda5", + "", 0, 0, true }, + {2, IkeTestType::ikeV1, + "707197817fb2d90cf54d1842606bdea59b9f4823", + "8ba4cbc73c0187301dc19a975823854dbd641c597f637f8d053a83b9514673eb", + "", "384be709a8a5e63c3ed160cfe3921c4b37d5b32d", + "8c3bcd3a69831d7f", "d2d9a7ff4fbe95a7", + "", 0, 0, true }, + {3, IkeTestType::ikeV1, + "707197817fb2d90cf54d1842606bdea59b9f4823", + "8ba4cbc73c0187301dc19a975823854dbd641c597f637f8d053a83b9514673eb", + "384be709a8a5e63c3ed160cfe3921c4b37d5b32d", + "48b327575abe3adba0f279849e289022a13e2b47", + "8c3bcd3a69831d7f", "d2d9a7ff4fbe95a7", + "", 1, 0, true }, + {4, IkeTestType::ikeV1, + "707197817fb2d90cf54d1842606bdea59b9f4823", + "8ba4cbc73c0187301dc19a975823854dbd641c597f637f8d053a83b9514673eb", + "48b327575abe3adba0f279849e289022a13e2b47", + "a4a415c8e0c38c0da847c356cc61c24df8025560", + "8c3bcd3a69831d7f", "d2d9a7ff4fbe95a7", + "", 2, 0, true }, + {5, IkeTestType::ikeV1Psk, "c0", "", "", + "ab3be41bc62f2ef0c41a3076d58768be77fadd2e", + "03a6f25a83c8c2a3", "9d958a6618f77e7f", + "", 0, 0, true }, + {6, IkeTestType::ikeGxy, + "4b2c1f971981a8ad8d0abeafabf38cf75fc8349c148142465ed9c8b516b8be52", + "", "", "a9a7b222b59f8f48645f28a1db5b5f5d7479cba7", + "32b50d5f4a3763f3", "9206a04b26564cb1", + "", 0, 0, true }, + {7, IkeTestType::ikeV2Rekey, + "a14293677cc80ff8f9cc0eee30d895da9d8f4056", + "863f3c9d06efd39d2b907b97f8699e5dd5251ef64a2a176f36ee40c87d4f9330", + "", "63e81194946ebd05df7df5ebf5d8750056bf1f1d", + "32b50d5f4a3763f3", "9206a04b26564cb1", + "", 0, 0, true }, + {8, IkeTestType::ikePlus, + "a9a7b222b59f8f48645f28a1db5b5f5d7479cba7", "", "", + "a14293677cc80ff8f9cc0eee30d895da9d8f405666e30ef0dfcb63c634a46002a2a63080e514a062768b76606f9fa5e992204fc5a670bde3f10d6b027113936a5c55b648a194ae587b0088d52204b702c979fa280870d2ed41efa9c549fd11198af1670b143d384bd275c5f594cf266b05ebadca855e4249520a441a81157435a7a56cc4", "", "", + // seed_data is Ni || Nr || SPIi || SPIr + // NOTE: there is no comma so the strings are concatenated together. + "32b50d5f4a3763f3" // Ni + "9206a04b26564cb1" // Nr + "34c9e7c188868785" // SPIi + "3ff77d760d2b2199", // SPIr + 0, 132, true }, + {9, IkeTestType::ikePlus, + "a9a7b222b59f8f48645f28a1db5b5f5d7479cba7", "", "", + "a14293677cc80ff8f9cc0eee30d895da9d8f405666e30ef0dfcb63c634a46002a2a63080e514a062", "", "", + // seed_data is Ni || Nr || SPIi || SPIr + // NOTE: there is no comma so the strings are concatenated together. + "32b50d5f4a3763f3" // Ni + "9206a04b26564cb1" // Nr + "34c9e7c188868785" // SPIi + "3ff77d760d2b2199", // SPIr + 0, 40, true }, + {10, IkeTestType::ikePlus, + "a9a7b222b59f8f48645f28a1db5b5f5d7479cba7", "", "", + "a14293677cc80ff8f9cc0eee30d895", "", "", + // seed_data is Ni || Nr || SPIi || SPIr + // NOTE: there is no comma so the strings are concatenated together. + "32b50d5f4a3763f3" // Ni + "9206a04b26564cb1" // Nr + "34c9e7c188868785" // SPIi + "3ff77d760d2b2199", // SPIr + 0, 15, true }, + // these vectors are self-generated + {11, IkeTestType::ikeV1AppB, + "63e81194946ebd05df7df5ebf5d8750056bf1f1d", "", "", + "933347a07de5782247dd36d1562ffe0eecade1eb4134165257e3af1000af8ae3f165063828cbb60d910b7db38fa3c7f62c4afaaf3203da065c841729853edb23e9e7ac8286ae65c8cb6c667d79268c0bd6705abb9131698eb822b1c1f9dd142fc7be2c1010ee0152e10195add98999c6b6d42c8fe9c1b134d56ad5f2c6f20e815bd25c52", + "", "", "", 0, 132, true }, + {12, IkeTestType::ikeV1AppB, + "63e81194946ebd05df7df5ebf5d8750056bf1f1d", "", "", + "933347a07de5782247dd36d1562ffe0eecade1eb4134165257e3af1000af8ae3f165063828cbb60d", + "", "", "", 0, 40, true }, + {13, IkeTestType::ikeV1AppB, + "63e81194946ebd05df7df5ebf5d8750056bf1f1d", "", "", + "63e81194946ebd05df7df5ebf5d875", + "", "", "", 0, 15, true }, + {14, IkeTestType::ikeV1AppBQuick, + "63e81194946ebd05df7df5ebf5d8750056bf1f1d", "", "", + "933347a07de5782247dd36d1562ffe0eecade1ebaeaa476a5f578c34a9b2b7101a621202f61db924c5ef9efa3bb2698095841603b7ac8a880329a927ecd4ad53a944b607a5ac2f3d154e2748c188d7370d76be83fc204fdacf0f66b99dd760ba619ffac65eda1420c8a936dac5a599afaf4043b29ef2b65dc042724355b550875316c6fd", + "", "", "0", 0, 132, true }, + {15, IkeTestType::ikeV1AppBQuick, + "63e81194946ebd05df7df5ebf5d8750056bf1f1d", "", "", + "933347a07de5782247dd36d1562ffe0eecade1ebaeaa476a5f578c34a9b2b7101a621202f61db924", + "", "", "0", 0, 40, true }, + {16, IkeTestType::ikeV1AppBQuick, + "63e81194946ebd05df7df5ebf5d8750056bf1f1d", "", "", + "933347a07de5782247dd36d1562ffe", + "", "", "0", 0, 15, true }, + }; + +#endif // ike_sha1_vectors_h__ diff -up ./gtests/pk11_gtest/manifest.mn.orig ./gtests/pk11_gtest/manifest.mn --- ./gtests/pk11_gtest/manifest.mn.orig 2020-12-05 10:53:12.529385354 -0800 +++ ./gtests/pk11_gtest/manifest.mn 2020-12-05 10:54:36.649849926 -0800 @@ -22,6 +22,7 @@ CPPSRCS = \ pk11_export_unittest.cc \ pk11_find_certs_unittest.cc \ pk11_hkdf_unittest.cc \ + pk11_ike_unittest.cc \ pk11_import_unittest.cc \ pk11_kdf_unittest.cc \ pk11_kbkdf.cc \ diff -up ./gtests/pk11_gtest/pk11_gtest.gyp.orig ./gtests/pk11_gtest/pk11_gtest.gyp --- ./gtests/pk11_gtest/pk11_gtest.gyp.orig 2020-06-16 15:50:59.000000000 -0700 +++ ./gtests/pk11_gtest/pk11_gtest.gyp 2020-12-05 10:54:36.649849926 -0800 @@ -27,6 +27,7 @@ 'pk11_encrypt_derive_unittest.cc', 'pk11_find_certs_unittest.cc', 'pk11_hkdf_unittest.cc', + 'pk11_ike_unittest.cc', 'pk11_import_unittest.cc', 'pk11_kbkdf.cc', 'pk11_keygen.cc', diff -up ./gtests/pk11_gtest/pk11_ike_unittest.cc.orig ./gtests/pk11_gtest/pk11_ike_unittest.cc --- ./gtests/pk11_gtest/pk11_ike_unittest.cc.orig 2020-12-05 10:54:36.649849926 -0800 +++ ./gtests/pk11_gtest/pk11_ike_unittest.cc 2020-12-05 10:54:36.649849926 -0800 @@ -0,0 +1,197 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include "blapi.h" +#include "gtest/gtest.h" +#include "nss.h" +#include "nss_scoped_ptrs.h" +#include "pk11pub.h" +#include "secerr.h" +#include "sechash.h" +#include "util.h" + +#include "testvectors/ike-sha1-vectors.h" +#ifdef notdef +#include "testvectors/ike-sha256-vectors.h" +#include "testvectors/ike-aesxcbc-vectors.h" +#endif + +namespace nss_test { + +class Pkcs11IkeTest + : public ::testing::TestWithParam< + std::tuple> { + protected: + void dump_item(const char *label, SECItem *item) { + printf("%s: %d bytes { \"",label, item->len); + unsigned int i; + for (i=0; i < item->len; i++) { + printf("%02x",item->data[i]); + } + printf("\"\n"); + } + + ScopedPK11SymKey ImportKey(SECItem &ikm_item) { + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + if (!slot) { + ADD_FAILURE() << "Can't get slot"; + return nullptr; + } + ScopedPK11SymKey ikm(PK11_ImportSymKey(slot.get(), + CKM_GENERIC_SECRET_KEY_GEN, + PK11_OriginUnwrap, CKA_DERIVE, &ikm_item, + nullptr)); + return ikm; + } + + void RunVectorTest(const IkeTestVector &vec, CK_MECHANISM_TYPE prf_mech) { + std::string msg = "Test #" + std::to_string(vec.id) + " failed"; + std::vector vec_ikm = hex_string_to_bytes(vec.ikm); + std::vector vec_okm = hex_string_to_bytes(vec.okm); + std::vector vec_gxykm = hex_string_to_bytes(vec.gxykm); + std::vector vec_prevkm = hex_string_to_bytes(vec.prevkm); + std::vector vec_Ni = hex_string_to_bytes(vec.Ni); + std::vector vec_Nr = hex_string_to_bytes(vec.Nr); + std::vector vec_seed_data = hex_string_to_bytes(vec.seed_data); + SECItem ikm_item = {siBuffer, vec_ikm.data(), + static_cast(vec_ikm.size())}; + SECItem okm_item = {siBuffer, vec_okm.data(), + static_cast(vec_okm.size())}; + SECItem prevkm_item = {siBuffer, vec_prevkm.data(), + static_cast(vec_prevkm.size())}; + SECItem gxykm_item = {siBuffer, vec_gxykm.data(), + static_cast(vec_gxykm.size())}; + CK_MECHANISM_TYPE derive_mech = CKM_NSS_IKE_PRF_DERIVE; + ScopedPK11SymKey gxy_key= nullptr; + ScopedPK11SymKey prev_key= nullptr; + ScopedPK11SymKey ikm = ImportKey(ikm_item); + + // IKE_PRF structure (used in cases 1, 2 and 3) + CK_NSS_IKE_PRF_DERIVE_PARAMS nss_ike_prf_params = { + prf_mech, false, false, + vec_Ni.data(), static_cast(vec_Ni.size()), + vec_Nr.data(), static_cast(vec_Nr.size()), + CK_INVALID_HANDLE + }; + + // IKE_V1_PRF, used to derive session keys. + CK_NSS_IKE1_PRF_DERIVE_PARAMS nss_ike_v1_prf_params = { + prf_mech, false, CK_INVALID_HANDLE, CK_INVALID_HANDLE, + vec_Ni.data(), static_cast(vec_Ni.size()), + vec_Nr.data(), static_cast(vec_Nr.size()), + vec.key_number + }; + + // IKE_V1_APP_B, do quick mode (all session keys in one call). + CK_NSS_IKE1_APP_B_PRF_DERIVE_PARAMS nss_ike_app_b_prf_params_quick = { + prf_mech, false, CK_INVALID_HANDLE, + vec_seed_data.data(), static_cast(vec_seed_data.size()) + }; + + // IKE_V1_APP_B, used for long session keys in ike_v1 + CK_MECHANISM_TYPE nss_ike_app_b_prf_params = prf_mech; + + // IKE_PRF_PLUS, used to generate session keys in ike v2 + CK_NSS_IKE_PRF_PLUS_DERIVE_PARAMS nss_ike_prf_plus_params = { + prf_mech, false, CK_INVALID_HANDLE, + vec_seed_data.data(), static_cast(vec_seed_data.size()) + }; + + + SECItem params_item = {siBuffer, (unsigned char *)&nss_ike_prf_params, + sizeof(nss_ike_prf_params)}; + + switch (vec.test_type) { + case IkeTestType::ikeGxy: + nss_ike_prf_params.bDataAsKey = true; + break; + case IkeTestType::ikeV1Psk: + break; + case IkeTestType::ikeV2Rekey: + nss_ike_prf_params.bRekey = true; + gxy_key = ImportKey(gxykm_item); + nss_ike_prf_params.hNewKey = PK11_GetSymKeyHandle(gxy_key.get()); + break; + case IkeTestType::ikeV1: + derive_mech = CKM_NSS_IKE1_PRF_DERIVE; + params_item.data = (unsigned char *) &nss_ike_v1_prf_params; + params_item.len = sizeof(nss_ike_v1_prf_params); + gxy_key = ImportKey(gxykm_item); + nss_ike_v1_prf_params.hKeygxy = PK11_GetSymKeyHandle(gxy_key.get()); + if (prevkm_item.len != 0) { + prev_key = ImportKey(prevkm_item); + nss_ike_v1_prf_params.bHasPrevKey = true; + nss_ike_v1_prf_params.hPrevKey = PK11_GetSymKeyHandle(prev_key.get()); + } + break; + case IkeTestType::ikeV1AppB: + derive_mech = CKM_NSS_IKE1_APP_B_PRF_DERIVE; + params_item.data = (unsigned char *) &nss_ike_app_b_prf_params; + params_item.len = sizeof(nss_ike_app_b_prf_params); + break; + case IkeTestType::ikeV1AppBQuick: + derive_mech = CKM_NSS_IKE1_APP_B_PRF_DERIVE; + params_item.data = (unsigned char *) &nss_ike_app_b_prf_params_quick; + params_item.len = sizeof(nss_ike_app_b_prf_params_quick); + if (gxykm_item.len != 0) { + gxy_key = ImportKey(gxykm_item); + nss_ike_app_b_prf_params_quick.bHasKeygxy = true; + nss_ike_app_b_prf_params_quick.hKeygxy = + PK11_GetSymKeyHandle(gxy_key.get()); + } + break; + case IkeTestType::ikePlus: + derive_mech = CKM_NSS_IKE_PRF_PLUS_DERIVE; + params_item.data = (unsigned char *) &nss_ike_prf_plus_params; + params_item.len = sizeof(nss_ike_prf_plus_params); + break; + default: + ADD_FAILURE() << msg; + return; + } + ASSERT_NE(nullptr, ikm) << msg; + + ScopedPK11SymKey okm = ScopedPK11SymKey( + PK11_Derive(ikm.get(), derive_mech, ¶ms_item, + CKM_GENERIC_SECRET_KEY_GEN, CKA_DERIVE, vec.size)); + if (vec.valid) { + ASSERT_NE(nullptr, okm.get()) << msg; + ASSERT_EQ(SECSuccess, PK11_ExtractKeyValue(okm.get())) << msg; + SECItem *outItem = PK11_GetKeyData(okm.get()); + if (SECITEM_CompareItem(&okm_item, outItem) != 0) { + dump_item("expected key:", &okm_item); + dump_item("calculated key:", outItem); + } + ASSERT_EQ(0, SECITEM_CompareItem(&okm_item, PK11_GetKeyData(okm.get()))) + << msg; + } else { + ASSERT_EQ(nullptr, okm.get()) << msg; + } + } +}; + +TEST_P(Pkcs11IkeTest, IkeproofVectors) { + RunVectorTest(std::get<0>(GetParam()), std::get<1>(GetParam())); +} + +INSTANTIATE_TEST_CASE_P( + IkeSha1, Pkcs11IkeTest, + ::testing::Combine(::testing::ValuesIn(kIkeSha1ProofVectors), + ::testing::Values(CKM_SHA_1_HMAC))); +#ifdef notdef +INSTANTIATE_TEST_CASE_P( + IkeSha256, Pkcs11IkeTest, + ::testing::Combine(::testing::ValuesIn(kIkeSha256ProofVectors), + ::testing::Values(CKM_SHA256_HMAC))); + +INSTANTIATE_TEST_CASE_P( + IkeAESXCBC, Pkcs11IkeTest, + ::testing::Combine(::testing::ValuesIn(kIkeAesXcbcProofVectors), + ::testing::Values(CKM_AES_XCBC_MAC))); +#endif + +} // namespace nss_test diff -up ./lib/softoken/sftkike.c.orig ./lib/softoken/sftkike.c --- ./lib/softoken/sftkike.c.orig 2020-12-05 10:53:12.629385906 -0800 +++ ./lib/softoken/sftkike.c 2020-12-05 10:59:16.073393113 -0800 @@ -720,6 +720,7 @@ sftk_ike1_appendix_b_prf(CK_SESSION_HAND unsigned int macSize; unsigned int outKeySize; unsigned int genKeySize; + PRBool quickMode = PR_FALSE; CK_RV crv; prfContext context; @@ -748,6 +749,11 @@ sftk_ike1_appendix_b_prf(CK_SESSION_HAND crv = CKR_KEY_HANDLE_INVALID; goto fail; } + quickMode = PR_TRUE; + } + + if (params->ulExtraDataLen !=0) { + quickMode = PR_TRUE; } macSize = prf_length(&context); @@ -756,10 +762,16 @@ sftk_ike1_appendix_b_prf(CK_SESSION_HAND keySize = macSize; } - if (keySize <= inKey->attrib.ulValueLen) { + /* In appendix B, we are just expanding or contracting a single key. + * If the input key is less than equal the the key size we want, just + * subset the original key. In quick mode we are actually getting new + * keys (salted with our seed data and our gxy key), so we want to run + * through our algorithm */ + if ((!quickMode) && (keySize <= inKey->attrib.ulValueLen)) { return sftk_forceAttribute(outKey, CKA_VALUE, inKey->attrib.pValue, keySize); } + outKeySize = PR_ROUNDUP(keySize, macSize); outKeyData = PORT_Alloc(outKeySize); if (outKeyData == NULL) {