Commit d4e889aa authored by Maksim Ivanov's avatar Maksim Ivanov Committed by Commit Bot

Test for system cert token loading after TPM ready

Add a browser test for the logic that triggers the system slot
initialization whenever the TPM goes into the "ready" state as
notified by cryptohomed (added in r698007).

The test exercises the following codepath (this description
skips some intermediate callers for the sake of brevity):
1. SystemTokenCertDBInitializer is notified by the
   chromeos::[Fake]CryptohomeClient that TpmInitStatusUpdated
   with |ready|==true;
2. chromeos::TPMTokenLoader::EnsureStarted() gets called;
3. crypto::InitializeTPMTokenAndSystemSlot() gets called.

This is verified by the test by opening a web page in the
Chrome OS Login screen that uses client cert authentication.
If the codepath mentioned above wouldn't work, the test would
fail due to ClientCertFilterChromeOS waiting infinitely for
the result from crypto::GetSystemNSSKeySlot().

Bug: 725500
Change-Id: I17e0fa42d3fda7d0deed5f86a2ab99b079865b36
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1815857
Commit-Queue: Maksim Ivanov <emaxx@chromium.org>
Reviewed-by: default avatarMatt Mueller <mattm@chromium.org>
Reviewed-by: default avatarDavid Benjamin <davidben@chromium.org>
Reviewed-by: default avatarPavol Marko <pmarko@chromium.org>
Reviewed-by: default avatarAchuith Bhandarkar <achuith@chromium.org>
Cr-Commit-Position: refs/heads/master@{#705243}
parent f9ec939b
...@@ -175,7 +175,7 @@ void FakeCryptohomeClient::GetRsuDeviceId( ...@@ -175,7 +175,7 @@ void FakeCryptohomeClient::GetRsuDeviceId(
void FakeCryptohomeClient::TpmIsReady(DBusMethodCallback<bool> callback) { void FakeCryptohomeClient::TpmIsReady(DBusMethodCallback<bool> callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask( base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), true)); FROM_HERE, base::BindOnce(std::move(callback), tpm_is_ready_));
} }
void FakeCryptohomeClient::TpmIsEnabled(DBusMethodCallback<bool> callback) { void FakeCryptohomeClient::TpmIsEnabled(DBusMethodCallback<bool> callback) {
...@@ -900,6 +900,14 @@ void FakeCryptohomeClient::NotifyAsyncCallStatusWithData( ...@@ -900,6 +900,14 @@ void FakeCryptohomeClient::NotifyAsyncCallStatusWithData(
observer.AsyncCallStatusWithData(async_id, return_status, data); observer.AsyncCallStatusWithData(async_id, return_status, data);
} }
void FakeCryptohomeClient::NotifyTpmInitStatusUpdated(
bool ready,
bool owned,
bool was_owned_this_boot) {
for (auto& observer : observer_list_)
observer.TpmInitStatusUpdated(ready, owned, was_owned_this_boot);
}
void FakeCryptohomeClient::NotifyDircryptoMigrationProgress( void FakeCryptohomeClient::NotifyDircryptoMigrationProgress(
cryptohome::DircryptoMigrationStatus status, cryptohome::DircryptoMigrationStatus status,
uint64_t current, uint64_t current,
......
...@@ -255,6 +255,9 @@ class COMPONENT_EXPORT(CRYPTOHOME_CLIENT) FakeCryptohomeClient ...@@ -255,6 +255,9 @@ class COMPONENT_EXPORT(CRYPTOHOME_CLIENT) FakeCryptohomeClient
// unavailable. Expects service not to be available when called. // unavailable. Expects service not to be available when called.
void ReportServiceIsNotAvailable(); void ReportServiceIsNotAvailable();
// Changes the behavior of TpmIsReady().
void set_tpm_is_ready(bool value) { tpm_is_ready_ = value; }
// Changes the behavior of TpmIsEnabled(). // Changes the behavior of TpmIsEnabled().
void set_tpm_is_enabled(bool value) { tpm_is_enabled_ = value; } void set_tpm_is_enabled(bool value) { tpm_is_enabled_ = value; }
...@@ -344,6 +347,11 @@ class COMPONENT_EXPORT(CRYPTOHOME_CLIENT) FakeCryptohomeClient ...@@ -344,6 +347,11 @@ class COMPONENT_EXPORT(CRYPTOHOME_CLIENT) FakeCryptohomeClient
void SetTpmAttestationDeviceKeyPayload(const std::string& key_name, void SetTpmAttestationDeviceKeyPayload(const std::string& key_name,
const std::string& payload); const std::string& payload);
// Calls TpmInitStatusUpdated() on Observer instances.
void NotifyTpmInitStatusUpdated(bool ready,
bool owned,
bool was_owned_this_boot);
// Calls DircryptoMigrationProgress() on Observer instances. // Calls DircryptoMigrationProgress() on Observer instances.
void NotifyDircryptoMigrationProgress( void NotifyDircryptoMigrationProgress(
cryptohome::DircryptoMigrationStatus status, cryptohome::DircryptoMigrationStatus status,
...@@ -476,6 +484,7 @@ class COMPONENT_EXPORT(CRYPTOHOME_CLIENT) FakeCryptohomeClient ...@@ -476,6 +484,7 @@ class COMPONENT_EXPORT(CRYPTOHOME_CLIENT) FakeCryptohomeClient
bool supports_low_entropy_credentials_ = false; bool supports_low_entropy_credentials_ = false;
// Controls if CheckKeyEx actually checks the key. // Controls if CheckKeyEx actually checks the key.
bool enable_auth_check_ = false; bool enable_auth_check_ = false;
bool tpm_is_ready_ = true;
bool tpm_is_enabled_ = true; bool tpm_is_enabled_ = true;
// Reply to GetRsuDeviceId(). // Reply to GetRsuDeviceId().
......
...@@ -33,13 +33,13 @@ static TPMTokenLoader* g_tpm_token_loader = NULL; ...@@ -33,13 +33,13 @@ static TPMTokenLoader* g_tpm_token_loader = NULL;
// static // static
void TPMTokenLoader::Initialize() { void TPMTokenLoader::Initialize() {
CHECK(!g_tpm_token_loader); CHECK(!g_tpm_token_loader);
g_tpm_token_loader = new TPMTokenLoader(false /*for_test*/); g_tpm_token_loader = new TPMTokenLoader(/*initialized_for_test=*/false);
} }
// static // static
void TPMTokenLoader::InitializeForTest() { void TPMTokenLoader::InitializeForTest() {
CHECK(!g_tpm_token_loader); CHECK(!g_tpm_token_loader);
g_tpm_token_loader = new TPMTokenLoader(true /*for_test*/); g_tpm_token_loader = new TPMTokenLoader(/*initialized_for_test=*/true);
} }
// static // static
...@@ -61,8 +61,8 @@ bool TPMTokenLoader::IsInitialized() { ...@@ -61,8 +61,8 @@ bool TPMTokenLoader::IsInitialized() {
return g_tpm_token_loader; return g_tpm_token_loader;
} }
TPMTokenLoader::TPMTokenLoader(bool for_test) TPMTokenLoader::TPMTokenLoader(bool initialized_for_test)
: initialized_for_test_(for_test), : initialized_for_test_(initialized_for_test),
tpm_token_state_(TPM_STATE_UNKNOWN), tpm_token_state_(TPM_STATE_UNKNOWN),
tpm_token_info_getter_(TPMTokenInfoGetter::CreateForSystemToken( tpm_token_info_getter_(TPMTokenInfoGetter::CreateForSystemToken(
CryptohomeClient::Get(), CryptohomeClient::Get(),
...@@ -112,8 +112,9 @@ bool TPMTokenLoader::IsTPMLoadingEnabled() const { ...@@ -112,8 +112,9 @@ bool TPMTokenLoader::IsTPMLoadingEnabled() const {
// TPM loading is enabled on non-ChromeOS environments, e.g. when running // TPM loading is enabled on non-ChromeOS environments, e.g. when running
// tests on Linux. // tests on Linux.
// Treat TPM as disabled for guest users since they do not store certs. // Treat TPM as disabled for guest users since they do not store certs.
return initialized_for_test_ || (base::SysInfo::IsRunningOnChromeOS() && return initialized_for_test_ || enable_tpm_loading_for_testing_ ||
!LoginState::Get()->IsGuestSessionUser()); (base::SysInfo::IsRunningOnChromeOS() &&
!LoginState::Get()->IsGuestSessionUser());
} }
void TPMTokenLoader::MaybeStartTokenInitialization() { void TPMTokenLoader::MaybeStartTokenInitialization() {
......
...@@ -50,7 +50,8 @@ class COMPONENT_EXPORT(CHROMEOS_TPM) TPMTokenLoader ...@@ -50,7 +50,8 @@ class COMPONENT_EXPORT(CHROMEOS_TPM) TPMTokenLoader
// The global instance will immediately start observing |LoginState|. // The global instance will immediately start observing |LoginState|.
static void Initialize(); static void Initialize();
// Sets the global. stubbed out, instance. To be used in tests. // Sets the global, stubbed out with the already initialized token, instance.
// To be used in tests.
static void InitializeForTest(); static void InitializeForTest();
// Destroys the global instance. // Destroys the global instance.
...@@ -81,8 +82,13 @@ class COMPONENT_EXPORT(CHROMEOS_TPM) TPMTokenLoader ...@@ -81,8 +82,13 @@ class COMPONENT_EXPORT(CHROMEOS_TPM) TPMTokenLoader
std::string tpm_user_pin() const { return tpm_user_pin_; } std::string tpm_user_pin() const { return tpm_user_pin_; }
// Allows tests to enable the TPM token loading logic in this class.
void enable_tpm_loading_for_testing(bool enable) {
enable_tpm_loading_for_testing_ = enable;
}
private: private:
explicit TPMTokenLoader(bool for_test); explicit TPMTokenLoader(bool initialized_for_test);
~TPMTokenLoader() override; ~TPMTokenLoader() override;
bool IsTPMLoadingEnabled() const; bool IsTPMLoadingEnabled() const;
...@@ -104,6 +110,8 @@ class COMPONENT_EXPORT(CHROMEOS_TPM) TPMTokenLoader ...@@ -104,6 +110,8 @@ class COMPONENT_EXPORT(CHROMEOS_TPM) TPMTokenLoader
// LoginState::Observer // LoginState::Observer
void LoggedInStateChanged() override; void LoggedInStateChanged() override;
bool enable_tpm_loading_for_testing_ = false;
bool initialized_for_test_; bool initialized_for_test_;
TPMReadyCallbackList tpm_ready_callback_list_; TPMReadyCallbackList tpm_ready_callback_list_;
......
...@@ -580,6 +580,19 @@ class NSSInitSingleton { ...@@ -580,6 +580,19 @@ class NSSInitSingleton {
} }
} }
void SetSystemKeySlotWithoutInitializingTPMForTesting(ScopedPK11Slot slot) {
DCHECK(thread_checker_.CalledOnValidThread());
// Ensure that a previous value of test_system_slot_ is not overwritten.
// Unsetting, i.e. setting a nullptr, however is allowed.
DCHECK(!slot || !test_system_slot_);
if (tpm_slot_ && tpm_slot_ == test_system_slot_) {
// Unset |tpm_slot_| if it was initialized from |test_system_slot_|.
tpm_slot_.reset();
}
test_system_slot_ = std::move(slot);
}
void SetPrivateSoftwareSlotForChromeOSUserForTesting(ScopedPK11Slot slot) { void SetPrivateSoftwareSlotForChromeOSUserForTesting(ScopedPK11Slot slot) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
...@@ -823,6 +836,11 @@ void SetSystemKeySlotForTesting(ScopedPK11Slot slot) { ...@@ -823,6 +836,11 @@ void SetSystemKeySlotForTesting(ScopedPK11Slot slot) {
g_nss_singleton.Get().SetSystemKeySlotForTesting(std::move(slot)); g_nss_singleton.Get().SetSystemKeySlotForTesting(std::move(slot));
} }
void SetSystemKeySlotWithoutInitializingTPMForTesting(ScopedPK11Slot slot) {
g_nss_singleton.Get().SetSystemKeySlotWithoutInitializingTPMForTesting(
std::move(slot));
}
void EnableTPMTokenForNSS() { void EnableTPMTokenForNSS() {
g_nss_singleton.Get().EnableTPMTokenForNSS(); g_nss_singleton.Get().EnableTPMTokenForNSS();
} }
......
...@@ -63,6 +63,14 @@ CRYPTO_EXPORT ScopedPK11Slot GetSystemNSSKeySlot( ...@@ -63,6 +63,14 @@ CRYPTO_EXPORT ScopedPK11Slot GetSystemNSSKeySlot(
// |slot| is nullptr, the test system slot is unset. // |slot| is nullptr, the test system slot is unset.
CRYPTO_EXPORT void SetSystemKeySlotForTesting(ScopedPK11Slot slot); CRYPTO_EXPORT void SetSystemKeySlotForTesting(ScopedPK11Slot slot);
// Injects the given |slot| as a system slot set by the future
// |InitializeTPMTokenAndSystemSlot| call.
// This must must not be called consecutively with a |slot| != nullptr. If
// |slot| is nullptr and the system slot is already initialized to the
// previously passed test value, the system slot is unset.
CRYPTO_EXPORT void SetSystemKeySlotWithoutInitializingTPMForTesting(
ScopedPK11Slot slot);
// Prepare per-user NSS slot mapping. It is safe to call this function multiple // Prepare per-user NSS slot mapping. It is safe to call this function multiple
// times. Returns true if the user was added, or false if it already existed. // times. Returns true if the user was added, or false if it already existed.
CRYPTO_EXPORT bool InitializeNSSForChromeOSUser( CRYPTO_EXPORT bool InitializeNSSForChromeOSUser(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment