| // Copyright 2019 The Chromium 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 "chrome/browser/ash/attestation/tpm_challenge_key.h" |
| |
| #include "base/bind.h" |
| #include "base/run_loop.h" |
| #include "base/test/gmock_callback_support.h" |
| #include "chrome/browser/ash/attestation/mock_tpm_challenge_key_subtle.h" |
| #include "chrome/browser/ash/attestation/tpm_challenge_key_result.h" |
| #include "chrome/browser/ash/attestation/tpm_challenge_key_subtle.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using base::test::RunOnceCallback; |
| using testing::_; |
| using testing::StrictMock; |
| |
| class Profile; |
| |
| namespace ash { |
| namespace attestation { |
| namespace { |
| |
| constexpr char kEmptyKeyName[] = ""; |
| constexpr char kNonDefaultKeyName[] = "key_name_123"; |
| |
| std::string GetChallenge() { |
| constexpr uint8_t kBuffer[] = {0x0, 0x1, 0x2, 'c', 'h', |
| 'a', 'l', 0xfd, 0xfe, 0xff}; |
| return std::string(reinterpret_cast<const char*>(kBuffer), sizeof(kBuffer)); |
| } |
| |
| std::string GetChallengeResponse() { |
| constexpr uint8_t kBuffer[] = {0x0, 0x1, 0x2, 'r', 'e', |
| 's', 'p', 0xfd, 0xfe, 0xff}; |
| return std::string(reinterpret_cast<const char*>(kBuffer), sizeof(kBuffer)); |
| } |
| |
| std::string GetPublicKey() { |
| constexpr uint8_t kBuffer[] = {0x0, 0x1, 0x2, 'p', 'u', |
| 'b', 'k', 0xfd, 0xfe, 0xff}; |
| return std::string(reinterpret_cast<const char*>(kBuffer), sizeof(kBuffer)); |
| } |
| |
| class TpmChallengeKeyTest : public ::testing::Test { |
| public: |
| TpmChallengeKeyTest() { |
| auto mock_challenge_key_subtle = |
| std::make_unique<StrictMock<MockTpmChallengeKeySubtle>>(); |
| mock_tpm_challenge_key_subtle_ = mock_challenge_key_subtle.get(); |
| TpmChallengeKeySubtleFactory::SetForTesting( |
| std::move(mock_challenge_key_subtle)); |
| |
| challenge_key_ = TpmChallengeKeyFactory::Create(); |
| } |
| |
| protected: |
| content::BrowserTaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; |
| |
| MockTpmChallengeKeySubtle* mock_tpm_challenge_key_subtle_ = nullptr; |
| std::unique_ptr<TpmChallengeKey> challenge_key_; |
| // In the current implementation of TpmChallengeKey the profile is just |
| // forwarded, so actual value does not matter. |
| TestingProfile profile_; |
| }; |
| |
| class CallbackObserver { |
| public: |
| TpmChallengeKeyCallback GetCallback() { |
| return base::BindOnce(&CallbackObserver::Callback, base::Unretained(this)); |
| } |
| |
| const TpmChallengeKeyResult& GetResult() const { |
| CHECK(result_.has_value()) << "Callback was never called"; |
| return result_.value(); |
| } |
| |
| void WaitForCallback() { loop_.Run(); } |
| |
| private: |
| void Callback(const TpmChallengeKeyResult& result) { |
| CHECK(!result_.has_value()) << "Callback was called more than once"; |
| result_ = result; |
| loop_.Quit(); |
| } |
| |
| base::RunLoop loop_; |
| absl::optional<TpmChallengeKeyResult> result_; |
| }; |
| |
| TEST_F(TpmChallengeKeyTest, PrepareKeyFailed) { |
| const AttestationKeyType kKeyType = KEY_DEVICE; |
| const bool kRegisterKey = false; |
| const char* const kKeyName = kEmptyKeyName; |
| |
| EXPECT_CALL(*mock_tpm_challenge_key_subtle_, |
| StartPrepareKeyStep(kKeyType, kRegisterKey, kKeyName, &profile_, |
| /*callback=*/_)) |
| .WillOnce(RunOnceCallback<4>(TpmChallengeKeyResult::MakeError( |
| TpmChallengeKeyResultCode::kGetCertificateFailedError))); |
| |
| CallbackObserver callback_observer; |
| challenge_key_->BuildResponse(kKeyType, &profile_, |
| callback_observer.GetCallback(), GetChallenge(), |
| kRegisterKey, kKeyName); |
| callback_observer.WaitForCallback(); |
| |
| EXPECT_EQ(callback_observer.GetResult(), |
| TpmChallengeKeyResult::MakeError( |
| TpmChallengeKeyResultCode::kGetCertificateFailedError)); |
| } |
| |
| TEST_F(TpmChallengeKeyTest, SignChallengeFailed) { |
| const AttestationKeyType kKeyType = KEY_USER; |
| const bool kRegisterKey = true; |
| const char* const kKeyName = kNonDefaultKeyName; |
| |
| EXPECT_CALL(*mock_tpm_challenge_key_subtle_, |
| StartPrepareKeyStep(kKeyType, kRegisterKey, kKeyName, &profile_, |
| /*callback=*/_)) |
| .WillOnce(RunOnceCallback<4>( |
| TpmChallengeKeyResult::MakePublicKey(GetPublicKey()))); |
| |
| EXPECT_CALL(*mock_tpm_challenge_key_subtle_, |
| StartSignChallengeStep(GetChallenge(), /*callback=*/_)) |
| .WillOnce(RunOnceCallback<1>(TpmChallengeKeyResult::MakeError( |
| TpmChallengeKeyResultCode::kSignChallengeFailedError))); |
| |
| CallbackObserver callback_observer; |
| challenge_key_->BuildResponse(kKeyType, &profile_, |
| callback_observer.GetCallback(), GetChallenge(), |
| kRegisterKey, kKeyName); |
| callback_observer.WaitForCallback(); |
| |
| EXPECT_EQ(callback_observer.GetResult(), |
| TpmChallengeKeyResult::MakeError( |
| TpmChallengeKeyResultCode::kSignChallengeFailedError)); |
| } |
| |
| TEST_F(TpmChallengeKeyTest, RegisterKeyFailed) { |
| const AttestationKeyType kKeyType = KEY_USER; |
| const bool kRegisterKey = true; |
| const char* const kKeyName = kNonDefaultKeyName; |
| |
| EXPECT_CALL(*mock_tpm_challenge_key_subtle_, |
| StartPrepareKeyStep(kKeyType, kRegisterKey, kKeyName, &profile_, |
| /*callback=*/_)) |
| .WillOnce(RunOnceCallback<4>( |
| TpmChallengeKeyResult::MakePublicKey(GetPublicKey()))); |
| |
| EXPECT_CALL(*mock_tpm_challenge_key_subtle_, |
| StartSignChallengeStep(GetChallenge(), /*callback=*/_)) |
| .WillOnce(RunOnceCallback<1>(TpmChallengeKeyResult::MakeChallengeResponse( |
| GetChallengeResponse()))); |
| |
| EXPECT_CALL(*mock_tpm_challenge_key_subtle_, |
| StartRegisterKeyStep(/*callback=*/_)) |
| .WillOnce(RunOnceCallback<0>(TpmChallengeKeyResult::MakeError( |
| TpmChallengeKeyResultCode::kKeyRegistrationFailedError))); |
| |
| CallbackObserver callback_observer; |
| challenge_key_->BuildResponse(kKeyType, &profile_, |
| callback_observer.GetCallback(), GetChallenge(), |
| kRegisterKey, kKeyName); |
| callback_observer.WaitForCallback(); |
| |
| EXPECT_EQ(callback_observer.GetResult(), |
| TpmChallengeKeyResult::MakeError( |
| TpmChallengeKeyResultCode::kKeyRegistrationFailedError)); |
| } |
| |
| TEST_F(TpmChallengeKeyTest, DontRegisterSuccess) { |
| const AttestationKeyType kKeyType = KEY_USER; |
| const bool kRegisterKey = false; |
| const char* const kKeyName = kEmptyKeyName; |
| |
| EXPECT_CALL(*mock_tpm_challenge_key_subtle_, |
| StartPrepareKeyStep(kKeyType, kRegisterKey, kKeyName, &profile_, |
| /*callback=*/_)) |
| .WillOnce(RunOnceCallback<4>( |
| TpmChallengeKeyResult::MakePublicKey(GetPublicKey()))); |
| |
| EXPECT_CALL(*mock_tpm_challenge_key_subtle_, |
| StartSignChallengeStep(GetChallenge(), /*callback=*/_)) |
| .WillOnce(RunOnceCallback<1>(TpmChallengeKeyResult::MakeChallengeResponse( |
| GetChallengeResponse()))); |
| |
| EXPECT_CALL(*mock_tpm_challenge_key_subtle_, |
| StartRegisterKeyStep(/*callback=*/_)) |
| .Times(0); |
| |
| CallbackObserver callback_observer; |
| challenge_key_->BuildResponse(kKeyType, &profile_, |
| callback_observer.GetCallback(), GetChallenge(), |
| kRegisterKey, kKeyName); |
| callback_observer.WaitForCallback(); |
| |
| EXPECT_EQ( |
| callback_observer.GetResult(), |
| TpmChallengeKeyResult::MakeChallengeResponse(GetChallengeResponse())); |
| } |
| |
| TEST_F(TpmChallengeKeyTest, RegisterSuccess) { |
| const AttestationKeyType kKeyType = KEY_USER; |
| const bool kRegisterKey = true; |
| const char* const kKeyName = kEmptyKeyName; |
| |
| EXPECT_CALL(*mock_tpm_challenge_key_subtle_, |
| StartPrepareKeyStep(kKeyType, kRegisterKey, kKeyName, &profile_, |
| /*callback=*/_)) |
| .WillOnce(RunOnceCallback<4>( |
| TpmChallengeKeyResult::MakePublicKey(GetPublicKey()))); |
| |
| EXPECT_CALL(*mock_tpm_challenge_key_subtle_, |
| StartSignChallengeStep(GetChallenge(), /*callback=*/_)) |
| .WillOnce(RunOnceCallback<1>(TpmChallengeKeyResult::MakeChallengeResponse( |
| GetChallengeResponse()))); |
| |
| EXPECT_CALL(*mock_tpm_challenge_key_subtle_, |
| StartRegisterKeyStep(/*callback=*/_)) |
| .WillOnce(RunOnceCallback<0>(TpmChallengeKeyResult::MakeSuccess())); |
| |
| CallbackObserver callback_observer; |
| challenge_key_->BuildResponse(kKeyType, &profile_, |
| callback_observer.GetCallback(), GetChallenge(), |
| kRegisterKey, kKeyName); |
| callback_observer.WaitForCallback(); |
| |
| EXPECT_EQ( |
| callback_observer.GetResult(), |
| TpmChallengeKeyResult::MakeChallengeResponse(GetChallengeResponse())); |
| } |
| |
| } // namespace |
| } // namespace attestation |
| } // namespace ash |