// // Copyright (C) 2015 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include <base/run_loop.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include "tpm_manager/server/mock_local_data_store.h" #include "tpm_manager/server/mock_tpm_initializer.h" #include "tpm_manager/server/mock_tpm_nvram.h" #include "tpm_manager/server/mock_tpm_status.h" #include "tpm_manager/server/tpm_manager_service.h" using testing::_; using testing::AtLeast; using testing::Invoke; using testing::NiceMock; using testing::Return; using testing::SaveArg; using testing::SetArgPointee; namespace { const char kOwnerPassword[] = "owner"; const char kOwnerDependency[] = "owner_dependency"; const char kOtherDependency[] = "other_dependency"; } namespace tpm_manager { // A test fixture that takes care of message loop management and configuring a // TpmManagerService instance with mock dependencies. class TpmManagerServiceTest : public testing::Test { public: ~TpmManagerServiceTest() override = default; void SetUp() override { service_.reset(new TpmManagerService(true /*wait_for_ownership*/, &mock_local_data_store_, &mock_tpm_status_, &mock_tpm_initializer_, &mock_tpm_nvram_)); SetupService(); } protected: void Run() { run_loop_.Run(); } void RunServiceWorkerAndQuit() { // Run out the service worker loop by posting a new command and waiting for // the response. auto callback = [this](const GetTpmStatusReply& reply) { Quit(); }; GetTpmStatusRequest request; service_->GetTpmStatus(request, base::Bind(callback)); Run(); } void Quit() { run_loop_.Quit(); } void SetupService() { CHECK(service_->Initialize()); } NiceMock<MockLocalDataStore> mock_local_data_store_; NiceMock<MockTpmInitializer> mock_tpm_initializer_; NiceMock<MockTpmNvram> mock_tpm_nvram_; NiceMock<MockTpmStatus> mock_tpm_status_; std::unique_ptr<TpmManagerService> service_; private: base::MessageLoop message_loop_; base::RunLoop run_loop_; }; // Tests must call SetupService(). class TpmManagerServiceTest_NoWaitForOwnership : public TpmManagerServiceTest { public: ~TpmManagerServiceTest_NoWaitForOwnership() override = default; void SetUp() override { service_.reset(new TpmManagerService(false /*wait_for_ownership*/, &mock_local_data_store_, &mock_tpm_status_, &mock_tpm_initializer_, &mock_tpm_nvram_)); } }; TEST_F(TpmManagerServiceTest_NoWaitForOwnership, AutoInitialize) { // Make sure InitializeTpm doesn't get multiple calls. EXPECT_CALL(mock_tpm_initializer_, InitializeTpm()).Times(1); SetupService(); RunServiceWorkerAndQuit(); } TEST_F(TpmManagerServiceTest_NoWaitForOwnership, AutoInitializeNoTpm) { EXPECT_CALL(mock_tpm_status_, IsTpmEnabled()).WillRepeatedly(Return(false)); EXPECT_CALL(mock_tpm_initializer_, InitializeTpm()).Times(0); SetupService(); RunServiceWorkerAndQuit(); } TEST_F(TpmManagerServiceTest_NoWaitForOwnership, AutoInitializeFailure) { EXPECT_CALL(mock_tpm_initializer_, InitializeTpm()) .WillRepeatedly(Return(false)); SetupService(); RunServiceWorkerAndQuit(); } TEST_F(TpmManagerServiceTest_NoWaitForOwnership, TakeOwnershipAfterAutoInitialize) { EXPECT_CALL(mock_tpm_initializer_, InitializeTpm()).Times(AtLeast(2)); SetupService(); auto callback = [this](const TakeOwnershipReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); Quit(); }; TakeOwnershipRequest request; service_->TakeOwnership(request, base::Bind(callback)); Run(); } TEST_F(TpmManagerServiceTest, NoAutoInitialize) { EXPECT_CALL(mock_tpm_initializer_, InitializeTpm()).Times(0); RunServiceWorkerAndQuit(); } TEST_F(TpmManagerServiceTest, GetTpmStatusSuccess) { EXPECT_CALL(mock_tpm_status_, GetDictionaryAttackInfo(_, _, _, _)) .WillRepeatedly(Invoke([](int* counter, int* threshold, bool* lockout, int* seconds_remaining) { *counter = 5; *threshold = 6; *lockout = true; *seconds_remaining = 7; return true; })); LocalData local_data; local_data.set_owner_password(kOwnerPassword); EXPECT_CALL(mock_local_data_store_, Read(_)) .WillRepeatedly(DoAll(SetArgPointee<0>(local_data), Return(true))); auto callback = [this](const GetTpmStatusReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); EXPECT_TRUE(reply.enabled()); EXPECT_TRUE(reply.owned()); EXPECT_EQ(kOwnerPassword, reply.local_data().owner_password()); EXPECT_EQ(5, reply.dictionary_attack_counter()); EXPECT_EQ(6, reply.dictionary_attack_threshold()); EXPECT_TRUE(reply.dictionary_attack_lockout_in_effect()); EXPECT_EQ(7, reply.dictionary_attack_lockout_seconds_remaining()); Quit(); }; GetTpmStatusRequest request; service_->GetTpmStatus(request, base::Bind(callback)); Run(); } TEST_F(TpmManagerServiceTest, GetTpmStatusLocalDataFailure) { EXPECT_CALL(mock_local_data_store_, Read(_)) .WillRepeatedly(Return(false)); auto callback = [this](const GetTpmStatusReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); EXPECT_TRUE(reply.enabled()); EXPECT_TRUE(reply.owned()); EXPECT_FALSE(reply.has_local_data()); EXPECT_TRUE(reply.has_dictionary_attack_counter()); EXPECT_TRUE(reply.has_dictionary_attack_threshold()); EXPECT_TRUE(reply.has_dictionary_attack_lockout_in_effect()); EXPECT_TRUE(reply.has_dictionary_attack_lockout_seconds_remaining()); Quit(); }; GetTpmStatusRequest request; service_->GetTpmStatus(request, base::Bind(callback)); Run(); } TEST_F(TpmManagerServiceTest, GetTpmStatusNoTpm) { EXPECT_CALL(mock_tpm_status_, IsTpmEnabled()).WillRepeatedly(Return(false)); EXPECT_CALL(mock_tpm_status_, GetDictionaryAttackInfo(_, _, _, _)) .WillRepeatedly(Return(false)); auto callback = [this](const GetTpmStatusReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); EXPECT_FALSE(reply.enabled()); EXPECT_TRUE(reply.owned()); EXPECT_TRUE(reply.has_local_data()); EXPECT_FALSE(reply.has_dictionary_attack_counter()); EXPECT_FALSE(reply.has_dictionary_attack_threshold()); EXPECT_FALSE(reply.has_dictionary_attack_lockout_in_effect()); EXPECT_FALSE(reply.has_dictionary_attack_lockout_seconds_remaining()); Quit(); }; GetTpmStatusRequest request; service_->GetTpmStatus(request, base::Bind(callback)); Run(); } TEST_F(TpmManagerServiceTest, TakeOwnershipSuccess) { // Make sure InitializeTpm doesn't get multiple calls. EXPECT_CALL(mock_tpm_initializer_, InitializeTpm()).Times(1); auto callback = [this](const TakeOwnershipReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); Quit(); }; TakeOwnershipRequest request; service_->TakeOwnership(request, base::Bind(callback)); Run(); } TEST_F(TpmManagerServiceTest, TakeOwnershipFailure) { EXPECT_CALL(mock_tpm_initializer_, InitializeTpm()) .WillRepeatedly(Return(false)); auto callback = [this](const TakeOwnershipReply& reply) { EXPECT_EQ(STATUS_UNEXPECTED_DEVICE_ERROR, reply.status()); Quit(); }; TakeOwnershipRequest request; service_->TakeOwnership(request, base::Bind(callback)); Run(); } TEST_F(TpmManagerServiceTest, TakeOwnershipNoTpm) { EXPECT_CALL(mock_tpm_status_, IsTpmEnabled()).WillRepeatedly(Return(false)); auto callback = [this](const TakeOwnershipReply& reply) { EXPECT_EQ(STATUS_NOT_AVAILABLE, reply.status()); Quit(); }; TakeOwnershipRequest request; service_->TakeOwnership(request, base::Bind(callback)); Run(); } TEST_F(TpmManagerServiceTest, RemoveOwnerDependencyReadFailure) { EXPECT_CALL(mock_local_data_store_, Read(_)) .WillRepeatedly(Return(false)); auto callback = [this](const RemoveOwnerDependencyReply& reply) { EXPECT_EQ(STATUS_UNEXPECTED_DEVICE_ERROR, reply.status()); Quit(); }; RemoveOwnerDependencyRequest request; request.set_owner_dependency(kOwnerDependency); service_->RemoveOwnerDependency(request, base::Bind(callback)); Run(); } TEST_F(TpmManagerServiceTest, RemoveOwnerDependencyWriteFailure) { EXPECT_CALL(mock_local_data_store_, Write(_)) .WillRepeatedly(Return(false)); auto callback = [this](const RemoveOwnerDependencyReply& reply) { EXPECT_EQ(STATUS_UNEXPECTED_DEVICE_ERROR, reply.status()); Quit(); }; RemoveOwnerDependencyRequest request; request.set_owner_dependency(kOwnerDependency); service_->RemoveOwnerDependency(request, base::Bind(callback)); Run(); } TEST_F(TpmManagerServiceTest, RemoveOwnerDependencyNotCleared) { LocalData local_data; local_data.set_owner_password(kOwnerPassword); local_data.add_owner_dependency(kOwnerDependency); local_data.add_owner_dependency(kOtherDependency); EXPECT_CALL(mock_local_data_store_, Read(_)) .WillOnce(DoAll(SetArgPointee<0>(local_data), Return(true))); EXPECT_CALL(mock_local_data_store_, Write(_)) .WillOnce(DoAll(SaveArg<0>(&local_data), Return(true))); auto callback = [this, &local_data](const RemoveOwnerDependencyReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); EXPECT_EQ(1, local_data.owner_dependency_size()); EXPECT_EQ(kOtherDependency, local_data.owner_dependency(0)); EXPECT_TRUE(local_data.has_owner_password()); EXPECT_EQ(kOwnerPassword, local_data.owner_password()); Quit(); }; RemoveOwnerDependencyRequest request; request.set_owner_dependency(kOwnerDependency); service_->RemoveOwnerDependency(request, base::Bind(callback)); Run(); } TEST_F(TpmManagerServiceTest, RemoveOwnerDependencyCleared) { LocalData local_data; local_data.set_owner_password(kOwnerPassword); local_data.add_owner_dependency(kOwnerDependency); EXPECT_CALL(mock_local_data_store_, Read(_)) .WillOnce(DoAll(SetArgPointee<0>(local_data), Return(true))); EXPECT_CALL(mock_local_data_store_, Write(_)) .WillOnce(DoAll(SaveArg<0>(&local_data), Return(true))); auto callback = [this, &local_data](const RemoveOwnerDependencyReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); EXPECT_EQ(0, local_data.owner_dependency_size()); EXPECT_FALSE(local_data.has_owner_password()); Quit(); }; RemoveOwnerDependencyRequest request; request.set_owner_dependency(kOwnerDependency); service_->RemoveOwnerDependency(request, base::Bind(callback)); Run(); } TEST_F(TpmManagerServiceTest, RemoveOwnerDependencyNotPresent) { LocalData local_data; local_data.set_owner_password(kOwnerPassword); local_data.add_owner_dependency(kOwnerDependency); EXPECT_CALL(mock_local_data_store_, Read(_)) .WillOnce(DoAll(SetArgPointee<0>(local_data), Return(true))); EXPECT_CALL(mock_local_data_store_, Write(_)) .WillOnce(DoAll(SaveArg<0>(&local_data), Return(true))); auto callback = [this, &local_data](const RemoveOwnerDependencyReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); EXPECT_EQ(1, local_data.owner_dependency_size()); EXPECT_EQ(kOwnerDependency, local_data.owner_dependency(0)); EXPECT_TRUE(local_data.has_owner_password()); EXPECT_EQ(kOwnerPassword, local_data.owner_password()); Quit(); }; RemoveOwnerDependencyRequest request; request.set_owner_dependency(kOtherDependency); service_->RemoveOwnerDependency(request, base::Bind(callback)); Run(); } TEST_F(TpmManagerServiceTest, DefineNvramFailure) { uint32_t nvram_index = 5; size_t nvram_length = 32; EXPECT_CALL(mock_tpm_nvram_, DefineNvram(nvram_index, nvram_length)) .WillRepeatedly(Return(false)); auto callback = [this](const DefineNvramReply& reply) { EXPECT_EQ(STATUS_UNEXPECTED_DEVICE_ERROR, reply.status()); Quit(); }; DefineNvramRequest request; request.set_index(nvram_index); request.set_length(nvram_length); service_->DefineNvram(request, base::Bind(callback)); Run(); } TEST_F(TpmManagerServiceTest, DefineNvramSuccess) { uint32_t nvram_index = 5; uint32_t nvram_length = 32; auto define_callback = [this](const DefineNvramReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); }; auto is_defined_callback = [this](const IsNvramDefinedReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); EXPECT_EQ(true, reply.is_defined()); }; auto size_callback = [this, nvram_length](const GetNvramSizeReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); EXPECT_EQ(nvram_length, reply.size()); }; DefineNvramRequest define_request; define_request.set_index(nvram_index); define_request.set_length(nvram_length); service_->DefineNvram(define_request, base::Bind(define_callback)); IsNvramDefinedRequest is_defined_request; is_defined_request.set_index(nvram_index); service_->IsNvramDefined(is_defined_request, base::Bind(is_defined_callback)); GetNvramSizeRequest size_request; size_request.set_index(nvram_index); service_->GetNvramSize(size_request, base::Bind(size_callback)); RunServiceWorkerAndQuit(); } TEST_F(TpmManagerServiceTest, DestroyUnitializedNvram) { auto callback = [this](const DestroyNvramReply& reply) { EXPECT_EQ(STATUS_UNEXPECTED_DEVICE_ERROR, reply.status()); Quit(); }; DestroyNvramRequest request; service_->DestroyNvram(request, base::Bind(callback)); Run(); } TEST_F(TpmManagerServiceTest, DestroyNvramSuccess) { uint32_t nvram_index = 5; uint32_t nvram_length = 32; auto define_callback = [this](const DefineNvramReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); }; auto destroy_callback = [this](const DestroyNvramReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); }; DefineNvramRequest define_request; define_request.set_index(nvram_index); define_request.set_length(nvram_length); service_->DefineNvram(define_request, base::Bind(define_callback)); DestroyNvramRequest destroy_request; destroy_request.set_index(nvram_index); service_->DestroyNvram(destroy_request, base::Bind(destroy_callback)); RunServiceWorkerAndQuit(); } TEST_F(TpmManagerServiceTest, DoubleDestroyNvram) { uint32_t nvram_index = 5; uint32_t nvram_length = 32; auto define_callback = [this](const DefineNvramReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); }; auto destroy_callback_success = [this](const DestroyNvramReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); }; auto destroy_callback_failure = [this](const DestroyNvramReply& reply) { EXPECT_EQ(STATUS_UNEXPECTED_DEVICE_ERROR, reply.status()); }; DefineNvramRequest define_request; define_request.set_index(nvram_index); define_request.set_length(nvram_length); service_->DefineNvram(define_request, base::Bind(define_callback)); DestroyNvramRequest destroy_request; destroy_request.set_index(nvram_index); service_->DestroyNvram(destroy_request, base::Bind(destroy_callback_success)); service_->DestroyNvram(destroy_request, base::Bind(destroy_callback_failure)); RunServiceWorkerAndQuit(); } TEST_F(TpmManagerServiceTest, WriteUninitializedNvram) { auto callback = [this](const WriteNvramReply& reply) { EXPECT_EQ(STATUS_UNEXPECTED_DEVICE_ERROR, reply.status()); Quit(); }; WriteNvramRequest request; service_->WriteNvram(request, base::Bind(callback)); Run(); } TEST_F(TpmManagerServiceTest, WriteNvramIncorrectSize) { uint32_t nvram_index = 5; std::string nvram_data("nvram_data"); auto define_callback = [this](const DefineNvramReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); }; auto write_callback = [this](const WriteNvramReply& reply) { EXPECT_EQ(STATUS_UNEXPECTED_DEVICE_ERROR, reply.status()); }; DefineNvramRequest define_request; define_request.set_index(nvram_index); define_request.set_length(nvram_data.size() - 1); service_->DefineNvram(define_request, base::Bind(define_callback)); WriteNvramRequest write_request; write_request.set_index(nvram_index); write_request.set_data(nvram_data); service_->WriteNvram(write_request, base::Bind(write_callback)); RunServiceWorkerAndQuit(); } TEST_F(TpmManagerServiceTest, DoubleWrite) { uint32_t nvram_index = 5; std::string nvram_data("nvram_data"); auto define_callback = [this](const DefineNvramReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); }; auto write_callback_success = [this](const WriteNvramReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); }; auto write_callback_failure = [this](const WriteNvramReply& reply) { EXPECT_EQ(STATUS_UNEXPECTED_DEVICE_ERROR, reply.status()); }; DefineNvramRequest define_request; define_request.set_index(nvram_index); define_request.set_length(nvram_data.size()); service_->DefineNvram(define_request, base::Bind(define_callback)); WriteNvramRequest write_request; write_request.set_index(nvram_index); write_request.set_data(nvram_data); service_->WriteNvram(write_request, base::Bind(write_callback_success)); service_->WriteNvram(write_request, base::Bind(write_callback_failure)); RunServiceWorkerAndQuit(); } TEST_F(TpmManagerServiceTest, ReadUninitializedNvram) { auto callback = [this](const ReadNvramReply& reply) { EXPECT_EQ(STATUS_UNEXPECTED_DEVICE_ERROR, reply.status()); Quit(); }; ReadNvramRequest request; service_->ReadNvram(request, base::Bind(callback)); Run(); } TEST_F(TpmManagerServiceTest, ReadUnwrittenNvram) { uint32_t nvram_index = 5; uint32_t nvram_length = 32; auto define_callback = [this](const DefineNvramReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); }; auto read_callback = [this](const ReadNvramReply& reply) { EXPECT_EQ(STATUS_UNEXPECTED_DEVICE_ERROR, reply.status()); }; DefineNvramRequest define_request; define_request.set_index(nvram_index); define_request.set_length(nvram_length); service_->DefineNvram(define_request, base::Bind(define_callback)); ReadNvramRequest read_request; read_request.set_index(nvram_index); service_->ReadNvram(read_request, base::Bind(read_callback)); RunServiceWorkerAndQuit(); } TEST_F(TpmManagerServiceTest, ReadWriteNvramSuccess) { uint32_t nvram_index = 5; std::string nvram_data("nvram_data"); auto define_callback = [this](const DefineNvramReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); }; auto write_callback = [this](const WriteNvramReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); }; auto read_callback = [this, nvram_data](const ReadNvramReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); EXPECT_EQ(nvram_data, reply.data()); }; auto locked_callback = [this](const IsNvramLockedReply& reply) { EXPECT_EQ(STATUS_SUCCESS, reply.status()); EXPECT_EQ(true, reply.is_locked()); }; DefineNvramRequest define_request; define_request.set_index(nvram_index); define_request.set_length(nvram_data.size()); service_->DefineNvram(define_request, base::Bind(define_callback)); WriteNvramRequest write_request; write_request.set_index(nvram_index); write_request.set_data(nvram_data); service_->WriteNvram(write_request, base::Bind(write_callback)); ReadNvramRequest read_request; read_request.set_index(nvram_index); service_->ReadNvram(read_request, base::Bind(read_callback)); IsNvramLockedRequest locked_request; locked_request.set_index(nvram_index); service_->IsNvramLocked(locked_request, base::Bind(locked_callback)); RunServiceWorkerAndQuit(); } } // namespace tpm_manager