OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "chromeos/tpm_token_loader.h" | |
6 | |
7 #include <algorithm> | |
8 | |
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" | |
19 | |
20 namespace chromeos { | |
21 | |
22 namespace { | |
23 | |
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)); | |
28 } | |
29 | |
30 } // namespace | |
31 | |
32 static TPMTokenLoader* g_tpm_token_loader = NULL; | |
33 | |
34 // static | |
35 void TPMTokenLoader::Initialize() { | |
36 CHECK(!g_tpm_token_loader); | |
37 g_tpm_token_loader = new TPMTokenLoader(false /*for_test*/); | |
38 } | |
39 | |
40 // static | |
41 void TPMTokenLoader::InitializeForTest() { | |
42 CHECK(!g_tpm_token_loader); | |
43 g_tpm_token_loader = new TPMTokenLoader(true /*for_test*/); | |
44 } | |
45 | |
46 // static | |
47 void TPMTokenLoader::Shutdown() { | |
48 CHECK(g_tpm_token_loader); | |
49 delete g_tpm_token_loader; | |
50 g_tpm_token_loader = NULL; | |
51 } | |
52 | |
53 // static | |
54 TPMTokenLoader* TPMTokenLoader::Get() { | |
55 CHECK(g_tpm_token_loader) | |
56 << "TPMTokenLoader::Get() called before Initialize()"; | |
57 return g_tpm_token_loader; | |
58 } | |
59 | |
60 // static | |
61 bool TPMTokenLoader::IsInitialized() { | |
62 return g_tpm_token_loader; | |
63 } | |
64 | |
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); | |
76 | |
77 if (initialized_for_test_) { | |
78 tpm_token_state_ = TPM_TOKEN_INITIALIZED; | |
79 tpm_user_pin_ = "111111"; | |
80 } | |
81 } | |
82 | |
83 void TPMTokenLoader::SetCryptoTaskRunner( | |
84 const scoped_refptr<base::SequencedTaskRunner>& crypto_task_runner) { | |
85 crypto_task_runner_ = crypto_task_runner; | |
86 MaybeStartTokenInitialization(); | |
87 } | |
88 | |
89 TPMTokenLoader::~TPMTokenLoader() { | |
90 if (!initialized_for_test_ && LoginState::IsInitialized()) | |
91 LoginState::Get()->RemoveObserver(this); | |
92 } | |
93 | |
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; | |
104 } | |
105 | |
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()); | |
112 } | |
113 | |
114 void TPMTokenLoader::MaybeStartTokenInitialization() { | |
115 CHECK(thread_checker_.CalledOnValidThread()); | |
116 | |
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; | |
121 | |
122 if (!LoginState::IsInitialized()) | |
123 return; | |
124 | |
125 bool start_initialization = LoginState::Get()->IsUserLoggedIn(); | |
126 | |
127 VLOG(1) << "StartTokenInitialization: " << start_initialization; | |
128 if (!start_initialization) | |
129 return; | |
130 | |
131 if (!IsTPMLoadingEnabled()) | |
132 tpm_token_state_ = TPM_DISABLED; | |
133 | |
134 ContinueTokenInitialization(); | |
135 | |
136 DCHECK_NE(tpm_token_state_, TPM_STATE_UNKNOWN); | |
137 } | |
138 | |
139 void TPMTokenLoader::ContinueTokenInitialization() { | |
140 CHECK(thread_checker_.CalledOnValidThread()); | |
141 VLOG(1) << "ContinueTokenInitialization: " << tpm_token_state_; | |
142 | |
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; | |
152 } | |
153 case TPM_INITIALIZATION_STARTED: { | |
154 NOTREACHED(); | |
155 return; | |
156 } | |
157 case TPM_TOKEN_ENABLED_FOR_NSS: { | |
158 tpm_token_info_getter_->Start( | |
159 base::Bind(&TPMTokenLoader::OnGotTpmTokenInfo, | |
160 weak_factory_.GetWeakPtr())); | |
161 return; | |
162 } | |
163 case TPM_DISABLED: { | |
164 // TPM is disabled, so proceed with empty tpm token name. | |
165 NotifyTPMTokenReady(); | |
166 return; | |
167 } | |
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; | |
179 } | |
180 case TPM_TOKEN_INITIALIZED: { | |
181 NotifyTPMTokenReady(); | |
182 return; | |
183 } | |
184 } | |
185 } | |
186 | |
187 void TPMTokenLoader::OnTPMTokenEnabledForNSS() { | |
188 VLOG(1) << "TPMTokenEnabledForNSS"; | |
189 tpm_token_state_ = TPM_TOKEN_ENABLED_FOR_NSS; | |
190 ContinueTokenInitialization(); | |
191 } | |
192 | |
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; | |
198 } | |
199 | |
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; | |
203 | |
204 ContinueTokenInitialization(); | |
205 } | |
206 | |
207 void TPMTokenLoader::OnTPMTokenInitialized(bool success) { | |
208 VLOG(1) << "OnTPMTokenInitialized: " << success; | |
209 | |
210 tpm_token_state_ = success ? TPM_TOKEN_INITIALIZED : TPM_DISABLED; | |
211 ContinueTokenInitialization(); | |
212 } | |
213 | |
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); | |
222 } | |
223 tpm_ready_callback_list_.clear(); | |
224 } | |
225 | |
226 void TPMTokenLoader::LoggedInStateChanged() { | |
227 VLOG(1) << "LoggedInStateChanged"; | |
228 MaybeStartTokenInitialization(); | |
229 } | |
230 | |
231 } // namespace chromeos | |
OLD | NEW |