// 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 "gtest/gtest.h" #include "nss_scoped_ptrs.h" #include #include #include #include #include namespace nss_test { uint8_t kKeyData[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; SECItem kFull = {siBuffer, (unsigned char *)kKeyData, 16}; SECItem kLeftHalf = {siBuffer, (unsigned char *)kKeyData, 8}; SECItem kRightHalf = {siBuffer, (unsigned char *)kKeyData + 8, 8}; class Pkcs11SymKeyTest : public ::testing::Test { protected: PK11SymKey *ImportSymKey(PK11SlotInfo *slot, SECItem *key_data) { PK11SymKey *out = PK11_ImportSymKey(slot, CKM_NULL, PK11_OriginUnwrap, CKA_DERIVE, key_data, nullptr); EXPECT_NE(nullptr, out); return out; } void CheckKeyData(SECItem &expected, PK11SymKey *actual) { ASSERT_NE(nullptr, actual); SECStatus rv = PK11_ExtractKeyValue(actual); ASSERT_EQ(SECSuccess, rv); SECItem *keyData = PK11_GetKeyData(actual); ASSERT_NE(nullptr, keyData); ASSERT_NE(nullptr, keyData->data); ASSERT_EQ(expected.len, keyData->len); ASSERT_EQ(0, memcmp(expected.data, keyData->data, keyData->len)); } void SetSensitive(PK11SymKey *key) { ASSERT_NE(nullptr, key); CK_BBOOL cktrue = CK_TRUE; SECItem attrValue = {siBuffer, &cktrue, sizeof(CK_BBOOL)}; EXPECT_EQ(SECSuccess, PK11_WriteRawAttribute(PK11_TypeSymKey, key, CKA_SENSITIVE, &attrValue)); } void CheckIsSensitive(PK11SymKey *key) { ASSERT_NE(nullptr, key); StackSECItem attrValue; ASSERT_EQ(SECSuccess, PK11_ReadRawAttribute(PK11_TypeSymKey, key, CKA_SENSITIVE, &attrValue)); ASSERT_EQ(attrValue.len, sizeof(CK_BBOOL)); EXPECT_EQ(*(CK_BBOOL *)attrValue.data, CK_TRUE); } void SetNotExtractable(PK11SymKey *key) { ASSERT_NE(nullptr, key); CK_BBOOL ckfalse = CK_FALSE; SECItem attrValue = {siBuffer, &ckfalse, sizeof(CK_BBOOL)}; EXPECT_EQ(SECSuccess, PK11_WriteRawAttribute(PK11_TypeSymKey, key, CKA_EXTRACTABLE, &attrValue)); } void CheckIsNotExtractable(PK11SymKey *key) { ASSERT_NE(nullptr, key); StackSECItem attrValue; ASSERT_EQ(SECSuccess, PK11_ReadRawAttribute(PK11_TypeSymKey, key, CKA_EXTRACTABLE, &attrValue)); ASSERT_EQ(attrValue.len, sizeof(CK_BBOOL)); EXPECT_EQ(*(CK_BBOOL *)attrValue.data, CK_FALSE); } }; TEST_F(Pkcs11SymKeyTest, ConcatSymKeyTest) { ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); ASSERT_NE(nullptr, slot); ScopedPK11SymKey left(ImportSymKey(slot.get(), &kLeftHalf)); ScopedPK11SymKey right(ImportSymKey(slot.get(), &kRightHalf)); ScopedPK11SymKey key( PK11_ConcatSymKeys(left.get(), right.get(), CKM_HKDF_DERIVE, CKA_DERIVE)); CheckKeyData(kFull, key.get()); } // Test that the derived key is sensitive if either input is. TEST_F(Pkcs11SymKeyTest, SensitiveConcatSymKeyTest) { ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); ASSERT_NE(nullptr, slot); ScopedPK11SymKey left(ImportSymKey(slot.get(), &kLeftHalf)); SetSensitive(left.get()); ScopedPK11SymKey right(ImportSymKey(slot.get(), &kRightHalf)); ScopedPK11SymKey key( PK11_ConcatSymKeys(left.get(), right.get(), CKM_HKDF_DERIVE, CKA_DERIVE)); CheckIsSensitive(key.get()); // Again with left and right swapped ScopedPK11SymKey key2( PK11_ConcatSymKeys(right.get(), left.get(), CKM_HKDF_DERIVE, CKA_DERIVE)); CheckIsSensitive(key2.get()); } // Test that the derived key is extractable if either input is. TEST_F(Pkcs11SymKeyTest, NotExtractableConcatSymKeyTest) { ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); ASSERT_NE(nullptr, slot); ScopedPK11SymKey left(ImportSymKey(slot.get(), &kLeftHalf)); SetNotExtractable(left.get()); ScopedPK11SymKey right(ImportSymKey(slot.get(), &kRightHalf)); ScopedPK11SymKey key( PK11_ConcatSymKeys(left.get(), right.get(), CKM_HKDF_DERIVE, CKA_DERIVE)); CheckIsNotExtractable(key.get()); ScopedPK11SymKey key2( PK11_ConcatSymKeys(right.get(), left.get(), CKM_HKDF_DERIVE, CKA_DERIVE)); CheckIsNotExtractable(key2.get()); } // Test that keys can be concatenated on the key slot. TEST_F(Pkcs11SymKeyTest, KeySlotConcatSymKeyTest) { ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); ASSERT_NE(nullptr, slot); ScopedPK11SymKey left(ImportSymKey(slot.get(), &kLeftHalf)); ScopedPK11SymKey right(ImportSymKey(slot.get(), &kRightHalf)); ScopedPK11SymKey key( PK11_ConcatSymKeys(left.get(), right.get(), CKM_HKDF_DERIVE, CKA_DERIVE)); CheckKeyData(kFull, key.get()); } // Test that keys in different slots are moved to the same slot for derivation. // The PK11SymKey.data fields are set in PK11_ImportSymKey, so this just // re-imports the key data. TEST_F(Pkcs11SymKeyTest, CrossSlotConcatSymKeyTest) { ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); ASSERT_NE(nullptr, slot); ScopedPK11SlotInfo slot2(PK11_GetInternalKeySlot()); ASSERT_NE(nullptr, slot2); EXPECT_NE(slot, slot2); ScopedPK11SymKey left(ImportSymKey(slot.get(), &kLeftHalf)); ScopedPK11SymKey right(ImportSymKey(slot2.get(), &kRightHalf)); ScopedPK11SymKey key( PK11_ConcatSymKeys(left.get(), right.get(), CKM_HKDF_DERIVE, CKA_DERIVE)); CheckKeyData(kFull, key.get()); } } // namespace nss_test