Add UMA to identify where a hotword trigger comes from.
[chromium-blink-merge.git] / chromeos / tpm_token_loader.cc
blob4f17bf5595747345fb65f820903762b449d4eafb
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_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_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 weak_factory_(this) {
74 if (!initialized_for_test_ && LoginState::IsInitialized())
75 LoginState::Get()->AddObserver(this);
77 if (initialized_for_test_) {
78 tpm_token_state_ = TPM_TOKEN_INITIALIZED;
79 tpm_user_pin_ = "111111";
83 void TPMTokenLoader::SetCryptoTaskRunner(
84 const scoped_refptr<base::SequencedTaskRunner>& crypto_task_runner) {
85 crypto_task_runner_ = crypto_task_runner;
86 MaybeStartTokenInitialization();
89 TPMTokenLoader::~TPMTokenLoader() {
90 if (!initialized_for_test_ && LoginState::IsInitialized())
91 LoginState::Get()->RemoveObserver(this);
94 TPMTokenLoader::TPMTokenStatus TPMTokenLoader::IsTPMTokenEnabled(
95 const TPMReadyCallback& callback) {
96 if (tpm_token_state_ == TPM_TOKEN_INITIALIZED)
97 return TPM_TOKEN_STATUS_ENABLED;
98 if (!IsTPMLoadingEnabled() || tpm_token_state_ == TPM_DISABLED)
99 return TPM_TOKEN_STATUS_DISABLED;
100 // Status is not known yet.
101 if (!callback.is_null())
102 tpm_ready_callback_list_.push_back(callback);
103 return TPM_TOKEN_STATUS_UNDETERMINED;
106 bool TPMTokenLoader::IsTPMLoadingEnabled() const {
107 // TPM loading is enabled on non-ChromeOS environments, e.g. when running
108 // tests on Linux.
109 // Treat TPM as disabled for guest users since they do not store certs.
110 return initialized_for_test_ || (base::SysInfo::IsRunningOnChromeOS() &&
111 !LoginState::Get()->IsGuestSessionUser());
114 void TPMTokenLoader::MaybeStartTokenInitialization() {
115 CHECK(thread_checker_.CalledOnValidThread());
117 // This is the entry point to the TPM token initialization process,
118 // which we should do at most once.
119 if (tpm_token_state_ != TPM_STATE_UNKNOWN || !crypto_task_runner_.get())
120 return;
122 if (!LoginState::IsInitialized())
123 return;
125 bool start_initialization = LoginState::Get()->IsUserLoggedIn();
127 VLOG(1) << "StartTokenInitialization: " << start_initialization;
128 if (!start_initialization)
129 return;
131 if (!IsTPMLoadingEnabled())
132 tpm_token_state_ = TPM_DISABLED;
134 ContinueTokenInitialization();
136 DCHECK_NE(tpm_token_state_, TPM_STATE_UNKNOWN);
139 void TPMTokenLoader::ContinueTokenInitialization() {
140 CHECK(thread_checker_.CalledOnValidThread());
141 VLOG(1) << "ContinueTokenInitialization: " << tpm_token_state_;
143 switch (tpm_token_state_) {
144 case TPM_STATE_UNKNOWN: {
145 crypto_task_runner_->PostTaskAndReply(
146 FROM_HERE,
147 base::Bind(&crypto::EnableTPMTokenForNSS),
148 base::Bind(&TPMTokenLoader::OnTPMTokenEnabledForNSS,
149 weak_factory_.GetWeakPtr()));
150 tpm_token_state_ = TPM_INITIALIZATION_STARTED;
151 return;
153 case TPM_INITIALIZATION_STARTED: {
154 NOTREACHED();
155 return;
157 case TPM_TOKEN_ENABLED_FOR_NSS: {
158 tpm_token_info_getter_->Start(
159 base::Bind(&TPMTokenLoader::OnGotTpmTokenInfo,
160 weak_factory_.GetWeakPtr()));
161 return;
163 case TPM_DISABLED: {
164 // TPM is disabled, so proceed with empty tpm token name.
165 NotifyTPMTokenReady();
166 return;
168 case TPM_TOKEN_INFO_RECEIVED: {
169 crypto_task_runner_->PostTask(
170 FROM_HERE,
171 base::Bind(
172 &crypto::InitializeTPMTokenAndSystemSlot,
173 tpm_token_slot_id_,
174 base::Bind(&PostResultToTaskRunner,
175 base::ThreadTaskRunnerHandle::Get(),
176 base::Bind(&TPMTokenLoader::OnTPMTokenInitialized,
177 weak_factory_.GetWeakPtr()))));
178 return;
180 case TPM_TOKEN_INITIALIZED: {
181 NotifyTPMTokenReady();
182 return;
187 void TPMTokenLoader::OnTPMTokenEnabledForNSS() {
188 VLOG(1) << "TPMTokenEnabledForNSS";
189 tpm_token_state_ = TPM_TOKEN_ENABLED_FOR_NSS;
190 ContinueTokenInitialization();
193 void TPMTokenLoader::OnGotTpmTokenInfo(const TPMTokenInfo& token_info) {
194 if (!token_info.tpm_is_enabled) {
195 tpm_token_state_ = TPM_DISABLED;
196 ContinueTokenInitialization();
197 return;
200 tpm_token_slot_id_ = token_info.token_slot_id;
201 tpm_user_pin_ = token_info.user_pin;
202 tpm_token_state_ = TPM_TOKEN_INFO_RECEIVED;
204 ContinueTokenInitialization();
207 void TPMTokenLoader::OnTPMTokenInitialized(bool success) {
208 VLOG(1) << "OnTPMTokenInitialized: " << success;
210 tpm_token_state_ = success ? TPM_TOKEN_INITIALIZED : TPM_DISABLED;
211 ContinueTokenInitialization();
214 void TPMTokenLoader::NotifyTPMTokenReady() {
215 DCHECK(tpm_token_state_ == TPM_DISABLED ||
216 tpm_token_state_ == TPM_TOKEN_INITIALIZED);
217 bool tpm_status = tpm_token_state_ == TPM_TOKEN_INITIALIZED;
218 for (TPMReadyCallbackList::iterator i = tpm_ready_callback_list_.begin();
219 i != tpm_ready_callback_list_.end();
220 ++i) {
221 i->Run(tpm_status);
223 tpm_ready_callback_list_.clear();
226 void TPMTokenLoader::LoggedInStateChanged() {
227 VLOG(1) << "LoggedInStateChanged";
228 MaybeStartTokenInitialization();
231 } // namespace chromeos