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) OVERRIDE {} | |
452 virtual void RemoveObserver(Observer* observer) OVERRIDE {} | |
453 virtual void LoadKeyStore() OVERRIDE {} | |
454 virtual bool CertificatesLoading() const OVERRIDE { | |
455 return false; | |
456 } | |
457 virtual bool CertificatesLoaded() const OVERRIDE { | |
458 return true; | |
459 } | |
460 virtual bool IsHardwareBacked() const OVERRIDE { | |
461 return false; | |
462 } | |
463 virtual const std::string& GetTpmTokenName() const OVERRIDE { | |
464 return token_name_; | |
465 } | |
466 virtual const CertList& GetCertificates() const OVERRIDE { | |
467 return cert_list_; | |
468 } | |
469 virtual const CertList& GetUserCertificates() const OVERRIDE { | |
470 return cert_list_; | |
471 } | |
472 virtual const CertList& GetServerCertificates() const OVERRIDE { | |
473 return cert_list_; | |
474 } | |
475 virtual const CertList& GetCACertificates() const OVERRIDE { | |
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); |
517 bool hardware_backed = | 115 } |
518 !cert_library_->GetTpmTokenName().empty() && IsHardwareBackedAt(index); | 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); |
| 148 bool hardware_backed = IsCertHardwareBackedAt(type, index); |
519 return GetDisplayString(cert, hardware_backed); | 149 return GetDisplayString(cert, hardware_backed); |
520 } | 150 } |
521 | 151 |
522 std::string CertLibrary::CertList::GetNicknameAt(int index) const { | 152 std::string CertLibrary::GetCertNicknameAt(CertType type, int index) const { |
523 net::X509Certificate* cert = GetCertificateAt(index); | 153 net::X509Certificate* cert = GetCertificateAt(type, index); |
524 return x509_certificate_model::GetNickname(cert->os_cert_handle()); | 154 return x509_certificate_model::GetNickname(cert->os_cert_handle()); |
525 } | 155 } |
526 | 156 |
527 std::string CertLibrary::CertList::GetPkcs11IdAt(int index) const { | 157 std::string CertLibrary::GetCertPkcs11IdAt(CertType type, int index) const { |
528 net::X509Certificate* cert = GetCertificateAt(index); | 158 net::X509Certificate* cert = GetCertificateAt(type, index); |
529 return x509_certificate_model::GetPkcs11Id(cert->os_cert_handle()); | 159 return x509_certificate_model::GetPkcs11Id(cert->os_cert_handle()); |
530 } | 160 } |
531 | 161 |
532 bool CertLibrary::CertList::IsHardwareBackedAt(int index) const { | 162 bool CertLibrary::IsCertHardwareBackedAt(CertType type, int index) const { |
533 net::X509Certificate* cert = GetCertificateAt(index); | 163 if (!CertLoader::Get()->IsHardwareBacked()) |
| 164 return false; |
| 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 UErrorCode error = U_ZERO_ERROR; |
| 235 scoped_ptr<icu::Collator> collator(icu::Collator::createInstance( |
| 236 icu::Locale(g_browser_process->GetApplicationLocale().c_str()), error)); |
| 237 if (U_FAILURE(error)) |
| 238 collator.reset(); |
| 239 CertNameComparator cert_name_comparator(collator.get()); |
| 240 std::sort(certs_.begin(), certs_.end(), cert_name_comparator); |
| 241 std::sort(user_certs_.begin(), user_certs_.end(), cert_name_comparator); |
| 242 std::sort(server_certs_.begin(), server_certs_.end(), cert_name_comparator); |
| 243 std::sort(server_ca_certs_.begin(), server_ca_certs_.end(), |
| 244 cert_name_comparator); |
| 245 |
| 246 VLOG(1) << "certs_: " << certs_.size(); |
| 247 VLOG(1) << "user_certs_: " << user_certs_.size(); |
| 248 VLOG(1) << "server_certs_: " << server_certs_.size(); |
| 249 VLOG(1) << "server_ca_certs_: " << server_ca_certs_.size(); |
| 250 |
| 251 FOR_EACH_OBSERVER(CertLibrary::Observer, observer_list_, |
| 252 OnCertificatesLoaded(initial_load)); |
| 253 } |
| 254 |
| 255 net::X509Certificate* CertLibrary::GetCertificateAt(CertType type, |
| 256 int index) const { |
| 257 const net::CertificateList& cert_list = GetCertificateListForType(type); |
| 258 DCHECK_GE(index, 0); |
| 259 DCHECK_LT(index, static_cast<int>(cert_list.size())); |
| 260 return cert_list[index].get(); |
| 261 } |
| 262 |
| 263 const net::CertificateList& CertLibrary::GetCertificateListForType( |
| 264 CertType type) const { |
| 265 if (type == CERT_TYPE_USER) |
| 266 return user_certs_; |
| 267 if (type == CERT_TYPE_SERVER) |
| 268 return server_certs_; |
| 269 if (type == CERT_TYPE_SERVER_CA) |
| 270 return server_ca_certs_; |
| 271 DCHECK(type == CERT_TYPE_DEFAULT); |
| 272 return certs_; |
| 273 } |
| 274 |
563 } // chromeos | 275 } // chromeos |
OLD | NEW |