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 enum SystemTPMTokenStatus { | |
64 SYSTEM_TPM_TOKEN_STATUS_UNDETERMINED, | |
65 SYSTEM_TPM_TOKEN_STATUS_ENABLED, | |
66 SYSTEM_TPM_TOKEN_STATUS_DISABLED | |
67 }; | |
68 | |
69 enum State { | |
70 TPM_TOKEN_STATE_UNKNOWN, | |
71 TPM_TOKEN_ENABLED_AND_READY, | |
72 INITIALIZED_NSS_FOR_USER, | |
73 GOT_PRIVATE_SLOT_FOR_USER, | |
74 WAITING_FOR_SYSTEM_TPM_TOKEN, | |
75 SYSTEM_TPM_TOKEN_READY, | |
76 GOT_SYSTEM_SLOT, | |
77 CREATED_NSS_CERTDB | |
78 }; | |
79 | |
80 explicit Internal( | |
81 const std::string& user_email, | |
82 const std::string& username_hash, | |
83 bool use_system_key_slot, | |
84 const base::FilePath& path, | |
85 const scoped_refptr<base::SequencedTaskRunner>& dbus_task_runner, | |
86 chromeos::CryptohomeClient* cryptohome_client, | |
87 CertDatabaseServiceIOPartChromeOS* io_part) | |
88 : user_email_(user_email), | |
89 username_hash_(username_hash), | |
90 use_system_key_slot_(use_system_key_slot), | |
91 path_(path), | |
92 dbus_task_runner_(dbus_task_runner), | |
93 state_(TPM_TOKEN_STATE_UNKNOWN), | |
94 system_tpm_token_status_(SYSTEM_TPM_TOKEN_STATUS_UNDETERMINED), | |
95 cryptohome_client_(cryptohome_client), | |
96 io_part_(io_part), | |
97 weak_ptr_factory_(this) { | |
98 CHECK(dbus_task_runner_.get()); | |
99 CHECK(cryptohome_client_); | |
100 CHECK(io_part_); | |
101 } | |
102 | |
103 void Run() { | |
104 thread_checker_.DetachFromThread(); | |
105 thread_checker_.CalledOnValidThread(); | |
106 | |
107 VLOG(1) << "Initialize NSS for chromeos user " << username_hash_; | |
108 crypto::InitializeNSSForChromeOSUser(username_hash_, path_); | |
109 RunNextStep(TPM_TOKEN_STATE_UNKNOWN); | |
110 } | |
111 | |
112 void RunNextStep(const State& next_state) { | |
mattm
2014/10/18 00:45:16
hm, not entirely sure about the state machine, esp
pneubeck (no reviews)
2014/10/21 09:22:09
What specific do you mean?
The fact that it's wait
mattm
2014/10/30 03:37:48
I dunno, just feels a little weird to me. But I do
| |
113 DCHECK(thread_checker_.CalledOnValidThread()); | |
114 | |
115 VLOG(1) << "State transition " << state_ << " -> " << next_state; | |
116 state_ = next_state; | |
117 switch (state_) { | |
118 case TPM_TOKEN_STATE_UNKNOWN: | |
119 CheckTPMTokenState(); | |
120 break; | |
121 case TPM_TOKEN_ENABLED_AND_READY: | |
122 GetTPMTokenInfo(); | |
123 break; | |
124 case INITIALIZED_NSS_FOR_USER: | |
125 GetPrivateSlot(); | |
126 break; | |
127 case GOT_PRIVATE_SLOT_FOR_USER: | |
128 if (!use_system_key_slot_) { | |
129 RunNextStep(GOT_SYSTEM_SLOT); | |
130 } else if (system_tpm_token_status_ == | |
131 SYSTEM_TPM_TOKEN_STATUS_UNDETERMINED) { | |
132 state_ = WAITING_FOR_SYSTEM_TPM_TOKEN; | |
133 } else { | |
134 RunNextStep(SYSTEM_TPM_TOKEN_READY); | |
135 } | |
136 break; | |
137 case WAITING_FOR_SYSTEM_TPM_TOKEN: | |
138 // This step is waiting for OnSystemTPMTokenReady to be called. | |
139 NOTREACHED(); | |
140 break; | |
141 case SYSTEM_TPM_TOKEN_READY: | |
142 GetSystemSlot(); | |
143 break; | |
144 case GOT_SYSTEM_SLOT: | |
145 CreateCertDatabase(); | |
146 break; | |
147 case CREATED_NSS_CERTDB: | |
148 NOTREACHED(); | |
149 } | |
150 } | |
151 | |
152 void FinishWithState(const State& state) { | |
153 VLOG(1) << "FinishWithState " << state; | |
154 state_ = state; | |
155 } | |
156 | |
157 void CheckTPMTokenState() { | |
158 // Check if it's OK to initialize TPM for the user before continuing. This | |
159 // may not be the case if the TPM slot initialization was previously | |
160 // requested for the same user. | |
161 if (!crypto::ShouldInitializeTPMForChromeOSUser(username_hash_)) { | |
162 RunNextStep(INITIALIZED_NSS_FOR_USER); | |
163 return; | |
164 } | |
165 | |
166 crypto::WillInitializeTPMForChromeOSUser(username_hash_); | |
167 | |
168 if (crypto::IsTPMTokenEnabledForNSS()) { | |
169 base::Closure tpm_token_ready_callback = | |
170 base::Bind(&Internal::RunNextStep, | |
171 weak_ptr_factory_.GetWeakPtr(), | |
172 TPM_TOKEN_ENABLED_AND_READY); | |
173 if (crypto::IsTPMTokenReady(tpm_token_ready_callback)) | |
174 tpm_token_ready_callback.Run(); | |
175 else | |
176 DVLOG(1) << "Waiting for tpm ready ..."; | |
177 } else { | |
178 crypto::InitializePrivateSoftwareSlotForChromeOSUser(username_hash_); | |
179 RunNextStep(INITIALIZED_NSS_FOR_USER); | |
180 } | |
181 } | |
182 | |
183 void GetTPMTokenInfo() { | |
184 GetTPMInfoForUserOnIOThread(user_email_, | |
185 base::Bind(&Internal::GetTPMTokenInfoDONE, | |
186 weak_ptr_factory_.GetWeakPtr()), | |
187 dbus_task_runner_, | |
188 cryptohome_client_); | |
189 } | |
190 | |
191 void GetTPMTokenInfoDONE(chromeos::DBusMethodCallStatus call_status, | |
192 const std::string& label, | |
193 const std::string& user_pin, | |
194 int slot_id) { | |
195 DCHECK(thread_checker_.CalledOnValidThread()); | |
196 | |
197 if (call_status == chromeos::DBUS_METHOD_CALL_FAILURE) { | |
198 LOG(ERROR) << "DBus error while getting TPM info for " << username_hash_; | |
199 crypto::InitializePrivateSoftwareSlotForChromeOSUser(username_hash_); | |
200 } else { | |
201 crypto::InitializeTPMForChromeOSUser(username_hash_, slot_id); | |
202 } | |
203 RunNextStep(INITIALIZED_NSS_FOR_USER); | |
204 } | |
205 | |
206 void GetPrivateSlot() { | |
207 base::Callback<void(crypto::ScopedPK11Slot)> callback = base::Bind( | |
208 &Internal::GetPrivateSlotDONE, weak_ptr_factory_.GetWeakPtr()); | |
209 | |
210 crypto::ScopedPK11Slot private_slot( | |
211 crypto::GetPrivateSlotForChromeOSUser(username_hash_, callback)); | |
212 if (private_slot) | |
213 callback.Run(private_slot.Pass()); | |
214 } | |
215 | |
216 void GetPrivateSlotDONE(crypto::ScopedPK11Slot private_slot) { | |
mattm
2014/10/18 00:45:16
Name style. Maybe GotPrivateSlot or DidGetPrivateS
pneubeck (no reviews)
2014/10/21 09:22:09
Done.
| |
217 DCHECK(thread_checker_.CalledOnValidThread()); | |
218 DCHECK(private_slot); | |
219 | |
220 private_slot_ = private_slot.Pass(); | |
221 RunNextStep(GOT_PRIVATE_SLOT_FOR_USER); | |
222 } | |
223 | |
224 void OnSystemTPMTokenReady(bool system_tpm_token_enabled) { | |
225 if (!use_system_key_slot_) | |
226 return; | |
227 if (system_tpm_token_enabled) | |
228 system_tpm_token_status_ = SYSTEM_TPM_TOKEN_STATUS_ENABLED; | |
229 else | |
230 system_tpm_token_status_ = SYSTEM_TPM_TOKEN_STATUS_DISABLED; | |
231 if (state_ == WAITING_FOR_SYSTEM_TPM_TOKEN) | |
232 RunNextStep(SYSTEM_TPM_TOKEN_READY); | |
233 } | |
234 | |
235 void GetSystemSlot() { | |
236 if (!use_system_key_slot_ || | |
237 system_tpm_token_status_ == SYSTEM_TPM_TOKEN_STATUS_DISABLED) { | |
238 VLOG(2) << "Skip system key slot initialization"; | |
239 RunNextStep(GOT_SYSTEM_SLOT); | |
240 return; | |
241 } | |
242 | |
243 base::Callback<void(crypto::ScopedPK11Slot)> callback = base::Bind( | |
244 &Internal::GetSystemSlotDONE, weak_ptr_factory_.GetWeakPtr()); | |
245 | |
246 crypto::ScopedPK11Slot system_slot = crypto::GetSystemNSSKeySlot(callback); | |
247 if (system_slot) | |
248 callback.Run(system_slot.Pass()); | |
249 } | |
250 | |
251 void GetSystemSlotDONE(crypto::ScopedPK11Slot system_slot) { | |
252 if (!system_slot) | |
253 LOG(ERROR) << "Could not get the system key slot."; | |
254 system_slot_ = system_slot.Pass(); | |
255 RunNextStep(GOT_SYSTEM_SLOT); | |
256 } | |
257 | |
258 void CreateCertDatabase() { | |
259 crypto::ScopedPK11Slot public_slot = | |
260 crypto::GetPublicSlotForChromeOSUser(username_hash_); | |
261 | |
262 scoped_ptr<net::NSSCertDatabaseChromeOS> db( | |
263 new net::NSSCertDatabaseChromeOS(public_slot.Pass(), | |
264 private_slot_.Pass())); | |
265 if (system_slot_) | |
266 db->SetSystemSlot(system_slot_.Pass()); | |
267 | |
268 io_part_->DidCreateNSSCertDatabase(db.PassAs<net::NSSCertDatabase>()); | |
mattm
2014/10/18 00:45:16
can use Pass() now
pneubeck (no reviews)
2014/10/21 09:22:09
Done.
| |
269 FinishWithState(CREATED_NSS_CERTDB); | |
270 } | |
271 | |
272 const std::string user_email_; | |
273 const std::string username_hash_; | |
274 bool use_system_key_slot_; | |
275 const base::FilePath path_; | |
276 scoped_refptr<base::SequencedTaskRunner> dbus_task_runner_; | |
277 State state_; | |
278 crypto::ScopedPK11Slot private_slot_; | |
279 SystemTPMTokenStatus system_tpm_token_status_; | |
280 crypto::ScopedPK11Slot system_slot_; | |
281 chromeos::CryptohomeClient* cryptohome_client_; | |
282 CertDatabaseServiceIOPartChromeOS* io_part_; | |
283 base::ThreadChecker thread_checker_; | |
284 base::WeakPtrFactory<Internal> weak_ptr_factory_; | |
285 | |
286 DISALLOW_COPY_AND_ASSIGN(Internal); | |
287 }; | |
288 | |
289 CertDatabaseServiceIOPartChromeOS::CertDatabaseServiceIOPartChromeOS( | |
290 const std::string& user_email, | |
291 const std::string& username_hash, | |
292 bool use_system_key_slot, | |
293 const base::FilePath& path, | |
294 const scoped_refptr<base::SequencedTaskRunner>& dbus_task_runner, | |
295 chromeos::CryptohomeClient* cryptohome_client) | |
296 : internal_(new Internal(user_email, | |
297 username_hash, | |
298 use_system_key_slot, | |
299 path, | |
300 dbus_task_runner, | |
301 cryptohome_client, | |
302 this)) { | |
303 } | |
304 | |
305 CertDatabaseServiceIOPartChromeOS::~CertDatabaseServiceIOPartChromeOS() { | |
306 DCHECK(thread_checker_.CalledOnValidThread()); | |
307 } | |
308 | |
309 void CertDatabaseServiceIOPartChromeOS::Init() { | |
310 CertDatabaseServiceIOPart::Init(); | |
311 | |
312 internal_->Run(); | |
313 } | |
314 | |
315 void CertDatabaseServiceIOPartChromeOS::DidCreateNSSCertDatabase( | |
316 scoped_ptr<net::NSSCertDatabase> db) { | |
317 internal_.reset(); | |
318 CertDatabaseServiceIOPart::DidCreateNSSCertDatabase(db.Pass()); | |
319 } | |
320 | |
321 CertDatabaseServiceIOPartChromeOS::SystemTPMTokenReadyCallback | |
322 CertDatabaseServiceIOPartChromeOS::GetSystemTPMTokenReadyCallback() { | |
323 return base::Bind( | |
324 &OnSystemTPMTokenReady, GetWeakPtr(), base::Unretained(this)); | |
325 } | |
326 | |
327 // static | |
328 void CertDatabaseServiceIOPartChromeOS::OnSystemTPMTokenReady( | |
329 const base::WeakPtr<CertDatabaseServiceIOPart>& weak_ptr, | |
330 CertDatabaseServiceIOPartChromeOS* io_part, | |
331 bool system_tpm_token_enabled) { | |
332 if (!weak_ptr) | |
333 return; | |
334 CHECK_EQ(io_part, weak_ptr.get()); | |
335 | |
336 io_part->internal_->OnSystemTPMTokenReady(system_tpm_token_enabled); | |
337 } | |
338 | |
339 } // namespace cert_database | |
OLD | NEW |