| 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/chromeos/chromeos_version.h" | 9 #include "base/chromeos/chromeos_version.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 #include "chromeos/login/login_state.h" | 22 #include "chromeos/login/login_state.h" |
| 23 #include "content/public/browser/browser_thread.h" | 23 #include "content/public/browser/browser_thread.h" |
| 24 #include "crypto/nss_util.h" | 24 #include "crypto/nss_util.h" |
| 25 #include "grit/generated_resources.h" | 25 #include "grit/generated_resources.h" |
| 26 #include "net/cert/cert_database.h" | 26 #include "net/cert/cert_database.h" |
| 27 #include "net/cert/nss_cert_database.h" | 27 #include "net/cert/nss_cert_database.h" |
| 28 #include "third_party/icu/public/i18n/unicode/coll.h" // icu::Collator | 28 #include "third_party/icu/public/i18n/unicode/coll.h" // icu::Collator |
| 29 #include "ui/base/l10n/l10n_util.h" | 29 #include "ui/base/l10n/l10n_util.h" |
| 30 #include "ui/base/l10n/l10n_util_collator.h" | 30 #include "ui/base/l10n/l10n_util_collator.h" |
| 31 | 31 |
| 32 using content::BrowserThread; | |
| 33 | |
| 34 namespace chromeos { | 32 namespace chromeos { |
| 35 | 33 |
| 36 namespace { | 34 namespace { |
| 37 | 35 |
| 38 // Root CA certificates that are built into Chrome use this token name. | 36 // Root CA certificates that are built into Chrome use this token name. |
| 39 const char kRootCertificateTokenName[] = "Builtin Object Token"; | 37 const char kRootCertificateTokenName[] = "Builtin Object Token"; |
| 40 | 38 |
| 41 // Delay between certificate requests while waiting for TPM/PKCS#11 init. | |
| 42 const int kRequestDelayMs = 500; | |
| 43 | |
| 44 string16 GetDisplayString(net::X509Certificate* cert, bool hardware_backed) { | 39 string16 GetDisplayString(net::X509Certificate* cert, bool hardware_backed) { |
| 45 std::string org; | 40 std::string org; |
| 46 if (!cert->subject().organization_names.empty()) | 41 if (!cert->subject().organization_names.empty()) |
| 47 org = cert->subject().organization_names[0]; | 42 org = cert->subject().organization_names[0]; |
| 48 if (org.empty()) | 43 if (org.empty()) |
| 49 org = cert->subject().GetDisplayName(); | 44 org = cert->subject().GetDisplayName(); |
| 50 string16 issued_by = UTF8ToUTF16( | 45 string16 issued_by = UTF8ToUTF16( |
| 51 x509_certificate_model::GetIssuerCommonName(cert->os_cert_handle(), | 46 x509_certificate_model::GetIssuerCommonName(cert->os_cert_handle(), |
| 52 org)); // alternative text | 47 org)); // alternative text |
| 53 string16 issued_to = UTF8ToUTF16( | 48 string16 issued_to = UTF8ToUTF16( |
| 54 x509_certificate_model::GetCertNameOrNickname(cert->os_cert_handle())); | 49 x509_certificate_model::GetCertNameOrNickname(cert->os_cert_handle())); |
| 55 | 50 |
| 56 if (hardware_backed) { | 51 if (hardware_backed) { |
| 57 return l10n_util::GetStringFUTF16( | 52 return l10n_util::GetStringFUTF16( |
| 58 IDS_CERT_MANAGER_HARDWARE_BACKED_KEY_FORMAT_LONG, | 53 IDS_CERT_MANAGER_HARDWARE_BACKED_KEY_FORMAT_LONG, |
| 59 issued_by, | 54 issued_by, |
| 60 issued_to, | 55 issued_to, |
| 61 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED)); | 56 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED)); |
| 62 } else { | 57 } else { |
| 63 return l10n_util::GetStringFUTF16( | 58 return l10n_util::GetStringFUTF16( |
| 64 IDS_CERT_MANAGER_KEY_FORMAT_LONG, | 59 IDS_CERT_MANAGER_KEY_FORMAT_LONG, |
| 65 issued_by, | 60 issued_by, |
| 66 issued_to); | 61 issued_to); |
| 67 } | 62 } |
| 68 } | 63 } |
| 69 | 64 |
| 70 } // namespace | 65 } // namespace |
| 71 | 66 |
| 72 ////////////////////////////////////////////////////////////////////////////// | 67 class CertNameComparator { |
| 73 | |
| 74 // base::Unretained(this) in the class is safe. By the time this object is | |
| 75 // deleted as part of CrosLibrary, the DB thread and the UI message loop | |
| 76 // are already terminated. | |
| 77 class CertLibraryImpl | |
| 78 : public CertLibrary, | |
| 79 public net::CertDatabase::Observer { | |
| 80 public: | 68 public: |
| 81 typedef ObserverListThreadSafe<CertLibrary::Observer> CertLibraryObserverList; | 69 explicit CertNameComparator(icu::Collator* collator) |
| 82 | 70 : collator_(collator) { |
| 83 CertLibraryImpl() : | |
| 84 observer_list_(new CertLibraryObserverList), | |
| 85 tpm_token_ready_(false), | |
| 86 user_logged_in_(false), | |
| 87 certificates_requested_(false), | |
| 88 certificates_loaded_(false), | |
| 89 key_store_loaded_(false), | |
| 90 certs_(this), | |
| 91 user_certs_(this), | |
| 92 server_certs_(this), | |
| 93 server_ca_certs_(this), | |
| 94 weak_ptr_factory_(this) { | |
| 95 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 96 net::CertDatabase::GetInstance()->AddObserver(this); | |
| 97 } | 71 } |
| 98 | 72 |
| 99 virtual ~CertLibraryImpl() { | 73 bool operator()(const scoped_refptr<net::X509Certificate>& lhs, |
| 100 DCHECK(request_task_.is_null()); | 74 const scoped_refptr<net::X509Certificate>& rhs) const { |
| 101 net::CertDatabase::GetInstance()->RemoveObserver(this); | 75 string16 lhs_name = GetDisplayString(lhs.get(), false); |
| 102 } | 76 string16 rhs_name = GetDisplayString(rhs.get(), false); |
| 103 | 77 if (collator_ == NULL) |
| 104 // CertLibrary implementation. | 78 return lhs_name < rhs_name; |
| 105 virtual void AddObserver(CertLibrary::Observer* observer) OVERRIDE { | 79 return base::i18n::CompareString16WithCollator( |
| 106 observer_list_->AddObserver(observer); | 80 collator_, lhs_name, rhs_name) == UCOL_LESS; |
| 107 } | |
| 108 | |
| 109 virtual void RemoveObserver(CertLibrary::Observer* observer) OVERRIDE { | |
| 110 observer_list_->RemoveObserver(observer); | |
| 111 } | |
| 112 | |
| 113 virtual void LoadKeyStore() OVERRIDE { | |
| 114 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 115 if (key_store_loaded_) | |
| 116 return; | |
| 117 | |
| 118 // Ensure we've opened the real user's key/certificate database. | |
| 119 crypto::OpenPersistentNSSDB(); | |
| 120 | |
| 121 if (base::chromeos::IsRunningOnChromeOS() || | |
| 122 CommandLine::ForCurrentProcess()->HasSwitch( | |
| 123 switches::kLoadOpencryptoki)) { | |
| 124 crypto::EnableTPMTokenForNSS(); | |
| 125 // Note: this calls crypto::EnsureTPMTokenReady() | |
| 126 RequestCertificates(); | |
| 127 } | |
| 128 key_store_loaded_ = true; | |
| 129 } | |
| 130 | |
| 131 virtual bool CertificatesLoading() const OVERRIDE { | |
| 132 return certificates_requested_ && !certificates_loaded_; | |
| 133 } | |
| 134 | |
| 135 virtual bool CertificatesLoaded() const OVERRIDE { | |
| 136 return certificates_loaded_; | |
| 137 } | |
| 138 | |
| 139 virtual bool IsHardwareBacked() const OVERRIDE { | |
| 140 return !tpm_token_name_.empty(); | |
| 141 } | |
| 142 | |
| 143 virtual const CertList& GetCertificates() const OVERRIDE { | |
| 144 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 145 return certs_; | |
| 146 } | |
| 147 | |
| 148 virtual const CertList& GetUserCertificates() const OVERRIDE { | |
| 149 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 150 return user_certs_; | |
| 151 } | |
| 152 | |
| 153 virtual const CertList& GetServerCertificates() const OVERRIDE { | |
| 154 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 155 return server_certs_; | |
| 156 } | |
| 157 | |
| 158 virtual const CertList& GetCACertificates() const OVERRIDE { | |
| 159 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 160 return server_ca_certs_; | |
| 161 } | |
| 162 | |
| 163 // net::CertDatabase::Observer implementation. Observer added on UI thread. | |
| 164 virtual void OnCertTrustChanged(const net::X509Certificate* cert) OVERRIDE { | |
| 165 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 166 } | |
| 167 | |
| 168 virtual void OnCertAdded(const net::X509Certificate* cert) OVERRIDE { | |
| 169 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 170 // Only load certificates if we have completed an initial request. | |
| 171 if (certificates_loaded_) { | |
| 172 BrowserThread::PostTask( | |
| 173 BrowserThread::DB, FROM_HERE, | |
| 174 base::Bind(&CertLibraryImpl::LoadCertificates, | |
| 175 base::Unretained(this))); | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 virtual void OnCertRemoved(const net::X509Certificate* cert) OVERRIDE { | |
| 180 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 181 // Only load certificates if we have completed an initial request. | |
| 182 if (certificates_loaded_) { | |
| 183 BrowserThread::PostTask( | |
| 184 BrowserThread::DB, FROM_HERE, | |
| 185 base::Bind(&CertLibraryImpl::LoadCertificates, | |
| 186 base::Unretained(this))); | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 virtual const std::string& GetTpmTokenName() const OVERRIDE { | |
| 191 return tpm_token_name_; | |
| 192 } | 81 } |
| 193 | 82 |
| 194 private: | 83 private: |
| 195 void LoadCertificates() { | 84 icu::Collator* collator_; |
| 196 VLOG(1) << " Loading Certificates."; | |
| 197 // Certificate fetch occurs on the DB thread. | |
| 198 CHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); | |
| 199 net::CertificateList* cert_list = new net::CertificateList(); | |
| 200 net::NSSCertDatabase::GetInstance()->ListCerts(cert_list); | |
| 201 // Pass the list to the UI thread to safely update the local lists. | |
| 202 BrowserThread::PostTask( | |
| 203 BrowserThread::UI, FROM_HERE, | |
| 204 base::Bind(&CertLibraryImpl::UpdateCertificates, | |
| 205 base::Unretained(this), cert_list)); | |
| 206 } | |
| 207 | |
| 208 // Comparison functor for locale-sensitive sorting of certificates by name. | |
| 209 class CertNameComparator { | |
| 210 public: | |
| 211 explicit CertNameComparator(icu::Collator* collator) | |
| 212 : collator_(collator) { } | |
| 213 | |
| 214 bool operator()(const scoped_refptr<net::X509Certificate>& lhs, | |
| 215 const scoped_refptr<net::X509Certificate>& rhs) const { | |
| 216 string16 lhs_name = GetDisplayString(lhs.get(), false); | |
| 217 string16 rhs_name = GetDisplayString(rhs.get(), false); | |
| 218 if (collator_ == NULL) | |
| 219 return lhs_name < rhs_name; | |
| 220 return base::i18n::CompareString16WithCollator( | |
| 221 collator_, lhs_name, rhs_name) == UCOL_LESS; | |
| 222 } | |
| 223 private: | |
| 224 icu::Collator* collator_; | |
| 225 }; | |
| 226 | |
| 227 void NotifyCertificatesLoaded(bool initial_load) { | |
| 228 observer_list_->Notify( | |
| 229 &CertLibrary::Observer::OnCertificatesLoaded, initial_load); | |
| 230 } | |
| 231 | |
| 232 // |cert_list| is allocated in LoadCertificates() and must be deleted here. | |
| 233 void UpdateCertificates(net::CertificateList* cert_list) { | |
| 234 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 235 DCHECK(cert_list); | |
| 236 | |
| 237 // Clear any existing certificates. | |
| 238 certs_.Clear(); | |
| 239 server_ca_certs_.Clear(); | |
| 240 user_certs_.Clear(); | |
| 241 server_certs_.Clear(); | |
| 242 | |
| 243 // Add certificates to the appropriate list. | |
| 244 for (net::CertificateList::const_iterator iter = cert_list->begin(); | |
| 245 iter != cert_list->end(); ++iter) { | |
| 246 certs_.Append(iter->get()); | |
| 247 net::X509Certificate::OSCertHandle cert_handle = | |
| 248 iter->get()->os_cert_handle(); | |
| 249 net::CertType type = x509_certificate_model::GetType(cert_handle); | |
| 250 switch (type) { | |
| 251 case net::USER_CERT: | |
| 252 user_certs_.Append(iter->get()); | |
| 253 break; | |
| 254 case net::SERVER_CERT: | |
| 255 server_certs_.Append(iter->get()); | |
| 256 break; | |
| 257 case net::CA_CERT: { | |
| 258 // Exclude root CA certificates that are built into Chrome. | |
| 259 std::string token_name = | |
| 260 x509_certificate_model::GetTokenName(cert_handle); | |
| 261 if (token_name != kRootCertificateTokenName) | |
| 262 server_ca_certs_.Append(iter->get()); | |
| 263 break; | |
| 264 } | |
| 265 default: | |
| 266 break; | |
| 267 } | |
| 268 } | |
| 269 | |
| 270 // Perform locale-sensitive sorting by certificate name. | |
| 271 scoped_ptr<icu::Collator> collator; | |
| 272 UErrorCode error = U_ZERO_ERROR; | |
| 273 collator.reset( | |
| 274 icu::Collator::createInstance( | |
| 275 icu::Locale(g_browser_process->GetApplicationLocale().c_str()), | |
| 276 error)); | |
| 277 if (U_FAILURE(error)) | |
| 278 collator.reset(NULL); | |
| 279 CertNameComparator cert_name_comparator(collator.get()); | |
| 280 std::sort(user_certs_.list().begin(), user_certs_.list().end(), | |
| 281 cert_name_comparator); | |
| 282 std::sort(server_certs_.list().begin(), server_certs_.list().end(), | |
| 283 cert_name_comparator); | |
| 284 std::sort(server_ca_certs_.list().begin(), server_ca_certs_.list().end(), | |
| 285 cert_name_comparator); | |
| 286 | |
| 287 // cert_list is allocated in LoadCertificates(), then released here. | |
| 288 delete cert_list; | |
| 289 | |
| 290 // Set loaded state and notify observers. | |
| 291 if (!certificates_loaded_) { | |
| 292 certificates_loaded_ = true; | |
| 293 NotifyCertificatesLoaded(true); | |
| 294 } else { | |
| 295 NotifyCertificatesLoaded(false); | |
| 296 } | |
| 297 } | |
| 298 | |
| 299 // Call this to start the certificate list initialization process. | |
| 300 // Must be called from the UI thread. | |
| 301 void RequestCertificates() { | |
| 302 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 303 | |
| 304 certificates_requested_ = true; | |
| 305 | |
| 306 if (!LoginState::Get()->IsUserLoggedIn()) { | |
| 307 // If we are not logged in, we cannot load any certificates. | |
| 308 // Set 'loaded' to true for the UI, since we are not waiting on loading. | |
| 309 LOG(WARNING) << "Requesting certificates before login."; | |
| 310 certificates_loaded_ = true; | |
| 311 return; | |
| 312 } | |
| 313 | |
| 314 if (!user_logged_in_) { | |
| 315 user_logged_in_ = true; | |
| 316 certificates_loaded_ = false; | |
| 317 } | |
| 318 | |
| 319 VLOG(1) << "Requesting Certificates."; | |
| 320 DBusThreadManager::Get()->GetCryptohomeClient()->TpmIsEnabled( | |
| 321 base::Bind(&CertLibraryImpl::OnTpmIsEnabled, | |
| 322 weak_ptr_factory_.GetWeakPtr())); | |
| 323 } | |
| 324 | |
| 325 // This method is used to implement RequestCertificates. | |
| 326 void OnTpmIsEnabled(DBusMethodCallStatus call_status, bool tpm_is_enabled) { | |
| 327 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 328 if (call_status != DBUS_METHOD_CALL_SUCCESS || !tpm_is_enabled) { | |
| 329 // TPM is not enabled, so proceed with empty tpm token name. | |
| 330 VLOG(1) << "TPM not available."; | |
| 331 BrowserThread::PostTask( | |
| 332 BrowserThread::DB, FROM_HERE, | |
| 333 base::Bind(&CertLibraryImpl::LoadCertificates, | |
| 334 base::Unretained(this))); | |
| 335 } else if (tpm_token_ready_) { | |
| 336 InitializeTPMToken(); | |
| 337 } else { | |
| 338 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11IsTpmTokenReady( | |
| 339 base::Bind(&CertLibraryImpl::OnPkcs11IsTpmTokenReady, | |
| 340 weak_ptr_factory_.GetWeakPtr())); | |
| 341 } | |
| 342 } | |
| 343 | |
| 344 // This method is used to implement RequestCertificates. | |
| 345 void OnPkcs11IsTpmTokenReady(DBusMethodCallStatus call_status, | |
| 346 bool is_tpm_token_ready) { | |
| 347 if (call_status != DBUS_METHOD_CALL_SUCCESS || !is_tpm_token_ready) { | |
| 348 MaybeRetryRequestCertificates(); | |
| 349 return; | |
| 350 } | |
| 351 | |
| 352 // Retrieve token_name_ and user_pin_ here since they will never change | |
| 353 // and CryptohomeClient calls are not thread safe. | |
| 354 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11GetTpmTokenInfo( | |
| 355 base::Bind(&CertLibraryImpl::OnPkcs11GetTpmTokenInfo, | |
| 356 weak_ptr_factory_.GetWeakPtr())); | |
| 357 } | |
| 358 | |
| 359 // This method is used to implement RequestCertificates. | |
| 360 void OnPkcs11GetTpmTokenInfo(DBusMethodCallStatus call_status, | |
| 361 const std::string& token_name, | |
| 362 const std::string& user_pin) { | |
| 363 if (call_status != DBUS_METHOD_CALL_SUCCESS) { | |
| 364 MaybeRetryRequestCertificates(); | |
| 365 return; | |
| 366 } | |
| 367 tpm_token_name_ = token_name; | |
| 368 tpm_user_pin_ = user_pin; | |
| 369 tpm_token_ready_ = true; | |
| 370 | |
| 371 InitializeTPMToken(); | |
| 372 } | |
| 373 | |
| 374 // This method is used to implement RequestCertificates. | |
| 375 void InitializeTPMToken() { | |
| 376 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 377 if (!crypto::InitializeTPMToken(tpm_token_name_, tpm_user_pin_)) { | |
| 378 MaybeRetryRequestCertificates(); | |
| 379 return; | |
| 380 } | |
| 381 | |
| 382 // tpm_token_name_ is set, load the certificates on the DB thread. | |
| 383 BrowserThread::PostTask( | |
| 384 BrowserThread::DB, FROM_HERE, | |
| 385 base::Bind(&CertLibraryImpl::LoadCertificates, base::Unretained(this))); | |
| 386 } | |
| 387 | |
| 388 void MaybeRetryRequestCertificates() { | |
| 389 if (!request_task_.is_null()) | |
| 390 return; | |
| 391 // Cryptohome does not notify us when the token is ready, so call | |
| 392 // this again after a delay. | |
| 393 request_task_ = base::Bind(&CertLibraryImpl::RequestCertificatesTask, | |
| 394 weak_ptr_factory_.GetWeakPtr()); | |
| 395 BrowserThread::PostDelayedTask( | |
| 396 BrowserThread::UI, FROM_HERE, request_task_, | |
| 397 base::TimeDelta::FromMilliseconds(kRequestDelayMs)); | |
| 398 } | |
| 399 | |
| 400 void RequestCertificatesTask() { | |
| 401 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 402 // Reset the task to the initial state so is_null() returns true. | |
| 403 request_task_ = base::Closure(); | |
| 404 RequestCertificates(); | |
| 405 } | |
| 406 | |
| 407 // Observers. | |
| 408 const scoped_refptr<CertLibraryObserverList> observer_list_; | |
| 409 | |
| 410 // Active request task for re-requests while waiting for TPM init. | |
| 411 base::Closure request_task_; | |
| 412 | |
| 413 bool tpm_token_ready_; | |
| 414 | |
| 415 // Cached TPM token name. | |
| 416 std::string tpm_token_name_; | |
| 417 | |
| 418 // Cached TPM user pin. | |
| 419 std::string tpm_user_pin_; | |
| 420 | |
| 421 // Local state. | |
| 422 bool user_logged_in_; | |
| 423 bool certificates_requested_; | |
| 424 bool certificates_loaded_; | |
| 425 // The key store for the current user has been loaded. This flag is needed to | |
| 426 // ensure that the key store will not be loaded twice in the policy recovery | |
| 427 // "safe-mode". | |
| 428 bool key_store_loaded_; | |
| 429 | |
| 430 // Certificates. | |
| 431 CertList certs_; | |
| 432 CertList user_certs_; | |
| 433 CertList server_certs_; | |
| 434 CertList server_ca_certs_; | |
| 435 | |
| 436 base::WeakPtrFactory<CertLibraryImpl> weak_ptr_factory_; | |
| 437 | |
| 438 DISALLOW_COPY_AND_ASSIGN(CertLibraryImpl); | |
| 439 }; | 85 }; |
| 440 | 86 |
| 441 ////////////////////////////////////////////////////////////////////////////// | 87 static CertLibrary* g_cert_library = NULL; |
| 442 | 88 |
| 443 class CertLibraryImplStub : public CertLibrary { | 89 // static |
| 444 public: | 90 void CertLibrary::Initialize() { |
| 445 CertLibraryImplStub() | 91 CHECK(!g_cert_library); |
| 446 : token_name_("StubToken"), | 92 g_cert_library = new CertLibrary(); |
| 447 cert_list_(this) { | |
| 448 } | |
| 449 virtual ~CertLibraryImplStub() {} | |
| 450 | |
| 451 virtual void AddObserver(Observer* observer) {} | |
| 452 virtual void RemoveObserver(Observer* observer) {} | |
| 453 virtual void LoadKeyStore() {} | |
| 454 virtual bool CertificatesLoading() const { | |
| 455 return false; | |
| 456 } | |
| 457 virtual bool CertificatesLoaded() const { | |
| 458 return true; | |
| 459 } | |
| 460 virtual bool IsHardwareBacked() const { | |
| 461 return false; | |
| 462 } | |
| 463 virtual const std::string& GetTpmTokenName() const { | |
| 464 return token_name_; | |
| 465 } | |
| 466 virtual const CertList& GetCertificates() const { | |
| 467 return cert_list_; | |
| 468 } | |
| 469 virtual const CertList& GetUserCertificates() const { | |
| 470 return cert_list_; | |
| 471 } | |
| 472 virtual const CertList& GetServerCertificates() const { | |
| 473 return cert_list_; | |
| 474 } | |
| 475 virtual const CertList& GetCACertificates() const { | |
| 476 return cert_list_; | |
| 477 } | |
| 478 | |
| 479 private: | |
| 480 std::string token_name_; | |
| 481 CertList cert_list_; | |
| 482 | |
| 483 DISALLOW_COPY_AND_ASSIGN(CertLibraryImplStub); | |
| 484 }; | |
| 485 | |
| 486 ////////////////////////////////////////////////////////////////////////////// | |
| 487 | |
| 488 CertLibrary::~CertLibrary() { | |
| 489 } | 93 } |
| 490 | 94 |
| 491 // static | 95 // static |
| 492 CertLibrary* CertLibrary::GetImpl(bool stub) { | 96 void CertLibrary::Shutdown() { |
| 493 // TODO(stevenjb): Disassociate CertLibrary from CrosLibrary entirely. | 97 CHECK(g_cert_library); |
| 494 // crbug.com/133752 | 98 delete g_cert_library; |
| 495 if (stub) | 99 g_cert_library = NULL; |
| 496 return new CertLibraryImplStub(); | |
| 497 return new CertLibraryImpl(); | |
| 498 } | 100 } |
| 499 | 101 |
| 500 ////////////////////////////////////////////////////////////////////////////// | 102 // static |
| 501 | 103 CertLibrary* CertLibrary::Get() { |
| 502 CertLibrary::CertList::CertList(CertLibrary* library) | 104 CHECK(g_cert_library) << "CertLibrary::Get() called before Initialize()"; |
| 503 : cert_library_(library) { | 105 return g_cert_library; |
| 504 } | 106 } |
| 505 | 107 |
| 506 CertLibrary::CertList::~CertList() {} | 108 // static |
| 507 | 109 bool CertLibrary::IsInitialized() { |
| 508 net::X509Certificate* CertLibrary::CertList::GetCertificateAt(int index) const { | 110 return g_cert_library; |
| 509 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 510 DCHECK_GE(index, 0); | |
| 511 DCHECK_LT(index, static_cast<int>(list_.size())); | |
| 512 return list_[index].get(); | |
| 513 } | 111 } |
| 514 | 112 |
| 515 string16 CertLibrary::CertList::GetDisplayStringAt(int index) const { | 113 CertLibrary::CertLibrary() { |
| 516 net::X509Certificate* cert = GetCertificateAt(index); | 114 CertLoader::Get()->AddObserver(this); |
| 115 } |
| 116 |
| 117 CertLibrary::~CertLibrary() { |
| 118 CertLoader::Get()->RemoveObserver(this); |
| 119 } |
| 120 |
| 121 void CertLibrary::AddObserver(CertLibrary::Observer* observer) { |
| 122 observer_list_.AddObserver(observer); |
| 123 } |
| 124 |
| 125 void CertLibrary::RemoveObserver(CertLibrary::Observer* observer) { |
| 126 observer_list_.RemoveObserver(observer); |
| 127 } |
| 128 |
| 129 bool CertLibrary::CertificatesLoading() const { |
| 130 return CertLoader::Get()->CertificatesLoading(); |
| 131 } |
| 132 |
| 133 bool CertLibrary::CertificatesLoaded() const { |
| 134 return CertLoader::Get()->certificates_loaded(); |
| 135 } |
| 136 |
| 137 bool CertLibrary::IsHardwareBacked() const { |
| 138 return CertLoader::Get()->IsHardwareBacked(); |
| 139 } |
| 140 |
| 141 int CertLibrary::NumCertificates(CertType type) const { |
| 142 const net::CertificateList& cert_list = GetCertificateListForType(type); |
| 143 return static_cast<int>(cert_list.size()); |
| 144 } |
| 145 |
| 146 string16 CertLibrary::GetCertDisplayStringAt(CertType type, int index) const { |
| 147 net::X509Certificate* cert = GetCertificateAt(type, index); |
| 517 bool hardware_backed = | 148 bool hardware_backed = |
| 518 !cert_library_->GetTpmTokenName().empty() && IsHardwareBackedAt(index); | 149 CertLoader::Get()->IsHardwareBacked() && |
| 150 IsCertHardwareBackedAt(type, index); |
| 519 return GetDisplayString(cert, hardware_backed); | 151 return GetDisplayString(cert, hardware_backed); |
| 520 } | 152 } |
| 521 | 153 |
| 522 std::string CertLibrary::CertList::GetNicknameAt(int index) const { | 154 std::string CertLibrary::GetCertNicknameAt(CertType type, int index) const { |
| 523 net::X509Certificate* cert = GetCertificateAt(index); | 155 net::X509Certificate* cert = GetCertificateAt(type, index); |
| 524 return x509_certificate_model::GetNickname(cert->os_cert_handle()); | 156 return x509_certificate_model::GetNickname(cert->os_cert_handle()); |
| 525 } | 157 } |
| 526 | 158 |
| 527 std::string CertLibrary::CertList::GetPkcs11IdAt(int index) const { | 159 std::string CertLibrary::GetCertPkcs11IdAt(CertType type, int index) const { |
| 528 net::X509Certificate* cert = GetCertificateAt(index); | 160 net::X509Certificate* cert = GetCertificateAt(type, index); |
| 529 return x509_certificate_model::GetPkcs11Id(cert->os_cert_handle()); | 161 return x509_certificate_model::GetPkcs11Id(cert->os_cert_handle()); |
| 530 } | 162 } |
| 531 | 163 |
| 532 bool CertLibrary::CertList::IsHardwareBackedAt(int index) const { | 164 bool CertLibrary::IsCertHardwareBackedAt(CertType type, int index) const { |
| 533 net::X509Certificate* cert = GetCertificateAt(index); | 165 net::X509Certificate* cert = GetCertificateAt(type, index); |
| 534 std::string cert_token_name = | 166 std::string cert_token_name = |
| 535 x509_certificate_model::GetTokenName(cert->os_cert_handle()); | 167 x509_certificate_model::GetTokenName(cert->os_cert_handle()); |
| 536 return cert_token_name == cert_library_->GetTpmTokenName(); | 168 return cert_token_name == CertLoader::Get()->tpm_token_name(); |
| 537 } | 169 } |
| 538 | 170 |
| 539 int CertLibrary::CertList::FindCertByNickname( | 171 int CertLibrary::GetCertIndexByNickname(CertType type, |
| 540 const std::string& nickname) const { | 172 const std::string& nickname) const { |
| 541 for (int index = 0; index < Size(); ++index) { | 173 int num_certs = NumCertificates(type); |
| 542 net::X509Certificate* cert = GetCertificateAt(index); | 174 for (int index = 0; index < num_certs; ++index) { |
| 175 net::X509Certificate* cert = GetCertificateAt(type, index); |
| 543 net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); | 176 net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); |
| 544 std::string nick = x509_certificate_model::GetNickname(cert_handle); | 177 std::string nick = x509_certificate_model::GetNickname(cert_handle); |
| 545 if (nick == nickname) | 178 if (nick == nickname) |
| 546 return index; | 179 return index; |
| 547 } | 180 } |
| 548 return -1; // Not found. | 181 return -1; // Not found. |
| 549 } | 182 } |
| 550 | 183 |
| 551 int CertLibrary::CertList::FindCertByPkcs11Id( | 184 int CertLibrary::GetCertIndexByPkcs11Id(CertType type, |
| 552 const std::string& pkcs11_id) const { | 185 const std::string& pkcs11_id) const { |
| 553 for (int index = 0; index < Size(); ++index) { | 186 int num_certs = NumCertificates(type); |
| 554 net::X509Certificate* cert = GetCertificateAt(index); | 187 for (int index = 0; index < num_certs; ++index) { |
| 188 net::X509Certificate* cert = GetCertificateAt(type, index); |
| 555 net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); | 189 net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); |
| 556 std::string id = x509_certificate_model::GetPkcs11Id(cert_handle); | 190 std::string id = x509_certificate_model::GetPkcs11Id(cert_handle); |
| 557 if (id == pkcs11_id) | 191 if (id == pkcs11_id) |
| 558 return index; | 192 return index; |
| 559 } | 193 } |
| 560 return -1; // Not found. | 194 return -1; // Not found. |
| 561 } | 195 } |
| 562 | 196 |
| 197 void CertLibrary::OnCertificatesLoaded(const net::CertificateList& cert_list, |
| 198 bool initial_load) { |
| 199 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 200 VLOG(1) << "CertLibrary::OnCertificatesLoaded: " << cert_list.size(); |
| 201 certs_.clear(); |
| 202 user_certs_.clear(); |
| 203 server_certs_.clear(); |
| 204 server_ca_certs_.clear(); |
| 205 |
| 206 // Add certificates to the appropriate list. |
| 207 for (net::CertificateList::const_iterator iter = cert_list.begin(); |
| 208 iter != cert_list.end(); ++iter) { |
| 209 certs_.push_back(iter->get()); |
| 210 net::X509Certificate::OSCertHandle cert_handle = |
| 211 iter->get()->os_cert_handle(); |
| 212 net::CertType type = x509_certificate_model::GetType(cert_handle); |
| 213 switch (type) { |
| 214 case net::USER_CERT: |
| 215 user_certs_.push_back(iter->get()); |
| 216 break; |
| 217 case net::SERVER_CERT: |
| 218 server_certs_.push_back(iter->get()); |
| 219 break; |
| 220 case net::CA_CERT: { |
| 221 // Exclude root CA certificates that are built into Chrome. |
| 222 std::string token_name = |
| 223 x509_certificate_model::GetTokenName(cert_handle); |
| 224 if (token_name != kRootCertificateTokenName) |
| 225 server_ca_certs_.push_back(iter->get()); |
| 226 break; |
| 227 } |
| 228 default: |
| 229 break; |
| 230 } |
| 231 } |
| 232 |
| 233 // Perform locale-sensitive sorting by certificate name. |
| 234 scoped_ptr<icu::Collator> collator; |
| 235 UErrorCode error = U_ZERO_ERROR; |
| 236 collator.reset(icu::Collator::createInstance( |
| 237 icu::Locale(g_browser_process->GetApplicationLocale().c_str()), error)); |
| 238 if (U_FAILURE(error)) |
| 239 collator.reset(NULL); |
| 240 CertNameComparator cert_name_comparator(collator.get()); |
| 241 std::sort(certs_.begin(), certs_.end(), cert_name_comparator); |
| 242 std::sort(user_certs_.begin(), user_certs_.end(), cert_name_comparator); |
| 243 std::sort(server_certs_.begin(), server_certs_.end(), cert_name_comparator); |
| 244 std::sort(server_ca_certs_.begin(), server_ca_certs_.end(), |
| 245 cert_name_comparator); |
| 246 |
| 247 VLOG(1) << "certs_: " << certs_.size(); |
| 248 VLOG(1) << "user_certs_: " << user_certs_.size(); |
| 249 VLOG(1) << "server_certs_: " << server_certs_.size(); |
| 250 VLOG(1) << "server_ca_certs_: " << server_ca_certs_.size(); |
| 251 |
| 252 FOR_EACH_OBSERVER(CertLibrary::Observer, observer_list_, |
| 253 OnCertificatesLoaded(initial_load)); |
| 254 } |
| 255 |
| 256 net::X509Certificate* CertLibrary::GetCertificateAt(CertType type, |
| 257 int index) const { |
| 258 const net::CertificateList& cert_list = GetCertificateListForType(type); |
| 259 DCHECK_GE(index, 0); |
| 260 DCHECK_LT(index, static_cast<int>(cert_list.size())); |
| 261 return cert_list[index].get(); |
| 262 } |
| 263 |
| 264 const net::CertificateList& CertLibrary::GetCertificateListForType( |
| 265 CertType type) const { |
| 266 if (type == CERT_TYPE_USER) |
| 267 return user_certs_; |
| 268 if (type == CERT_TYPE_SERVER) |
| 269 return server_certs_; |
| 270 if (type == CERT_TYPE_SERVER_CA) |
| 271 return server_ca_certs_; |
| 272 DCHECK(type == CERT_TYPE_DEFAULT); |
| 273 return certs_; |
| 274 } |
| 275 |
| 563 } // chromeos | 276 } // chromeos |
| OLD | NEW |