OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/cros/cert_library.h" | 5 #include "chrome/browser/chromeos/cros/cert_library.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/memory/weak_ptr.h" | 10 #include "base/memory/weak_ptr.h" |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
88 issued_to, | 88 issued_to, |
89 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED)); | 89 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED)); |
90 } else { | 90 } else { |
91 return l10n_util::GetStringFUTF16( | 91 return l10n_util::GetStringFUTF16( |
92 IDS_CERT_MANAGER_KEY_FORMAT_LONG, | 92 IDS_CERT_MANAGER_KEY_FORMAT_LONG, |
93 issued_by, | 93 issued_by, |
94 issued_to); | 94 issued_to); |
95 } | 95 } |
96 } | 96 } |
97 | 97 |
98 class RealTPMTokenInfoDelegate : public crypto::TPMTokenInfoDelegate { | |
99 public: | |
100 RealTPMTokenInfoDelegate(); | |
101 virtual ~RealTPMTokenInfoDelegate(); | |
102 | |
103 // TPMTokenInfoDeleagte overrides: | |
104 virtual void RequestIsTokenReady( | |
105 base::Callback<void(bool result)> callback) const OVERRIDE; | |
106 virtual void GetTokenInfo(std::string* token_name, | |
107 std::string* user_pin) const OVERRIDE; | |
108 | |
109 private: | |
110 // This method is used to implement RequestIsTokenReady. | |
111 void OnPkcs11IsTpmTokenReady(base::Callback<void(bool result)> callback, | |
112 DBusMethodCallStatus call_status, | |
113 bool is_tpm_token_ready) const; | |
114 | |
115 // This method is used to implement RequestIsTokenReady. | |
116 void OnPkcs11GetTpmTokenInfo(base::Callback<void(bool result)> callback, | |
117 DBusMethodCallStatus call_status, | |
118 const std::string& token_name, | |
119 const std::string& user_pin) const; | |
120 | |
121 // These are mutable since we need to cache them in IsTokenReady(). | |
122 mutable bool token_ready_; | |
123 mutable std::string token_name_; | |
124 mutable std::string user_pin_; | |
125 mutable base::WeakPtrFactory<RealTPMTokenInfoDelegate> weak_ptr_factory_; | |
126 }; | |
127 | |
128 RealTPMTokenInfoDelegate::RealTPMTokenInfoDelegate() : token_ready_(false), | |
129 weak_ptr_factory_(this) { | |
130 } | |
131 | |
132 RealTPMTokenInfoDelegate::~RealTPMTokenInfoDelegate() {} | |
133 | |
134 void RealTPMTokenInfoDelegate::RequestIsTokenReady( | |
135 base::Callback<void(bool result)> callback) const { | |
136 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
137 if (token_ready_) { | |
138 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
139 base::Bind(callback, true)); | |
140 return; | |
141 } | |
142 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11IsTpmTokenReady( | |
143 base::Bind(&RealTPMTokenInfoDelegate::OnPkcs11IsTpmTokenReady, | |
144 weak_ptr_factory_.GetWeakPtr(), | |
145 callback)); | |
146 } | |
147 | |
148 void RealTPMTokenInfoDelegate::GetTokenInfo(std::string* token_name, | |
149 std::string* user_pin) const { | |
150 // May be called from a non UI thread, but must only be called after | |
151 // IsTokenReady() returns true. | |
152 CHECK(token_ready_); | |
153 if (token_name) | |
154 *token_name = token_name_; | |
155 if (user_pin) | |
156 *user_pin = user_pin_; | |
157 } | |
158 | |
159 void RealTPMTokenInfoDelegate::OnPkcs11IsTpmTokenReady( | |
160 base::Callback<void(bool result)> callback, | |
161 DBusMethodCallStatus call_status, | |
162 bool is_tpm_token_ready) const { | |
163 if (call_status != DBUS_METHOD_CALL_SUCCESS || !is_tpm_token_ready) { | |
164 callback.Run(false); | |
165 return; | |
166 } | |
167 | |
168 // Retrieve token_name_ and user_pin_ here since they will never change | |
169 // and CryptohomeClient calls are not thread safe. | |
170 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11GetTpmTokenInfo( | |
171 base::Bind(&RealTPMTokenInfoDelegate::OnPkcs11GetTpmTokenInfo, | |
172 weak_ptr_factory_.GetWeakPtr(), | |
173 callback)); | |
174 } | |
175 | |
176 void RealTPMTokenInfoDelegate::OnPkcs11GetTpmTokenInfo( | |
177 base::Callback<void(bool result)> callback, | |
178 DBusMethodCallStatus call_status, | |
179 const std::string& token_name, | |
180 const std::string& user_pin) const { | |
181 if (call_status == DBUS_METHOD_CALL_SUCCESS) { | |
182 token_name_ = token_name; | |
183 user_pin_ = user_pin; | |
184 token_ready_ = true; | |
185 } | |
186 callback.Run(token_ready_); | |
187 } | |
188 | |
189 } // namespace | 98 } // namespace |
190 | 99 |
191 ////////////////////////////////////////////////////////////////////////////// | 100 ////////////////////////////////////////////////////////////////////////////// |
192 | 101 |
193 // base::Unretained(this) in the class is safe. By the time this object is | 102 // base::Unretained(this) in the class is safe. By the time this object is |
194 // deleted as part of CrosLibrary, the DB thread and the UI message loop | 103 // deleted as part of CrosLibrary, the DB thread and the UI message loop |
195 // are already terminated. | 104 // are already terminated. |
196 class CertLibraryImpl | 105 class CertLibraryImpl |
197 : public CertLibrary, | 106 : public CertLibrary, |
198 public net::CertDatabase::Observer { | 107 public net::CertDatabase::Observer { |
199 public: | 108 public: |
200 typedef ObserverListThreadSafe<CertLibrary::Observer> CertLibraryObserverList; | 109 typedef ObserverListThreadSafe<CertLibrary::Observer> CertLibraryObserverList; |
201 | 110 |
202 CertLibraryImpl() : | 111 CertLibraryImpl() : |
203 observer_list_(new CertLibraryObserverList), | 112 observer_list_(new CertLibraryObserverList), |
113 tpm_token_ready_(false), | |
204 user_logged_in_(false), | 114 user_logged_in_(false), |
205 certificates_requested_(false), | 115 certificates_requested_(false), |
206 certificates_loaded_(false), | 116 certificates_loaded_(false), |
207 key_store_loaded_(false), | 117 key_store_loaded_(false), |
208 ALLOW_THIS_IN_INITIALIZER_LIST(certs_(this)), | 118 ALLOW_THIS_IN_INITIALIZER_LIST(certs_(this)), |
209 ALLOW_THIS_IN_INITIALIZER_LIST(user_certs_(this)), | 119 ALLOW_THIS_IN_INITIALIZER_LIST(user_certs_(this)), |
210 ALLOW_THIS_IN_INITIALIZER_LIST(server_certs_(this)), | 120 ALLOW_THIS_IN_INITIALIZER_LIST(server_certs_(this)), |
211 ALLOW_THIS_IN_INITIALIZER_LIST(server_ca_certs_(this)), | 121 ALLOW_THIS_IN_INITIALIZER_LIST(server_ca_certs_(this)), |
212 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { | 122 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { |
213 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) | 123 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) |
(...skipping 25 matching lines...) Expand all Loading... | |
239 | 149 |
240 // Only load the Opencryptoki library into NSS if we have this switch. | 150 // Only load the Opencryptoki library into NSS if we have this switch. |
241 // TODO(gspencer): Remove this switch once cryptohomed work is finished: | 151 // TODO(gspencer): Remove this switch once cryptohomed work is finished: |
242 // http://crosbug.com/12295 and 12304 | 152 // http://crosbug.com/12295 and 12304 |
243 // Note: ChromeOS login with or without loginmanager will crash when | 153 // Note: ChromeOS login with or without loginmanager will crash when |
244 // the CertLibrary is not there (http://crosbug.com/121456). Before removing | 154 // the CertLibrary is not there (http://crosbug.com/121456). Before removing |
245 // make sure that that case still works. | 155 // make sure that that case still works. |
246 if (CommandLine::ForCurrentProcess()->HasSwitch( | 156 if (CommandLine::ForCurrentProcess()->HasSwitch( |
247 switches::kLoadOpencryptoki) || | 157 switches::kLoadOpencryptoki) || |
248 CommandLine::ForCurrentProcess()->HasSwitch(switches::kStubCros)) { | 158 CommandLine::ForCurrentProcess()->HasSwitch(switches::kStubCros)) { |
249 crypto::EnableTPMTokenForNSS(new RealTPMTokenInfoDelegate()); | 159 crypto::EnableTPMTokenForNSS(); |
Ryan Sleevi
2012/05/16 17:02:16
See comments in crypto/
| |
250 // Note: this calls crypto::EnsureTPMTokenReady() | 160 // Note: this calls crypto::EnsureTPMTokenReady() |
251 RequestCertificates(); | 161 RequestCertificates(); |
252 } | 162 } |
253 key_store_loaded_ = true; | 163 key_store_loaded_ = true; |
254 } | 164 } |
255 | 165 |
256 virtual bool CertificatesLoading() const OVERRIDE { | 166 virtual bool CertificatesLoading() const OVERRIDE { |
257 return certificates_requested_ && !certificates_loaded_; | 167 return certificates_requested_ && !certificates_loaded_; |
258 } | 168 } |
259 | 169 |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
380 string16 rhs_name = GetDisplayString(rhs.get(), false); | 290 string16 rhs_name = GetDisplayString(rhs.get(), false); |
381 if (collator_ == NULL) | 291 if (collator_ == NULL) |
382 return lhs_name < rhs_name; | 292 return lhs_name < rhs_name; |
383 return l10n_util::CompareString16WithCollator( | 293 return l10n_util::CompareString16WithCollator( |
384 collator_, lhs_name, rhs_name) == UCOL_LESS; | 294 collator_, lhs_name, rhs_name) == UCOL_LESS; |
385 } | 295 } |
386 private: | 296 private: |
387 icu::Collator* collator_; | 297 icu::Collator* collator_; |
388 }; | 298 }; |
389 | 299 |
390 void RequestCertificatesTask() { | |
391 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) | |
392 << __FUNCTION__ << " should be called on UI thread."; | |
393 // Reset the task to the initial state so is_null() returns true. | |
394 request_task_ = base::Closure(); | |
395 RequestCertificates(); | |
396 } | |
397 | |
398 void NotifyCertificatesLoaded(bool initial_load) { | 300 void NotifyCertificatesLoaded(bool initial_load) { |
399 observer_list_->Notify( | 301 observer_list_->Notify( |
400 &CertLibrary::Observer::OnCertificatesLoaded, initial_load); | 302 &CertLibrary::Observer::OnCertificatesLoaded, initial_load); |
401 } | 303 } |
402 | 304 |
403 // |cert_list| is allocated in LoadCertificates() and must be deleted here. | 305 // |cert_list| is allocated in LoadCertificates() and must be deleted here. |
404 void UpdateCertificates(net::CertificateList* cert_list) { | 306 void UpdateCertificates(net::CertificateList* cert_list) { |
405 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) | 307 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) |
406 << __FUNCTION__ << " should be called on UI thread."; | 308 << __FUNCTION__ << " should be called on UI thread."; |
407 DCHECK(cert_list); | 309 DCHECK(cert_list); |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
499 } | 401 } |
500 | 402 |
501 if (!user_logged_in_) { | 403 if (!user_logged_in_) { |
502 user_logged_in_ = true; | 404 user_logged_in_ = true; |
503 certificates_loaded_ = false; | 405 certificates_loaded_ = false; |
504 supplemental_user_key_.reset(NULL); | 406 supplemental_user_key_.reset(NULL); |
505 } | 407 } |
506 | 408 |
507 VLOG(1) << "Requesting Certificates."; | 409 VLOG(1) << "Requesting Certificates."; |
508 DBusThreadManager::Get()->GetCryptohomeClient()->TpmIsEnabled( | 410 DBusThreadManager::Get()->GetCryptohomeClient()->TpmIsEnabled( |
509 base::Bind(&CertLibraryImpl::RequestCertificatesInternal, | 411 base::Bind(&CertLibraryImpl::OnTpmIsEnabled, |
510 weak_ptr_factory_.GetWeakPtr())); | 412 weak_ptr_factory_.GetWeakPtr())); |
511 } | 413 } |
512 | 414 |
513 // This method is used to implement RequestCertificates. | 415 // This method is used to implement RequestCertificates. |
514 void RequestCertificatesInternal(DBusMethodCallStatus call_status, | 416 void OnTpmIsEnabled(DBusMethodCallStatus call_status, bool tpm_is_enabled) { |
515 bool tpm_is_enabled) { | |
516 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) | 417 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) |
517 << __FUNCTION__ << " should be called on UI thread."; | 418 << __FUNCTION__ << " should be called on UI thread."; |
518 if (call_status != DBUS_METHOD_CALL_SUCCESS || !tpm_is_enabled) { | 419 if (call_status != DBUS_METHOD_CALL_SUCCESS || !tpm_is_enabled) { |
519 // TPM is not enabled, so proceed with empty tpm token name. | 420 // TPM is not enabled, so proceed with empty tpm token name. |
520 VLOG(1) << "TPM not available."; | 421 VLOG(1) << "TPM not available."; |
521 BrowserThread::PostTask( | 422 BrowserThread::PostTask( |
522 BrowserThread::DB, FROM_HERE, | 423 BrowserThread::DB, FROM_HERE, |
523 base::Bind(&CertLibraryImpl::LoadCertificates, | 424 base::Bind(&CertLibraryImpl::LoadCertificates, |
524 base::Unretained(this))); | 425 base::Unretained(this))); |
525 } else if (crypto::IsTPMTokenReady()) { | 426 } else if (tpm_token_ready_) { |
526 // Need TPM token name to filter user certificates. | 427 InitializeTPMToken(); |
527 const bool tpm_token_ready = true; | |
528 GetTPMTokenName(tpm_token_ready); | |
529 } else { | 428 } else { |
530 crypto::InitializeTPMToken( | 429 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11IsTpmTokenReady( |
531 base::Bind(&CertLibraryImpl::GetTPMTokenName, | 430 base::Bind(&CertLibraryImpl::OnPkcs11IsTpmTokenReady, |
532 weak_ptr_factory_.GetWeakPtr())); | 431 weak_ptr_factory_.GetWeakPtr())); |
533 } | 432 } |
534 } | 433 } |
535 | 434 |
536 // This method is used to implement RequestCertificates. | 435 // This method is used to implement RequestCertificates. |
537 void GetTPMTokenName(bool tpm_token_ready) { | 436 void OnPkcs11IsTpmTokenReady(DBusMethodCallStatus call_status, |
538 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) | 437 bool is_tpm_token_ready) { |
539 << __FUNCTION__ << " should be called on UI thread."; | 438 if (call_status != DBUS_METHOD_CALL_SUCCESS || !is_tpm_token_ready) { |
540 if (tpm_token_ready) { | 439 MaybeRetryRequestCertificates(); |
541 std::string unused_pin; | |
542 crypto::GetTPMTokenInfo(&tpm_token_name_, &unused_pin); | |
543 } else { | |
544 VLOG(1) << "TPM token not ready."; | |
545 if (request_task_.is_null()) { | |
546 // Cryptohome does not notify us when the token is ready, so call | |
547 // this again after a delay. | |
548 request_task_ = base::Bind(&CertLibraryImpl::RequestCertificatesTask, | |
549 weak_ptr_factory_.GetWeakPtr()); | |
550 BrowserThread::PostDelayedTask( | |
551 BrowserThread::UI, FROM_HERE, request_task_, | |
552 base::TimeDelta::FromMilliseconds(kRequestDelayMs)); | |
553 } | |
554 return; | 440 return; |
555 } | 441 } |
556 | 442 |
443 // Retrieve token_name_ and user_pin_ here since they will never change | |
444 // and CryptohomeClient calls are not thread safe. | |
445 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11GetTpmTokenInfo( | |
446 base::Bind(&CertLibraryImpl::OnPkcs11GetTpmTokenInfo, | |
447 weak_ptr_factory_.GetWeakPtr())); | |
448 } | |
449 | |
450 // This method is used to implement RequestCertificates. | |
451 void OnPkcs11GetTpmTokenInfo(DBusMethodCallStatus call_status, | |
452 const std::string& token_name, | |
453 const std::string& user_pin) { | |
454 if (call_status != DBUS_METHOD_CALL_SUCCESS) { | |
455 MaybeRetryRequestCertificates(); | |
456 return; | |
457 } | |
458 tpm_token_name_ = token_name; | |
459 tpm_user_pin_ = user_pin; | |
460 tpm_token_ready_ = true; | |
461 | |
462 InitializeTPMToken(); | |
463 } | |
464 | |
465 // This method is used to implement RequestCertificates. | |
466 void InitializeTPMToken() { | |
467 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) | |
468 << __FUNCTION__ << " should be called on UI thread."; | |
Ryan Sleevi
2012/05/16 17:02:16
nit: These strings will not get optimized out in a
hashimoto
2012/05/17 07:35:07
Agree, CHECK itself is sufficient, removed the str
| |
469 if (!crypto::InitializeTPMToken(tpm_token_name_, tpm_user_pin_)) { | |
470 MaybeRetryRequestCertificates(); | |
471 return; | |
472 } | |
473 | |
557 // tpm_token_name_ is set, load the certificates on the DB thread. | 474 // tpm_token_name_ is set, load the certificates on the DB thread. |
558 BrowserThread::PostTask( | 475 BrowserThread::PostTask( |
559 BrowserThread::DB, FROM_HERE, | 476 BrowserThread::DB, FROM_HERE, |
560 base::Bind(&CertLibraryImpl::LoadCertificates, base::Unretained(this))); | 477 base::Bind(&CertLibraryImpl::LoadCertificates, base::Unretained(this))); |
561 } | 478 } |
562 | 479 |
480 void MaybeRetryRequestCertificates() { | |
481 if (!request_task_.is_null()) | |
482 return; | |
483 // Cryptohome does not notify us when the token is ready, so call | |
484 // this again after a delay. | |
485 request_task_ = base::Bind(&CertLibraryImpl::RequestCertificatesTask, | |
486 weak_ptr_factory_.GetWeakPtr()); | |
487 BrowserThread::PostDelayedTask( | |
488 BrowserThread::UI, FROM_HERE, request_task_, | |
489 base::TimeDelta::FromMilliseconds(kRequestDelayMs)); | |
490 } | |
491 | |
492 void RequestCertificatesTask() { | |
493 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) | |
494 << __FUNCTION__ << " should be called on UI thread."; | |
495 // Reset the task to the initial state so is_null() returns true. | |
496 request_task_ = base::Closure(); | |
497 RequestCertificates(); | |
498 } | |
499 | |
563 // Observers. | 500 // Observers. |
564 const scoped_refptr<CertLibraryObserverList> observer_list_; | 501 const scoped_refptr<CertLibraryObserverList> observer_list_; |
565 | 502 |
566 // Active request task for re-requests while waiting for TPM init. | 503 // Active request task for re-requests while waiting for TPM init. |
567 base::Closure request_task_; | 504 base::Closure request_task_; |
568 | 505 |
506 bool tpm_token_ready_; | |
507 | |
569 // Cached TPM token name. | 508 // Cached TPM token name. |
570 std::string tpm_token_name_; | 509 std::string tpm_token_name_; |
571 | 510 |
511 // Cached TPM user pin. | |
512 std::string tpm_user_pin_; | |
513 | |
572 // Supplemental user key. | 514 // Supplemental user key. |
573 scoped_ptr<crypto::SymmetricKey> supplemental_user_key_; | 515 scoped_ptr<crypto::SymmetricKey> supplemental_user_key_; |
574 | 516 |
575 // Local state. | 517 // Local state. |
576 bool user_logged_in_; | 518 bool user_logged_in_; |
577 bool certificates_requested_; | 519 bool certificates_requested_; |
578 bool certificates_loaded_; | 520 bool certificates_loaded_; |
579 // The key store for the current user has been loaded. This flag is needed to | 521 // The key store for the current user has been loaded. This flag is needed to |
580 // ensure that the key store will not be loaded twice in the policy recovery | 522 // ensure that the key store will not be loaded twice in the policy recovery |
581 // "safe-mode". | 523 // "safe-mode". |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
655 net::X509Certificate* cert = GetCertificateAt(index); | 597 net::X509Certificate* cert = GetCertificateAt(index); |
656 net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); | 598 net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); |
657 std::string id = x509_certificate_model::GetPkcs11Id(cert_handle); | 599 std::string id = x509_certificate_model::GetPkcs11Id(cert_handle); |
658 if (id == pkcs11_id) | 600 if (id == pkcs11_id) |
659 return index; | 601 return index; |
660 } | 602 } |
661 return -1; // Not found. | 603 return -1; // Not found. |
662 } | 604 } |
663 | 605 |
664 } // chromeos | 606 } // chromeos |
OLD | NEW |