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 "components/cert_database/public/chromeos/cert_database_service_io_part _chromeos.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/bind_helpers.h" | |
9 #include "base/callback.h" | |
10 #include "base/location.h" | |
11 #include "base/single_thread_task_runner.h" | |
12 #include "base/thread_task_runner_handle.h" | |
13 #include "chromeos/dbus/cryptohome_client.h" | |
14 #include "crypto/nss_util.h" | |
15 #include "crypto/nss_util_internal.h" | |
16 #include "net/cert/nss_cert_database_chromeos.h" | |
17 | |
18 namespace cert_database { | |
19 | |
20 namespace { | |
21 | |
22 void DidGetTPMInfoOnUICallBackToIO( | |
23 const chromeos::CryptohomeClient::Pkcs11GetTpmTokenInfoCallback& callback, | |
24 scoped_refptr<base::SingleThreadTaskRunner> origin_thread, | |
25 chromeos::DBusMethodCallStatus call_status, | |
26 const std::string& label, | |
27 const std::string& user_pin, | |
28 int slot_id) { | |
29 DVLOG(1) << "Got TPM info for slot " << slot_id; | |
30 origin_thread->PostTask( | |
31 FROM_HERE, base::Bind(callback, call_status, label, user_pin, slot_id)); | |
32 } | |
33 | |
34 void GetTPMInfoForUserOnUIThread( | |
35 const std::string& user_email, | |
36 const chromeos::CryptohomeClient::Pkcs11GetTpmTokenInfoCallback& callback, | |
37 scoped_refptr<base::SingleThreadTaskRunner> origin_thread, | |
38 chromeos::CryptohomeClient* cryptohome_client) { | |
39 DVLOG(1) << "Getting TPM info from cryptohome for " | |
40 << " " << user_email; | |
41 cryptohome_client->Pkcs11GetTpmTokenInfoForUser( | |
42 user_email, | |
43 base::Bind(&DidGetTPMInfoOnUICallBackToIO, callback, origin_thread)); | |
44 } | |
45 | |
46 void GetTPMInfoForUserOnIOThread( | |
47 const std::string& user_email, | |
48 const chromeos::CryptohomeClient::Pkcs11GetTpmTokenInfoCallback& callback, | |
49 scoped_refptr<base::SequencedTaskRunner> dbus_task_runner, | |
50 chromeos::CryptohomeClient* cryptohome_client) { | |
51 dbus_task_runner->PostTask(FROM_HERE, | |
52 base::Bind(&GetTPMInfoForUserOnUIThread, | |
53 user_email, | |
54 callback, | |
55 base::ThreadTaskRunnerHandle::Get(), | |
56 cryptohome_client)); | |
57 } | |
58 | |
59 } // namespace | |
60 | |
61 class CertDatabaseServiceIOPartChromeOS::Internal { | |
62 public: | |
63 explicit Internal( | |
Joao da Silva
2014/10/30 09:48:01
No need for explicit
pneubeck (no reviews)
2014/11/05 14:53:37
Done.
| |
64 const std::string& user_email, | |
65 const std::string& username_hash, | |
66 bool use_system_key_slot, | |
67 const base::FilePath& path, | |
68 const scoped_refptr<base::SequencedTaskRunner>& dbus_task_runner, | |
69 chromeos::CryptohomeClient* cryptohome_client, | |
70 CertDatabaseServiceIOPartChromeOS* io_part) | |
71 : user_email_(user_email), | |
72 username_hash_(username_hash), | |
73 use_system_key_slot_(use_system_key_slot), | |
74 path_(path), | |
75 dbus_task_runner_(dbus_task_runner), | |
76 state_(NOT_STARTED), | |
77 system_tpm_token_status_(SYSTEM_TPM_TOKEN_STATUS_UNDETERMINED), | |
78 cryptohome_client_(cryptohome_client), | |
79 io_part_(io_part), | |
80 weak_ptr_factory_(this) { | |
81 CHECK(dbus_task_runner_.get()); | |
82 CHECK(cryptohome_client_); | |
83 CHECK(io_part_); | |
84 } | |
85 | |
86 void Run() { | |
87 thread_checker_.DetachFromThread(); | |
88 thread_checker_.CalledOnValidThread(); | |
Joao da Silva
2014/10/30 09:48:01
DCHECK
pneubeck (no reviews)
2014/11/05 14:53:37
why? This check can never fail because of the Deta
Joao da Silva
2014/11/05 15:07:51
Ah, the call to CalledOnValidThread() is just to a
| |
89 DCHECK_EQ(NOT_STARTED, state_); | |
90 | |
91 VLOG(1) << "Initialize NSS for chromeos user " << username_hash_; | |
92 crypto::InitializeNSSForChromeOSUser(username_hash_, path_); | |
93 RunNextStep(TPM_TOKEN_STATE_UNKNOWN); | |
94 } | |
95 | |
96 typedef base::Callback<void(bool system_tpm_token_enabled)> | |
97 SystemTPMTokenReadyCallback; | |
98 SystemTPMTokenReadyCallback GetSystemTPMTokenReadyCallback() { | |
99 return base::Bind(&Internal::OnSystemTPMTokenReady, | |
100 weak_ptr_factory_.GetWeakPtr()); | |
101 } | |
102 | |
103 private: | |
104 enum SystemTPMTokenStatus { | |
105 SYSTEM_TPM_TOKEN_STATUS_UNDETERMINED, | |
106 SYSTEM_TPM_TOKEN_STATUS_ENABLED, | |
107 SYSTEM_TPM_TOKEN_STATUS_DISABLED | |
108 }; | |
109 | |
110 enum State { | |
111 NOT_STARTED, | |
112 TPM_TOKEN_STATE_UNKNOWN, | |
113 TPM_TOKEN_ENABLED_AND_READY, | |
114 INITIALIZED_NSS_FOR_USER, | |
115 GOT_PRIVATE_SLOT_FOR_USER, | |
116 WAITING_FOR_SYSTEM_TPM_TOKEN, | |
117 SYSTEM_TPM_TOKEN_READY, | |
118 GOT_SYSTEM_SLOT, | |
119 CREATED_NSS_CERTDB | |
120 }; | |
121 | |
122 void RunNextStep(const State& next_state) { | |
123 DCHECK(thread_checker_.CalledOnValidThread()); | |
124 | |
125 VLOG(1) << "State transition " << state_ << " -> " << next_state; | |
126 state_ = next_state; | |
127 switch (state_) { | |
128 case NOT_STARTED: | |
129 NOTREACHED(); | |
130 break; | |
131 case TPM_TOKEN_STATE_UNKNOWN: | |
132 CheckTPMTokenState(); | |
133 break; | |
134 case TPM_TOKEN_ENABLED_AND_READY: | |
135 GetTPMTokenInfo(); | |
136 break; | |
137 case INITIALIZED_NSS_FOR_USER: | |
138 GetPrivateSlot(); | |
139 break; | |
140 case GOT_PRIVATE_SLOT_FOR_USER: | |
141 if (!use_system_key_slot_) { | |
142 RunNextStep(GOT_SYSTEM_SLOT); | |
143 } else if (system_tpm_token_status_ == | |
144 SYSTEM_TPM_TOKEN_STATUS_UNDETERMINED) { | |
145 state_ = WAITING_FOR_SYSTEM_TPM_TOKEN; | |
146 } else { | |
147 RunNextStep(SYSTEM_TPM_TOKEN_READY); | |
148 } | |
149 break; | |
150 case WAITING_FOR_SYSTEM_TPM_TOKEN: | |
151 // This step is waiting for OnSystemTPMTokenReady to be called. | |
152 NOTREACHED(); | |
153 break; | |
154 case SYSTEM_TPM_TOKEN_READY: | |
155 GetSystemSlot(); | |
156 break; | |
157 case GOT_SYSTEM_SLOT: | |
158 CreateCertDatabase(); | |
159 break; | |
160 case CREATED_NSS_CERTDB: | |
161 NOTREACHED(); | |
162 } | |
163 } | |
164 | |
165 void FinishWithState(const State& state) { | |
166 VLOG(1) << "FinishWithState " << state; | |
167 state_ = state; | |
168 } | |
169 | |
170 void CheckTPMTokenState() { | |
171 // Check if it's OK to initialize TPM for the user before continuing. This | |
172 // may not be the case if the TPM slot initialization was previously | |
173 // requested for the same user. | |
174 if (!crypto::ShouldInitializeTPMForChromeOSUser(username_hash_)) { | |
175 RunNextStep(INITIALIZED_NSS_FOR_USER); | |
176 return; | |
177 } | |
178 | |
179 crypto::WillInitializeTPMForChromeOSUser(username_hash_); | |
180 | |
181 if (crypto::IsTPMTokenEnabledForNSS()) { | |
182 base::Closure tpm_token_ready_callback = | |
183 base::Bind(&Internal::RunNextStep, | |
184 weak_ptr_factory_.GetWeakPtr(), | |
185 TPM_TOKEN_ENABLED_AND_READY); | |
186 if (crypto::IsTPMTokenReady(tpm_token_ready_callback)) | |
187 tpm_token_ready_callback.Run(); | |
188 else | |
189 DVLOG(1) << "Waiting for tpm ready ..."; | |
190 } else { | |
191 crypto::InitializePrivateSoftwareSlotForChromeOSUser(username_hash_); | |
192 RunNextStep(INITIALIZED_NSS_FOR_USER); | |
193 } | |
194 } | |
195 | |
196 void GetTPMTokenInfo() { | |
197 GetTPMInfoForUserOnIOThread( | |
198 user_email_, | |
199 base::Bind(&Internal::GotTPMTokenInfo, weak_ptr_factory_.GetWeakPtr()), | |
200 dbus_task_runner_, | |
201 cryptohome_client_); | |
202 } | |
203 | |
204 void GotTPMTokenInfo(chromeos::DBusMethodCallStatus call_status, | |
205 const std::string& label, | |
206 const std::string& user_pin, | |
207 int slot_id) { | |
208 DCHECK(thread_checker_.CalledOnValidThread()); | |
209 | |
210 if (call_status == chromeos::DBUS_METHOD_CALL_FAILURE) { | |
211 // TODO(pneubeck, tbarzic): Retry instead of just failing. | |
212 // https://crbug.com/426349 | |
213 LOG(ERROR) << "DBus error while getting TPM info for " << username_hash_; | |
214 crypto::InitializePrivateSoftwareSlotForChromeOSUser(username_hash_); | |
215 } else { | |
216 crypto::InitializeTPMForChromeOSUser(username_hash_, slot_id); | |
217 } | |
218 RunNextStep(INITIALIZED_NSS_FOR_USER); | |
219 } | |
220 | |
221 void GetPrivateSlot() { | |
222 base::Callback<void(crypto::ScopedPK11Slot)> callback = | |
223 base::Bind(&Internal::GotPrivateSlot, weak_ptr_factory_.GetWeakPtr()); | |
224 | |
225 crypto::ScopedPK11Slot private_slot( | |
226 crypto::GetPrivateSlotForChromeOSUser(username_hash_, callback)); | |
227 if (private_slot) | |
228 callback.Run(private_slot.Pass()); | |
229 } | |
230 | |
231 void GotPrivateSlot(crypto::ScopedPK11Slot private_slot) { | |
232 DCHECK(thread_checker_.CalledOnValidThread()); | |
233 DCHECK(private_slot); | |
234 | |
235 private_slot_ = private_slot.Pass(); | |
236 RunNextStep(GOT_PRIVATE_SLOT_FOR_USER); | |
237 } | |
238 | |
239 // This is called from external once the TPM token is ready. Must be called at | |
240 // most once and after Run(). | |
241 void OnSystemTPMTokenReady(bool system_tpm_token_enabled) { | |
242 DCHECK(thread_checker_.CalledOnValidThread()); | |
243 DCHECK_NE(NOT_STARTED, state_); | |
244 DCHECK_EQ(SYSTEM_TPM_TOKEN_STATUS_UNDETERMINED, system_tpm_token_status_); | |
245 | |
246 if (!use_system_key_slot_) | |
247 return; | |
248 if (system_tpm_token_enabled) | |
249 system_tpm_token_status_ = SYSTEM_TPM_TOKEN_STATUS_ENABLED; | |
250 else | |
251 system_tpm_token_status_ = SYSTEM_TPM_TOKEN_STATUS_DISABLED; | |
252 if (state_ == WAITING_FOR_SYSTEM_TPM_TOKEN) | |
253 RunNextStep(SYSTEM_TPM_TOKEN_READY); | |
254 } | |
255 | |
256 void GetSystemSlot() { | |
257 if (!use_system_key_slot_ || | |
258 system_tpm_token_status_ == SYSTEM_TPM_TOKEN_STATUS_DISABLED) { | |
259 VLOG(2) << "Skip system key slot initialization"; | |
260 RunNextStep(GOT_SYSTEM_SLOT); | |
261 return; | |
262 } | |
263 | |
264 base::Callback<void(crypto::ScopedPK11Slot)> callback = | |
265 base::Bind(&Internal::GotSystemSlot, weak_ptr_factory_.GetWeakPtr()); | |
266 | |
267 crypto::ScopedPK11Slot system_slot = crypto::GetSystemNSSKeySlot(callback); | |
268 if (system_slot) | |
269 callback.Run(system_slot.Pass()); | |
270 } | |
271 | |
272 void GotSystemSlot(crypto::ScopedPK11Slot system_slot) { | |
273 if (!system_slot) | |
274 LOG(ERROR) << "Could not get the system key slot."; | |
275 system_slot_ = system_slot.Pass(); | |
276 RunNextStep(GOT_SYSTEM_SLOT); | |
277 } | |
278 | |
279 void CreateCertDatabase() { | |
280 crypto::ScopedPK11Slot public_slot = | |
281 crypto::GetPublicSlotForChromeOSUser(username_hash_); | |
282 | |
283 scoped_ptr<net::NSSCertDatabaseChromeOS> db( | |
284 new net::NSSCertDatabaseChromeOS(public_slot.Pass(), | |
285 private_slot_.Pass())); | |
286 if (system_slot_) | |
287 db->SetSystemSlot(system_slot_.Pass()); | |
288 | |
289 FinishWithState(CREATED_NSS_CERTDB); | |
290 io_part_->DidCreateNSSCertDatabase(db.Pass()); // Will delete this. | |
291 } | |
292 | |
293 const std::string user_email_; | |
294 const std::string username_hash_; | |
295 bool use_system_key_slot_; | |
296 const base::FilePath path_; | |
297 scoped_refptr<base::SequencedTaskRunner> dbus_task_runner_; | |
298 State state_; | |
299 crypto::ScopedPK11Slot private_slot_; | |
300 SystemTPMTokenStatus system_tpm_token_status_; | |
301 crypto::ScopedPK11Slot system_slot_; | |
302 chromeos::CryptohomeClient* cryptohome_client_; | |
303 CertDatabaseServiceIOPartChromeOS* io_part_; | |
304 base::ThreadChecker thread_checker_; | |
305 base::WeakPtrFactory<Internal> weak_ptr_factory_; | |
306 | |
307 DISALLOW_COPY_AND_ASSIGN(Internal); | |
308 }; | |
309 | |
310 CertDatabaseServiceIOPartChromeOS::CertDatabaseServiceIOPartChromeOS( | |
311 const std::string& user_email, | |
312 const std::string& username_hash, | |
313 bool use_system_key_slot, | |
314 const base::FilePath& path, | |
315 const scoped_refptr<base::SequencedTaskRunner>& dbus_task_runner, | |
316 chromeos::CryptohomeClient* cryptohome_client) | |
317 : internal_(new Internal(user_email, | |
318 username_hash, | |
319 use_system_key_slot, | |
320 path, | |
321 dbus_task_runner, | |
322 cryptohome_client, | |
323 this)) { | |
324 } | |
325 | |
326 CertDatabaseServiceIOPartChromeOS::~CertDatabaseServiceIOPartChromeOS() { | |
327 DCHECK(thread_checker_.CalledOnValidThread()); | |
328 } | |
329 | |
330 void CertDatabaseServiceIOPartChromeOS::Init() { | |
331 CertDatabaseServiceIOPart::Init(); | |
332 internal_->Run(); | |
333 } | |
334 | |
335 void CertDatabaseServiceIOPartChromeOS::DidCreateNSSCertDatabase( | |
336 scoped_ptr<net::NSSCertDatabase> db) { | |
337 internal_.reset(); | |
338 SetNSSCertDatabase(db.Pass()); | |
339 } | |
340 | |
341 CertDatabaseServiceIOPartChromeOS::SystemTPMTokenReadyCallback | |
342 CertDatabaseServiceIOPartChromeOS::GetSystemTPMTokenReadyCallback() { | |
343 CHECK(!IsInitialized()); | |
344 return internal_->GetSystemTPMTokenReadyCallback(); | |
345 } | |
346 | |
347 } // namespace cert_database | |
OLD | NEW |