Remove errant '>' in gyp file.
[chromium-blink-merge.git] / chromeos / tpm / tpm_token_loader.cc
blob672695a1f0f3537ce7e9cbad7d82aa94006b5848
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chromeos/tpm/tpm_token_loader.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/sequenced_task_runner.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/sys_info.h"
14 #include "base/task_runner_util.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "chromeos/dbus/dbus_thread_manager.h"
17 #include "chromeos/tpm/tpm_token_info_getter.h"
18 #include "crypto/nss_util.h"
20 namespace chromeos {
22 namespace {
24 void PostResultToTaskRunner(scoped_refptr<base::SequencedTaskRunner> runner,
25 const base::Callback<void(bool)>& callback,
26 bool success) {
27 runner->PostTask(FROM_HERE, base::Bind(callback, success));
30 } // namespace
32 static TPMTokenLoader* g_tpm_token_loader = NULL;
34 // static
35 void TPMTokenLoader::Initialize() {
36 CHECK(!g_tpm_token_loader);
37 g_tpm_token_loader = new TPMTokenLoader(false /*for_test*/);
40 // static
41 void TPMTokenLoader::InitializeForTest() {
42 CHECK(!g_tpm_token_loader);
43 g_tpm_token_loader = new TPMTokenLoader(true /*for_test*/);
46 // static
47 void TPMTokenLoader::Shutdown() {
48 CHECK(g_tpm_token_loader);
49 delete g_tpm_token_loader;
50 g_tpm_token_loader = NULL;
53 // static
54 TPMTokenLoader* TPMTokenLoader::Get() {
55 CHECK(g_tpm_token_loader)
56 << "TPMTokenLoader::Get() called before Initialize()";
57 return g_tpm_token_loader;
60 // static
61 bool TPMTokenLoader::IsInitialized() {
62 return g_tpm_token_loader;
65 TPMTokenLoader::TPMTokenLoader(bool for_test)
66 : initialized_for_test_(for_test),
67 tpm_token_state_(TPM_STATE_UNKNOWN),
68 tpm_token_info_getter_(
69 TPMTokenInfoGetter::CreateForSystemToken(
70 DBusThreadManager::Get()->GetCryptohomeClient(),
71 base::ThreadTaskRunnerHandle::Get())),
72 tpm_token_slot_id_(-1),
73 can_start_before_login_(false),
74 weak_factory_(this) {
75 if (!initialized_for_test_ && LoginState::IsInitialized())
76 LoginState::Get()->AddObserver(this);
78 if (initialized_for_test_) {
79 tpm_token_state_ = TPM_TOKEN_INITIALIZED;
80 tpm_user_pin_ = "111111";
84 void TPMTokenLoader::SetCryptoTaskRunner(
85 const scoped_refptr<base::SequencedTaskRunner>& crypto_task_runner) {
86 crypto_task_runner_ = crypto_task_runner;
87 MaybeStartTokenInitialization();
90 void TPMTokenLoader::EnsureStarted() {
91 if (can_start_before_login_)
92 return;
93 can_start_before_login_ = true;
94 MaybeStartTokenInitialization();
97 TPMTokenLoader::~TPMTokenLoader() {
98 if (!initialized_for_test_ && LoginState::IsInitialized())
99 LoginState::Get()->RemoveObserver(this);
102 TPMTokenLoader::TPMTokenStatus TPMTokenLoader::IsTPMTokenEnabled(
103 const TPMReadyCallback& callback) {
104 if (tpm_token_state_ == TPM_TOKEN_INITIALIZED)
105 return TPM_TOKEN_STATUS_ENABLED;
106 if (!IsTPMLoadingEnabled() || tpm_token_state_ == TPM_DISABLED)
107 return TPM_TOKEN_STATUS_DISABLED;
108 // Status is not known yet.
109 if (!callback.is_null())
110 tpm_ready_callback_list_.push_back(callback);
111 return TPM_TOKEN_STATUS_UNDETERMINED;
114 bool TPMTokenLoader::IsTPMLoadingEnabled() const {
115 // TPM loading is enabled on non-ChromeOS environments, e.g. when running
116 // tests on Linux.
117 // Treat TPM as disabled for guest users since they do not store certs.
118 return initialized_for_test_ || (base::SysInfo::IsRunningOnChromeOS() &&
119 !LoginState::Get()->IsGuestSessionUser());
122 void TPMTokenLoader::MaybeStartTokenInitialization() {
123 CHECK(thread_checker_.CalledOnValidThread());
125 // This is the entry point to the TPM token initialization process,
126 // which we should do at most once.
127 if (tpm_token_state_ != TPM_STATE_UNKNOWN || !crypto_task_runner_.get())
128 return;
130 bool start_initialization =
131 (LoginState::IsInitialized() && LoginState::Get()->IsUserLoggedIn()) ||
132 can_start_before_login_;
134 VLOG(1) << "StartTokenInitialization: " << start_initialization;
135 if (!start_initialization)
136 return;
138 if (!IsTPMLoadingEnabled())
139 tpm_token_state_ = TPM_DISABLED;
141 ContinueTokenInitialization();
143 DCHECK_NE(tpm_token_state_, TPM_STATE_UNKNOWN);
146 void TPMTokenLoader::ContinueTokenInitialization() {
147 CHECK(thread_checker_.CalledOnValidThread());
148 VLOG(1) << "ContinueTokenInitialization: " << tpm_token_state_;
150 switch (tpm_token_state_) {
151 case TPM_STATE_UNKNOWN: {
152 crypto_task_runner_->PostTaskAndReply(
153 FROM_HERE,
154 base::Bind(&crypto::EnableTPMTokenForNSS),
155 base::Bind(&TPMTokenLoader::OnTPMTokenEnabledForNSS,
156 weak_factory_.GetWeakPtr()));
157 tpm_token_state_ = TPM_INITIALIZATION_STARTED;
158 return;
160 case TPM_INITIALIZATION_STARTED: {
161 NOTREACHED();
162 return;
164 case TPM_TOKEN_ENABLED_FOR_NSS: {
165 tpm_token_info_getter_->Start(
166 base::Bind(&TPMTokenLoader::OnGotTpmTokenInfo,
167 weak_factory_.GetWeakPtr()));
168 return;
170 case TPM_DISABLED: {
171 // TPM is disabled, so proceed with empty tpm token name.
172 NotifyTPMTokenReady();
173 return;
175 case TPM_TOKEN_INFO_RECEIVED: {
176 crypto_task_runner_->PostTask(
177 FROM_HERE,
178 base::Bind(
179 &crypto::InitializeTPMTokenAndSystemSlot,
180 tpm_token_slot_id_,
181 base::Bind(&PostResultToTaskRunner,
182 base::ThreadTaskRunnerHandle::Get(),
183 base::Bind(&TPMTokenLoader::OnTPMTokenInitialized,
184 weak_factory_.GetWeakPtr()))));
185 return;
187 case TPM_TOKEN_INITIALIZED: {
188 NotifyTPMTokenReady();
189 return;
194 void TPMTokenLoader::OnTPMTokenEnabledForNSS() {
195 VLOG(1) << "TPMTokenEnabledForNSS";
196 tpm_token_state_ = TPM_TOKEN_ENABLED_FOR_NSS;
197 ContinueTokenInitialization();
200 void TPMTokenLoader::OnGotTpmTokenInfo(const TPMTokenInfo& token_info) {
201 if (!token_info.tpm_is_enabled) {
202 tpm_token_state_ = TPM_DISABLED;
203 ContinueTokenInitialization();
204 return;
207 tpm_token_slot_id_ = token_info.token_slot_id;
208 tpm_user_pin_ = token_info.user_pin;
209 tpm_token_state_ = TPM_TOKEN_INFO_RECEIVED;
211 ContinueTokenInitialization();
214 void TPMTokenLoader::OnTPMTokenInitialized(bool success) {
215 VLOG(1) << "OnTPMTokenInitialized: " << success;
217 tpm_token_state_ = success ? TPM_TOKEN_INITIALIZED : TPM_DISABLED;
218 ContinueTokenInitialization();
221 void TPMTokenLoader::NotifyTPMTokenReady() {
222 DCHECK(tpm_token_state_ == TPM_DISABLED ||
223 tpm_token_state_ == TPM_TOKEN_INITIALIZED);
224 bool tpm_status = tpm_token_state_ == TPM_TOKEN_INITIALIZED;
225 for (TPMReadyCallbackList::iterator i = tpm_ready_callback_list_.begin();
226 i != tpm_ready_callback_list_.end();
227 ++i) {
228 i->Run(tpm_status);
230 tpm_ready_callback_list_.clear();
233 void TPMTokenLoader::LoggedInStateChanged() {
234 VLOG(1) << "LoggedInStateChanged";
235 MaybeStartTokenInitialization();
238 } // namespace chromeos