1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/ash/components/tpm/tpm_token_loader.h"
#include <algorithm>
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "base/system/sys_info.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "chromeos/ash/components/tpm/tpm_token_info_getter.h"
#include "crypto/nss_util.h"
namespace ash {
namespace {
void PostResultToTaskRunner(scoped_refptr<base::SequencedTaskRunner> runner,
base::OnceCallback<void(bool)> callback,
bool success) {
runner->PostTask(FROM_HERE, base::BindOnce(std::move(callback), success));
}
} // namespace
static TPMTokenLoader* g_tpm_token_loader = NULL;
// static
void TPMTokenLoader::Initialize() {
CHECK(!g_tpm_token_loader);
g_tpm_token_loader = new TPMTokenLoader(/*initialized_for_test=*/false);
}
// static
void TPMTokenLoader::InitializeForTest() {
CHECK(!g_tpm_token_loader);
g_tpm_token_loader = new TPMTokenLoader(/*initialized_for_test=*/true);
}
// static
void TPMTokenLoader::Shutdown() {
CHECK(g_tpm_token_loader);
delete g_tpm_token_loader;
g_tpm_token_loader = NULL;
}
// static
TPMTokenLoader* TPMTokenLoader::Get() {
CHECK(g_tpm_token_loader)
<< "TPMTokenLoader::Get() called before Initialize()";
return g_tpm_token_loader;
}
// static
bool TPMTokenLoader::IsInitialized() {
return g_tpm_token_loader;
}
TPMTokenLoader::TPMTokenLoader(bool initialized_for_test)
: initialized_for_test_(initialized_for_test),
tpm_token_state_(TPM_STATE_UNKNOWN),
tpm_token_info_getter_(TPMTokenInfoGetter::CreateForSystemToken(
CryptohomePkcs11Client::Get(),
base::SingleThreadTaskRunner::GetCurrentDefault())),
tpm_token_slot_id_(-1),
can_start_before_login_(false) {
if (!initialized_for_test_ && LoginState::IsInitialized())
LoginState::Get()->AddObserver(this);
if (initialized_for_test_) {
tpm_token_state_ = TPM_TOKEN_INITIALIZED;
tpm_user_pin_ = "111111";
}
}
void TPMTokenLoader::SetCryptoTaskRunner(
const scoped_refptr<base::SequencedTaskRunner>& crypto_task_runner) {
crypto_task_runner_ = crypto_task_runner;
MaybeStartTokenInitialization();
}
void TPMTokenLoader::EnsureStarted() {
if (can_start_before_login_)
return;
can_start_before_login_ = true;
MaybeStartTokenInitialization();
}
TPMTokenLoader::~TPMTokenLoader() {
if (!initialized_for_test_ && LoginState::IsInitialized())
LoginState::Get()->RemoveObserver(this);
}
bool TPMTokenLoader::IsTPMLoadingEnabled() const {
// TPM loading is enabled on non-ChromeOS environments, e.g. when running
// tests on Linux.
// Treat TPM as disabled for guest users since they do not store certs.
return initialized_for_test_ || enable_tpm_loading_for_testing_ ||
(base::SysInfo::IsRunningOnChromeOS() &&
!LoginState::Get()->IsGuestSessionUser());
}
void TPMTokenLoader::MaybeStartTokenInitialization() {
CHECK(thread_checker_.CalledOnValidThread());
// This is the entry point to the TPM token initialization process,
// which we should do at most once.
if (tpm_token_state_ != TPM_STATE_UNKNOWN || !crypto_task_runner_.get())
return;
bool start_initialization =
(LoginState::IsInitialized() && LoginState::Get()->IsUserLoggedIn()) ||
can_start_before_login_;
VLOG(1) << "StartTokenInitialization: " << start_initialization;
if (!start_initialization)
return;
if (!IsTPMLoadingEnabled())
tpm_token_state_ = TPM_DISABLED;
ContinueTokenInitialization();
DCHECK_NE(tpm_token_state_, TPM_STATE_UNKNOWN);
}
void TPMTokenLoader::ContinueTokenInitialization() {
CHECK(thread_checker_.CalledOnValidThread());
VLOG(1) << "ContinueTokenInitialization: " << tpm_token_state_;
switch (tpm_token_state_) {
case TPM_STATE_UNKNOWN: {
tpm_token_state_ = TPM_INITIALIZATION_STARTED;
tpm_token_info_getter_->Start(base::BindOnce(
&TPMTokenLoader::OnGotTpmTokenInfo, weak_factory_.GetWeakPtr()));
return;
}
case TPM_INITIALIZATION_STARTED: {
NOTREACHED();
}
case TPM_TOKEN_INFO_RECEIVED: {
crypto_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&crypto::InitializeTPMTokenAndSystemSlot, tpm_token_slot_id_,
base::BindOnce(
&PostResultToTaskRunner,
base::SingleThreadTaskRunner::GetCurrentDefault(),
base::BindOnce(&TPMTokenLoader::OnTPMTokenInitialized,
weak_factory_.GetWeakPtr()))));
return;
}
case TPM_TOKEN_INITIALIZED:
case TPM_DISABLED: {
NotifyTPMTokenReady();
return;
}
}
}
void TPMTokenLoader::OnGotTpmTokenInfo(
std::optional<user_data_auth::TpmTokenInfo> token_info) {
if (!token_info.has_value()) {
tpm_token_state_ = TPM_DISABLED;
ContinueTokenInitialization();
return;
}
tpm_token_slot_id_ = token_info->slot();
tpm_user_pin_ = token_info->user_pin();
tpm_token_state_ = TPM_TOKEN_INFO_RECEIVED;
ContinueTokenInitialization();
}
void TPMTokenLoader::OnTPMTokenInitialized(bool success) {
VLOG(1) << "OnTPMTokenInitialized: " << success;
tpm_token_state_ = success ? TPM_TOKEN_INITIALIZED : TPM_DISABLED;
ContinueTokenInitialization();
}
void TPMTokenLoader::NotifyTPMTokenReady() {
crypto_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&crypto::FinishInitializingTPMTokenAndSystemSlot));
}
void TPMTokenLoader::LoggedInStateChanged() {
VLOG(1) << "LoggedInStateChanged";
MaybeStartTokenInitialization();
}
} // namespace ash
|