| // Copyright 2014 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "trunks/mock_tpm.h" |
| #include "trunks/tpm_generated.h" |
| #include "trunks/tpm_state_impl.h" |
| #include "trunks/trunks_factory_for_test.h" |
| |
| using testing::DoAll; |
| using testing::Invoke; |
| using testing::NiceMock; |
| using testing::Return; |
| using testing::SetArgPointee; |
| using testing::WithArgs; |
| using testing::_; |
| |
| namespace trunks { |
| |
| // A test fixture for TpmState tests. |
| class TpmStateTest : public testing::Test { |
| public: |
| TpmStateTest() = default; |
| ~TpmStateTest() override = default; |
| |
| void SetUp() override { |
| factory_.set_tpm(&mock_tpm_); |
| // All auth set (i.e. IsOwned() -> true) and in lockout. |
| fake_tpm_properties_[TPM_PT_PERMANENT] = 0x207; |
| // Orderly shutdown, storage and endorsement enabled, platform disabled |
| // (i.e. IsEnabled() -> true). |
| fake_tpm_properties_[TPM_PT_STARTUP_CLEAR] = 0x80000006; |
| fake_tpm_properties_[TPM_PT_LOCKOUT_COUNTER] = 2; |
| fake_tpm_properties_[TPM_PT_MAX_AUTH_FAIL] = 5; |
| fake_tpm_properties_[TPM_PT_LOCKOUT_INTERVAL] = 100; |
| fake_tpm_properties_[TPM_PT_LOCKOUT_RECOVERY] = 200; |
| fake_tpm_properties_[TPM_PT_NV_INDEX_MAX] = 2048; |
| fake_tpm_properties_[TPM_PT_NV_BUFFER_MAX] = 2048; |
| fake_algorithm_properties_[TPM_ALG_RSA] = 0x9; |
| fake_algorithm_properties_[TPM_ALG_ECC] = 0x9; |
| EXPECT_CALL(mock_tpm_, GetCapabilitySync(_, _, _, _, _, _)) |
| .WillRepeatedly(Invoke(this, &TpmStateTest::FakeGetCapability)); |
| } |
| |
| protected: |
| TPM_RC FakeGetCapability(const TPM_CAP& capability, |
| const UINT32& property, |
| const UINT32& property_count, |
| TPMI_YES_NO* more_data, |
| TPMS_CAPABILITY_DATA* capability_data, |
| AuthorizationDelegate* /* not_used */) { |
| // Return only two properties at a time, this will exercise the more_data |
| // logic. |
| constexpr uint32_t kMaxProperties = 2; |
| *more_data = NO; |
| memset(capability_data, 0, sizeof(TPMS_CAPABILITY_DATA)); |
| capability_data->capability = capability; |
| TPMU_CAPABILITIES& data = capability_data->data; |
| if (capability == TPM_CAP_TPM_PROPERTIES) { |
| // TPM properties get returned one group at a time, mimic this. |
| uint32_t group = (property >> 8); |
| uint32_t stop = PT_GROUP * (group + 1); |
| for (uint32_t i = property; i < stop; ++i) { |
| if (fake_tpm_properties_.count(i) > 0) { |
| if (data.tpm_properties.count == kMaxProperties || |
| data.tpm_properties.count == property_count) { |
| // There are more properties than we can fit. |
| *more_data = YES; |
| break; |
| } |
| data.tpm_properties.tpm_property[data.tpm_properties.count].property = |
| i; |
| data.tpm_properties.tpm_property[data.tpm_properties.count].value = |
| fake_tpm_properties_[i]; |
| data.tpm_properties.count++; |
| } |
| } |
| } else if (capability == TPM_CAP_ALGS) { |
| // Algorithm properties. |
| uint32_t stop = TPM_ALG_LAST + 1; |
| for (uint32_t i = property; i < stop; ++i) { |
| if (fake_algorithm_properties_.count(i) > 0) { |
| if (data.algorithms.count == kMaxProperties || |
| data.algorithms.count == property_count) { |
| // There are more properties than we can fit. |
| *more_data = YES; |
| break; |
| } |
| data.algorithms.alg_properties[data.algorithms.count].alg = i; |
| data.algorithms.alg_properties[data.algorithms.count].alg_properties = |
| fake_algorithm_properties_[i]; |
| data.algorithms.count++; |
| } |
| } |
| } |
| return TPM_RC_SUCCESS; |
| } |
| |
| TrunksFactoryForTest factory_; |
| NiceMock<MockTpm> mock_tpm_; |
| std::map<TPM_PT, uint32_t> fake_tpm_properties_; |
| std::map<TPM_ALG_ID, TPMA_ALGORITHM> fake_algorithm_properties_; |
| }; |
| |
| TEST(TpmState_DeathTest, NotInitialized) { |
| TrunksFactoryForTest factory; |
| TpmStateImpl tpm_state(factory); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.IsOwnerPasswordSet(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.IsEndorsementPasswordSet(), |
| "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.IsLockoutPasswordSet(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.IsOwned(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.IsInLockout(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.IsPlatformHierarchyEnabled(), |
| "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.IsStorageHierarchyEnabled(), |
| "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.IsEndorsementHierarchyEnabled(), |
| "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.IsEnabled(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.WasShutdownOrderly(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.IsRSASupported(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.IsECCSupported(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetLockoutCounter(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetLockoutThreshold(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetLockoutInterval(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetLockoutRecovery(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetMaxNVSize(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetTpmFamily(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetSpecificationLevel(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetSpecificationRevision(), |
| "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetManufacturer(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetTpmModel(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetFirmwareVersion(), "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetTpmProperty(0, nullptr), |
| "Check failed"); |
| EXPECT_DEATH_IF_SUPPORTED(tpm_state.GetAlgorithmProperties(0, nullptr), |
| "Check failed"); |
| } |
| |
| TEST_F(TpmStateTest, FlagsClear) { |
| fake_tpm_properties_[TPM_PT_PERMANENT] = 0; |
| fake_tpm_properties_[TPM_PT_STARTUP_CLEAR] = 0; |
| TpmStateImpl tpm_state(factory_); |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_FALSE(tpm_state.IsOwnerPasswordSet()); |
| EXPECT_FALSE(tpm_state.IsEndorsementPasswordSet()); |
| EXPECT_FALSE(tpm_state.IsLockoutPasswordSet()); |
| EXPECT_FALSE(tpm_state.IsInLockout()); |
| EXPECT_FALSE(tpm_state.IsOwned()); |
| EXPECT_FALSE(tpm_state.IsPlatformHierarchyEnabled()); |
| EXPECT_FALSE(tpm_state.IsStorageHierarchyEnabled()); |
| EXPECT_FALSE(tpm_state.IsEndorsementHierarchyEnabled()); |
| EXPECT_FALSE(tpm_state.WasShutdownOrderly()); |
| } |
| |
| TEST_F(TpmStateTest, FlagsSet) { |
| fake_tpm_properties_[TPM_PT_PERMANENT] = ~0; |
| fake_tpm_properties_[TPM_PT_STARTUP_CLEAR] = ~0; |
| |
| TpmStateImpl tpm_state(factory_); |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_TRUE(tpm_state.IsOwnerPasswordSet()); |
| EXPECT_TRUE(tpm_state.IsEndorsementPasswordSet()); |
| EXPECT_TRUE(tpm_state.IsLockoutPasswordSet()); |
| EXPECT_TRUE(tpm_state.IsOwned()); |
| EXPECT_TRUE(tpm_state.IsInLockout()); |
| EXPECT_TRUE(tpm_state.IsPlatformHierarchyEnabled()); |
| EXPECT_TRUE(tpm_state.IsStorageHierarchyEnabled()); |
| EXPECT_TRUE(tpm_state.IsEndorsementHierarchyEnabled()); |
| EXPECT_TRUE(tpm_state.WasShutdownOrderly()); |
| } |
| |
| TEST_F(TpmStateTest, EnabledTpm) { |
| TpmStateImpl tpm_state(factory_); |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_TRUE(tpm_state.IsEnabled()); |
| // All hierarchies enabled. |
| fake_tpm_properties_[TPM_PT_STARTUP_CLEAR] = 0x7; |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_FALSE(tpm_state.IsEnabled()); |
| // All hierarchies disabled. |
| fake_tpm_properties_[TPM_PT_STARTUP_CLEAR] = 0x0; |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_FALSE(tpm_state.IsEnabled()); |
| // Storage disabled. |
| fake_tpm_properties_[TPM_PT_STARTUP_CLEAR] = 0x5; |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_FALSE(tpm_state.IsEnabled()); |
| // Endorsement disabled. |
| fake_tpm_properties_[TPM_PT_STARTUP_CLEAR] = 0x3; |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_FALSE(tpm_state.IsEnabled()); |
| } |
| |
| TEST_F(TpmStateTest, OwnedTpm) { |
| TpmStateImpl tpm_state(factory_); |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_TRUE(tpm_state.IsOwned()); |
| // All auth missing. |
| fake_tpm_properties_[TPM_PT_PERMANENT] = 0x0; |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_FALSE(tpm_state.IsOwned()); |
| // Owner auth missing. |
| fake_tpm_properties_[TPM_PT_PERMANENT] = 0x6; |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_FALSE(tpm_state.IsOwned()); |
| // Endorsement auth missing. |
| fake_tpm_properties_[TPM_PT_PERMANENT] = 0x5; |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_FALSE(tpm_state.IsOwned()); |
| // Lockout auth missing. |
| fake_tpm_properties_[TPM_PT_PERMANENT] = 0x3; |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_FALSE(tpm_state.IsOwned()); |
| } |
| |
| TEST_F(TpmStateTest, AlgorithmSupport) { |
| TpmStateImpl tpm_state(factory_); |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_TRUE(tpm_state.IsRSASupported()); |
| EXPECT_TRUE(tpm_state.IsECCSupported()); |
| |
| fake_algorithm_properties_.clear(); |
| // Use a new instance because algorithm properties will not be queried again. |
| TpmStateImpl tpm_state2(factory_); |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state2.Initialize()); |
| EXPECT_FALSE(tpm_state2.IsRSASupported()); |
| EXPECT_FALSE(tpm_state2.IsECCSupported()); |
| } |
| |
| TEST_F(TpmStateTest, LockoutValuePassthrough) { |
| TpmStateImpl tpm_state(factory_); |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_EQ(tpm_state.GetLockoutCounter(), |
| fake_tpm_properties_[TPM_PT_LOCKOUT_COUNTER]); |
| EXPECT_EQ(tpm_state.GetLockoutThreshold(), |
| fake_tpm_properties_[TPM_PT_MAX_AUTH_FAIL]); |
| EXPECT_EQ(tpm_state.GetLockoutInterval(), |
| fake_tpm_properties_[TPM_PT_LOCKOUT_INTERVAL]); |
| EXPECT_EQ(tpm_state.GetLockoutRecovery(), |
| fake_tpm_properties_[TPM_PT_LOCKOUT_RECOVERY]); |
| |
| fake_tpm_properties_[TPM_PT_LOCKOUT_COUNTER]++; |
| fake_tpm_properties_[TPM_PT_MAX_AUTH_FAIL]++; |
| fake_tpm_properties_[TPM_PT_LOCKOUT_INTERVAL]++; |
| fake_tpm_properties_[TPM_PT_LOCKOUT_RECOVERY]++; |
| // Refresh and check for the new values. |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_EQ(tpm_state.GetLockoutCounter(), |
| fake_tpm_properties_[TPM_PT_LOCKOUT_COUNTER]); |
| EXPECT_EQ(tpm_state.GetLockoutThreshold(), |
| fake_tpm_properties_[TPM_PT_MAX_AUTH_FAIL]); |
| EXPECT_EQ(tpm_state.GetLockoutInterval(), |
| fake_tpm_properties_[TPM_PT_LOCKOUT_INTERVAL]); |
| EXPECT_EQ(tpm_state.GetLockoutRecovery(), |
| fake_tpm_properties_[TPM_PT_LOCKOUT_RECOVERY]); |
| } |
| |
| TEST_F(TpmStateTest, MaxNVSize) { |
| auto CheckMaxNVSize = [this]() { |
| TpmStateImpl tpm_state(factory_); |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| bool has_index = fake_tpm_properties_.count(TPM_PT_NV_INDEX_MAX) > 0; |
| bool has_buffer = fake_tpm_properties_.count(TPM_PT_NV_BUFFER_MAX) > 0; |
| if (has_index && has_buffer) { |
| EXPECT_EQ(tpm_state.GetMaxNVSize(), |
| std::min(fake_tpm_properties_[TPM_PT_NV_INDEX_MAX], |
| fake_tpm_properties_[TPM_PT_NV_BUFFER_MAX])); |
| } else if (has_index) { |
| EXPECT_EQ(tpm_state.GetMaxNVSize(), |
| fake_tpm_properties_[TPM_PT_NV_INDEX_MAX]); |
| } else if (has_buffer) { |
| EXPECT_EQ(tpm_state.GetMaxNVSize(), |
| fake_tpm_properties_[TPM_PT_NV_BUFFER_MAX]); |
| } else { |
| // Check for a reasonable default value. Brillo specs a minimum of 2048 so |
| // it shouldn't be less than that. |
| EXPECT_GE(tpm_state.GetMaxNVSize(), 2048u); |
| } |
| }; |
| // Check with the defaults (same index and buffer max). |
| CheckMaxNVSize(); |
| // Check with lower buffer max. |
| fake_tpm_properties_[TPM_PT_NV_INDEX_MAX] = 20; |
| fake_tpm_properties_[TPM_PT_NV_BUFFER_MAX] = 10; |
| CheckMaxNVSize(); |
| // Check with lower index max. |
| fake_tpm_properties_[TPM_PT_NV_INDEX_MAX] = 10; |
| fake_tpm_properties_[TPM_PT_NV_BUFFER_MAX] = 20; |
| CheckMaxNVSize(); |
| // Check without index property. |
| fake_tpm_properties_.erase(TPM_PT_NV_INDEX_MAX); |
| fake_tpm_properties_[TPM_PT_NV_BUFFER_MAX] = 5; |
| CheckMaxNVSize(); |
| // Check without buffer property. |
| fake_tpm_properties_[TPM_PT_NV_INDEX_MAX] = 5; |
| fake_tpm_properties_.erase(TPM_PT_NV_BUFFER_MAX); |
| CheckMaxNVSize(); |
| // Check without any properties. |
| fake_tpm_properties_.erase(TPM_PT_NV_INDEX_MAX); |
| fake_tpm_properties_.erase(TPM_PT_NV_BUFFER_MAX); |
| CheckMaxNVSize(); |
| } |
| |
| TEST_F(TpmStateTest, VersionNumbers) { |
| fake_tpm_properties_[TPM_PT_FAMILY_INDICATOR] = 0xfa; |
| fake_tpm_properties_[TPM_PT_LEVEL] = 1; |
| fake_tpm_properties_[TPM_PT_REVISION] = 101; |
| fake_tpm_properties_[TPM_PT_MANUFACTURER] = 0x90091; |
| fake_tpm_properties_[TPM_PT_VENDOR_TPM_TYPE] = 0x1234; |
| fake_tpm_properties_[TPM_PT_FIRMWARE_VERSION_1] = 0xf1; |
| fake_tpm_properties_[TPM_PT_FIRMWARE_VERSION_2] = 0xf2; |
| |
| TpmStateImpl tpm_state(factory_); |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| |
| EXPECT_EQ(0xfa, tpm_state.GetTpmFamily()); |
| EXPECT_EQ(1, tpm_state.GetSpecificationLevel()); |
| EXPECT_EQ(101, tpm_state.GetSpecificationRevision()); |
| EXPECT_EQ(0x90091, tpm_state.GetManufacturer()); |
| EXPECT_EQ(0x1234, tpm_state.GetTpmModel()); |
| EXPECT_EQ(0xf1000000f2, tpm_state.GetFirmwareVersion()); |
| EXPECT_EQ("", tpm_state.GetVendorIDString()); |
| } |
| |
| TEST_F(TpmStateTest, VendorIDString) { |
| fake_tpm_properties_[TPM_PT_VENDOR_STRING_1] = 0x66000000; |
| { |
| TpmStateImpl tpm_state(factory_); |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_EQ("f", tpm_state.GetVendorIDString()); |
| } |
| |
| fake_tpm_properties_[TPM_PT_VENDOR_STRING_1] = 0x66616b65; |
| { |
| TpmStateImpl tpm_state(factory_); |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_EQ("fake", tpm_state.GetVendorIDString()); |
| } |
| |
| fake_tpm_properties_[TPM_PT_VENDOR_STRING_2] = 0x666f6f00; |
| { |
| TpmStateImpl tpm_state(factory_); |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_EQ("fakefoo", tpm_state.GetVendorIDString()); |
| } |
| } |
| |
| TEST_F(TpmStateTest, RawTpmProperty) { |
| constexpr TPM_PT kProperty = 0x2FF; |
| TpmStateImpl tpm_state(factory_); |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_FALSE(tpm_state.GetTpmProperty(kProperty, nullptr)); |
| uint32_t value; |
| EXPECT_FALSE(tpm_state.GetTpmProperty(kProperty, &value)); |
| |
| fake_tpm_properties_[kProperty] = 1234; |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_TRUE(tpm_state.GetTpmProperty(kProperty, nullptr)); |
| EXPECT_TRUE(tpm_state.GetTpmProperty(kProperty, &value)); |
| EXPECT_EQ(value, fake_tpm_properties_[kProperty]); |
| } |
| |
| TEST_F(TpmStateTest, RawAlgorithmProperties) { |
| constexpr TPM_ALG_ID kAlgorithm = 0x39; |
| TpmStateImpl tpm_state(factory_); |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| EXPECT_FALSE(tpm_state.GetAlgorithmProperties(kAlgorithm, nullptr)); |
| uint32_t value; |
| EXPECT_FALSE(tpm_state.GetAlgorithmProperties(kAlgorithm, &value)); |
| |
| fake_algorithm_properties_[kAlgorithm] = 1234; |
| TpmStateImpl tpm_state2(factory_); |
| ASSERT_EQ(TPM_RC_SUCCESS, tpm_state2.Initialize()); |
| EXPECT_TRUE(tpm_state2.GetAlgorithmProperties(kAlgorithm, nullptr)); |
| EXPECT_TRUE(tpm_state2.GetAlgorithmProperties(kAlgorithm, &value)); |
| EXPECT_EQ(value, fake_algorithm_properties_[kAlgorithm]); |
| } |
| |
| TEST_F(TpmStateTest, InitFailOnMissingPermanentFlags) { |
| fake_tpm_properties_.erase(TPM_PT_PERMANENT); |
| TpmStateImpl tpm_state(factory_); |
| EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| } |
| |
| TEST_F(TpmStateTest, InitFailOnMissingStartupClearFlags) { |
| fake_tpm_properties_.erase(TPM_PT_STARTUP_CLEAR); |
| TpmStateImpl tpm_state(factory_); |
| EXPECT_NE(TPM_RC_SUCCESS, tpm_state.Initialize()); |
| } |
| |
| TEST_F(TpmStateTest, InitFailOnFailedTPMCommand) { |
| EXPECT_CALL(mock_tpm_, GetCapabilitySync(_, _, _, _, _, _)) |
| .WillRepeatedly(Return(TPM_RC_FAILURE)); |
| TpmStateImpl tpm_state(factory_); |
| EXPECT_EQ(TPM_RC_FAILURE, tpm_state.Initialize()); |
| } |
| |
| } // namespace trunks |