diff options
-rw-r--r-- | chrome/app/generated_resources.grd | 6 | ||||
-rw-r--r-- | chrome/browser/chromeos/cros/cert_library.cc | 373 | ||||
-rw-r--r-- | chrome/browser/chromeos/cros/cert_library.h | 96 | ||||
-rw-r--r-- | chrome/browser/chromeos/cros/cros_library.cc | 3 | ||||
-rw-r--r-- | chrome/browser/chromeos/cros/cros_library.h | 4 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/user_manager.cc | 9 | ||||
-rw-r--r-- | chrome/browser/chromeos/options/vpn_config_view.cc | 284 | ||||
-rw-r--r-- | chrome/browser/chromeos/options/vpn_config_view.h | 30 | ||||
-rw-r--r-- | chrome/browser/chromeos/options/wifi_config_model.cc | 191 | ||||
-rw-r--r-- | chrome/browser/chromeos/options/wifi_config_model.h | 70 | ||||
-rw-r--r-- | chrome/browser/chromeos/options/wifi_config_view.cc | 171 | ||||
-rw-r--r-- | chrome/browser/chromeos/options/wifi_config_view.h | 34 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 4 | ||||
-rw-r--r-- | crypto/nss_util.cc | 89 | ||||
-rw-r--r-- | crypto/nss_util.h | 17 |
15 files changed, 828 insertions, 553 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 3fce9e4..d1cf62d 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -10762,9 +10762,15 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_USER_CERT_NONE_INSTALLED" desc="In settings Internet options, when creating a VPN or enterprise Wi-Fi connection, combobox item to display when no user certificates are installed."> None installed </message> + <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_LOADING" desc="In settings Internet options, when creating a VPN or enterprise Wi-Fi connection, combobox item to display when certificates are loading."> + Loading... + </message> <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PLEASE_INSTALL_USER_CERT" desc="In settings Internet options, when creating a VPN or enterprise Wi-Fi connection, error message to display when no user certificates are installed."> Please install a user certificate. </message> + <message name="IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_LOGIN_FOR_USER_CERT" desc="In settings Internet options, when creating a VPN or enterprise Wi-Fi connection, error message to display when not logged in and user certificates are required."> + Login required for user certificate. + </message> <message name="IDS_NETWORK_RECONNECT_TITLE" desc="In network menu, title of the reconnect button that allows user to retry connection on error."> Reconnect </message> diff --git a/chrome/browser/chromeos/cros/cert_library.cc b/chrome/browser/chromeos/cros/cert_library.cc new file mode 100644 index 0000000..f4e4750 --- /dev/null +++ b/chrome/browser/chromeos/cros/cert_library.cc @@ -0,0 +1,373 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/cros/cert_library.h" + +#include <algorithm> + +#include "base/observer_list_threadsafe.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/browser_process.h" // g_browser_process +#include "chrome/browser/chromeos/login/user_manager.h" +#include "chrome/common/net/x509_certificate_model.h" +#include "content/browser/browser_thread.h" +#include "crypto/nss_util.h" +#include "net/base/cert_database.h" +#include "ui/base/l10n/l10n_util_collator.h" +#include "unicode/coll.h" // icu::Collator + +////////////////////////////////////////////////////////////////////////////// + +namespace { + +// Root CA certificates that are built into Chrome use this token name. +const char kRootCertificateTokenName[] = "Builtin Object Token"; + +// Delay between certificate requests while waiting for TPM/PKCS#11 init. +const int kRequestDelayMs = 500; + +string16 GetDisplayString(net::X509Certificate* cert) { + std::string name_or_nick = + x509_certificate_model::GetCertNameOrNickname(cert->os_cert_handle()); + return UTF8ToUTF16(name_or_nick); +} + +} // namespace + +////////////////////////////////////////////////////////////////////////////// + +namespace chromeos { + +////////////////////////////////////////////////////////////////////////////// + +class CertLibraryImpl + : public CertLibrary, + public net::CertDatabase::Observer { + public: + typedef ObserverListThreadSafe<CertLibrary::Observer> CertLibraryObserverList; + + CertLibraryImpl() : + observer_list_(new CertLibraryObserverList), + request_task_(NULL), + user_logged_in_(false), + certificates_loaded_(false) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + net::CertDatabase::AddObserver(this); + } + + ~CertLibraryImpl() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (request_task_) { + request_task_->Cancel(); + request_task_ = NULL; + } + net::CertDatabase::RemoveObserver(this); + } + + // CertLibrary implementation. + virtual void RequestCertificates() OVERRIDE { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + if (!UserManager::Get()->user_is_logged_in()) { + // If we are not logged in, we cannot load any certificates. + // Set 'loaded' to true for the UI, since we are not waiting on loading. + LOG(WARNING) << "Requesting certificates before login."; + certificates_loaded_ = true; + return; + } + + if (!user_logged_in_) { + user_logged_in_ = true; + certificates_loaded_ = false; + } + + VLOG(1) << "Requesting Certificates."; + + // Need TPM token name to filter user certificates. + // TODO(stevenjb): crypto::EnsureTPMTokenReady() may block if init has + // not succeeded. It is not clear whether or not TPM / PKCS#11 init can + // be done safely on a non blocking thread. Blocking time is low. + if (crypto::EnsureTPMTokenReady()) { + std::string unused_pin; + // TODO(stevenjb): Make this asynchronous. It results in a synchronous + // D-Bus call in cryptohome (~3 ms). + crypto::GetTPMTokenInfo(&tpm_token_name_, &unused_pin); + } else { + if (crypto::IsTPMTokenAvailable()) { + VLOG(1) << "TPM token not ready."; + if (request_task_ == NULL) { + // Cryptohome does not notify us when the token is ready, so call + // this again after a delay. + request_task_ = NewRunnableMethod( + this, &CertLibraryImpl::RequestCertificatesTask); + BrowserThread::PostDelayedTask( + BrowserThread::UI, FROM_HERE, request_task_, kRequestDelayMs); + } + return; + } + // TPM is not enabled, so proceed with empty tpm token name. + VLOG(1) << "TPM not available."; + } + + // tpm_token_name_ is set, load the certificates on the DB thread. + BrowserThread::PostTask( + BrowserThread::DB, FROM_HERE, + NewRunnableMethod(this, &CertLibraryImpl::LoadCertificates)); + } + + virtual void AddObserver(CertLibrary::Observer* observer) OVERRIDE { + observer_list_->AddObserver(observer); + } + + virtual void RemoveObserver(CertLibrary::Observer* observer) OVERRIDE { + observer_list_->RemoveObserver(observer); + } + + virtual bool CertificatesLoaded() const OVERRIDE { + return certificates_loaded_; + } + + virtual const CertList& GetCertificates() const OVERRIDE { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + return certs_; + } + + virtual const CertList& GetUserCertificates() const OVERRIDE { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + return user_certs_; + } + + virtual const CertList& GetServerCertificates() const OVERRIDE { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + return server_certs_; + } + + virtual const CertList& GetCACertificates() const OVERRIDE { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + return server_ca_certs_; + } + + // net::CertDatabase::Observer implementation. Observer added on UI thread. + virtual void OnCertTrustChanged(const net::X509Certificate* cert) OVERRIDE { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + } + + virtual void OnUserCertAdded(const net::X509Certificate* cert) OVERRIDE { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + VLOG(1) << "Certificate Added."; + // Only load certificates if we have completed an initial request. + if (certificates_loaded_) { + VLOG(1) << " Loading Certificates."; + // The certificate passed in is const, so we cannot add it to our + // ref counted list directly. Instead, re-load the certificate list. + BrowserThread::PostTask( + BrowserThread::DB, FROM_HERE, + NewRunnableMethod(this, &CertLibraryImpl::LoadCertificates)); + } + } + + private: + void LoadCertificates() { + // Certificate fetch occurs on the DB thread. + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); + net::CertDatabase cert_db; + net::CertificateList* cert_list = new net::CertificateList(); + cert_db.ListCerts(cert_list); + // Pass the list to the UI thread to safely update the local lists. + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod(this, &CertLibraryImpl::UpdateCertificates, + cert_list)); + } + + // Comparison functor for locale-sensitive sorting of certificates by name. + class CertNameComparator { + public: + explicit CertNameComparator(icu::Collator* collator) + : collator_(collator) { } + + bool operator()(const scoped_refptr<net::X509Certificate>& lhs, + const scoped_refptr<net::X509Certificate>& rhs) const { + string16 lhs_name = GetDisplayString(lhs.get()); + string16 rhs_name = GetDisplayString(rhs.get()); + if (collator_ == NULL) + return lhs_name < rhs_name; + return l10n_util::CompareString16WithCollator( + collator_, lhs_name, rhs_name) == UCOL_LESS; + } + private: + icu::Collator* collator_; + }; + + void RequestCertificatesTask() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + // This will only get called from request_task_ which will delete itself. + request_task_ = NULL; + RequestCertificates(); + } + + void NotifyCertificatesLoaded(bool initial_load) { + observer_list_->Notify( + &CertLibrary::Observer::OnCertificatesLoaded, initial_load); + } + + // |cert_list| is allocated in LoadCertificates() and must be deleted here. + void UpdateCertificates(net::CertificateList* cert_list) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(cert_list); + + // Clear any existing certificates. + certs_.Clear(); + server_ca_certs_.Clear(); + user_certs_.Clear(); + server_certs_.Clear(); + + // Add certificates to the appropriate list. + for (net::CertificateList::const_iterator iter = cert_list->begin(); + iter != cert_list->end(); ++iter) { + certs_.Append(iter->get()); + net::X509Certificate::OSCertHandle cert_handle = + iter->get()->os_cert_handle(); + net::CertType type = x509_certificate_model::GetType(cert_handle); + switch (type) { + case net::USER_CERT: { + // Only include user certs that are in the TPM token (and hence + // available via PKCS#11 to flimflam and wpa_supplicant). + std::string cert_token_name = + x509_certificate_model::GetTokenName(cert_handle); + if (tpm_token_name_.empty() || cert_token_name == tpm_token_name_) + user_certs_.Append(iter->get()); + break; + } + case net::SERVER_CERT: + server_certs_.Append(iter->get()); + break; + case net::CA_CERT: { + // Exclude root CA certificates that are built into Chrome. + std::string token_name = + x509_certificate_model::GetTokenName(cert_handle); + if (token_name != kRootCertificateTokenName) + server_ca_certs_.Append(iter->get()); + break; + } + default: + break; + } + } + + // Perform locale-sensitive sorting by certificate name. + scoped_ptr<icu::Collator> collator; + UErrorCode error = U_ZERO_ERROR; + collator.reset( + icu::Collator::createInstance( + icu::Locale(g_browser_process->GetApplicationLocale().c_str()), + error)); + if (U_FAILURE(error)) + collator.reset(NULL); + CertNameComparator cert_name_comparator(collator.get()); + std::sort(user_certs_.list().begin(), user_certs_.list().end(), + cert_name_comparator); + std::sort(server_certs_.list().begin(), server_certs_.list().end(), + cert_name_comparator); + std::sort(server_ca_certs_.list().begin(), server_ca_certs_.list().end(), + cert_name_comparator); + + // cert_list is allocated in LoadCertificates(), then released here. + delete cert_list; + + // Set loaded state and notify observers. + if (!certificates_loaded_) { + certificates_loaded_ = true; + NotifyCertificatesLoaded(true); + } else { + NotifyCertificatesLoaded(false); + } + } + + // Observers. + const scoped_refptr<CertLibraryObserverList> observer_list_; + + // Active request task for re-requests while waiting for TPM init. + CancelableTask* request_task_; + + // Cached TPM token name. + std::string tpm_token_name_; + + // Local state. + bool user_logged_in_; + bool certificates_loaded_; + + // Certificates. + CertList certs_; + CertList user_certs_; + CertList server_certs_; + CertList server_ca_certs_; + + DISALLOW_COPY_AND_ASSIGN(CertLibraryImpl); +}; + +////////////////////////////////////////////////////////////////////////////// + +CertLibrary::~CertLibrary() { +} + +// static +CertLibrary* CertLibrary::GetImpl(bool stub) { + // No libcros dependencies, so always return CertLibraryImpl() (no stub). + return new CertLibraryImpl(); +} + +////////////////////////////////////////////////////////////////////////////// + +net::X509Certificate* CertLibrary::CertList::GetCertificateAt(int index) const { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK_GE(index, 0); + DCHECK_LT(index, static_cast<int>(list_.size())); + return list_[index].get(); +} + +string16 CertLibrary::CertList::GetDisplayStringAt(int index) const { + net::X509Certificate* cert = GetCertificateAt(index); + return GetDisplayString(cert); +} + +std::string CertLibrary::CertList::GetNicknameAt(int index) const { + net::X509Certificate* cert = GetCertificateAt(index); + return x509_certificate_model::GetNickname(cert->os_cert_handle()); +} + +std::string CertLibrary::CertList::GetPkcs11IdAt(int index) const { + net::X509Certificate* cert = GetCertificateAt(index); + return x509_certificate_model::GetPkcs11Id(cert->os_cert_handle()); +} + +int CertLibrary::CertList::FindCertByNickname( + const std::string& nickname) const { + for (int index = 0; index < Size(); ++index) { + net::X509Certificate* cert = GetCertificateAt(index); + net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); + std::string nick = x509_certificate_model::GetNickname(cert_handle); + if (nick == nickname) + return index; + } + return -1; // Not found. +} + +int CertLibrary::CertList::FindCertByPkcs11Id( + const std::string& pkcs11_id) const { + for (int index = 0; index < Size(); ++index) { + net::X509Certificate* cert = GetCertificateAt(index); + net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); + std::string id = x509_certificate_model::GetPkcs11Id(cert_handle); + if (id == pkcs11_id) + return index; + } + return -1; // Not found. +} + +} // chromeos + +// Allows InvokeLater without adding refcounting. This class is a singleton and +// won't be deleted until it's last InvokeLater is run. +DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::CertLibraryImpl); diff --git a/chrome/browser/chromeos/cros/cert_library.h b/chrome/browser/chromeos/cros/cert_library.h new file mode 100644 index 0000000..87fecd6 --- /dev/null +++ b/chrome/browser/chromeos/cros/cert_library.h @@ -0,0 +1,96 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_CROS_CERT_LIBRARY_H_ +#define CHROME_BROWSER_CHROMEOS_CROS_CERT_LIBRARY_H_ +#pragma once + +#include <string> + +#include "base/string16.h" +#include "net/base/cert_database.h" +#include "net/base/x509_certificate.h" + +namespace chromeos { + +class CertLibrary { + public: + + // Observers can register themselves via CertLibrary::AddObserver, and can + // un-register with CertLibrary::RemoveObserver. + class Observer { + public: + virtual ~Observer() {} + + // Called for any Observers whenever the certificates are loaded. + // |initial_load| is true the first time this is called. + virtual void OnCertificatesLoaded(bool initial_load) = 0; + + protected: + Observer() {} + + private: + DISALLOW_COPY_AND_ASSIGN(Observer); + }; + + // Wrapper class to provide an additional interface for net::CertificateList. + class CertList { + public: + explicit CertList() {} + ~CertList() {} + void Append(net::X509Certificate* cert) { list_.push_back(cert); } + void Clear() { list_.clear(); } + int Size() const { return static_cast<int>(list_.size()); } + net::X509Certificate* GetCertificateAt(int index) const; + string16 GetDisplayStringAt(int index) const; // User-visible name. + std::string GetNicknameAt(int index) const; + std::string GetPkcs11IdAt(int index) const; + // Finds the index of a Certificate matching |nickname|. + // Returns -1 if none found. + int FindCertByNickname(const std::string& nickname) const; + // Same as above but for a pkcs#11 id. + int FindCertByPkcs11Id(const std::string& pkcs11_id) const; + net::CertificateList& list() { return list_; } + + private: + net::CertificateList list_; + + DISALLOW_COPY_AND_ASSIGN(CertList); + }; + + virtual ~CertLibrary(); + + static CertLibrary* GetImpl(bool stub); + + // Registers |observer|. The thread on which this is called is the thread + // on which |observer| will be called back with notifications. + virtual void AddObserver(Observer* observer) = 0; + + // Unregisters |observer| from receiving notifications. This must be called + // on the same thread on which AddObserver() was called. + virtual void RemoveObserver(Observer* observer) = 0; + + // Call this to start the certificate list initialization process. + // Must be called from the UI thread. + virtual void RequestCertificates() = 0; + + // Returns true when the certificate list has been initiailized. + virtual bool CertificatesLoaded() const = 0; + + // Returns the current list of all certificates. + virtual const CertList& GetCertificates() const = 0; + + // Returns the current list of user certificates. + virtual const CertList& GetUserCertificates() const = 0; + + // Returns the current list of server certificates. + virtual const CertList& GetServerCertificates() const = 0; + + // Returns the current list of server CA certificates. + virtual const CertList& GetCACertificates() const = 0; +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_CROS_CERT_LIBRARY_H_ diff --git a/chrome/browser/chromeos/cros/cros_library.cc b/chrome/browser/chromeos/cros/cros_library.cc index 9315fa1..7a0373a 100644 --- a/chrome/browser/chromeos/cros/cros_library.cc +++ b/chrome/browser/chromeos/cros/cros_library.cc @@ -7,6 +7,7 @@ #include "base/lazy_instance.h" #include "chrome/browser/chromeos/cros/brightness_library.h" #include "chrome/browser/chromeos/cros/burn_library.h" +#include "chrome/browser/chromeos/cros/cert_library.h" #include "chrome/browser/chromeos/cros/cros_library_loader.h" #include "chrome/browser/chromeos/cros/cryptohome_library.h" #include "chrome/browser/chromeos/cros/input_method_library.h" @@ -57,6 +58,7 @@ CrosLibrary* CrosLibrary::Get() { DEFINE_GET_LIBRARY_METHOD(Brightness, brightness); DEFINE_GET_LIBRARY_METHOD(Burn, burn); +DEFINE_GET_LIBRARY_METHOD(Cert, cert); DEFINE_GET_LIBRARY_METHOD(Cryptohome, crypto); DEFINE_GET_LIBRARY_METHOD(InputMethod, input_method); DEFINE_GET_LIBRARY_METHOD(LibCrosService, libcros_service); @@ -112,6 +114,7 @@ void CrosLibrary::TestApi::SetLibraryLoader(LibraryLoader* loader, bool own) { } DEFINE_SET_LIBRARY_METHOD(Brightness, brightness); +DEFINE_SET_LIBRARY_METHOD(Cert, cert); DEFINE_SET_LIBRARY_METHOD(Burn, burn); DEFINE_SET_LIBRARY_METHOD(Cryptohome, crypto); DEFINE_SET_LIBRARY_METHOD(InputMethod, input_method); diff --git a/chrome/browser/chromeos/cros/cros_library.h b/chrome/browser/chromeos/cros/cros_library.h index 7c67095..8148b3a 100644 --- a/chrome/browser/chromeos/cros/cros_library.h +++ b/chrome/browser/chromeos/cros/cros_library.h @@ -20,6 +20,7 @@ namespace chromeos { class BrightnessLibrary; class BurnLibrary; +class CertLibrary; class CryptohomeLibrary; class InputMethodLibrary; class LibCrosServiceLibrary; @@ -56,6 +57,7 @@ class CrosLibrary { // Setter for LibraryLoader. void SetLibraryLoader(LibraryLoader* loader, bool own); void SetBrightnessLibrary(BrightnessLibrary* library, bool own); + void SetCertLibrary(CertLibrary* library, bool own); void SetBurnLibrary(BurnLibrary* library, bool own); void SetCryptohomeLibrary(CryptohomeLibrary* library, bool own); void SetInputMethodLibrary(InputMethodLibrary* library, bool own); @@ -80,6 +82,7 @@ class CrosLibrary { BrightnessLibrary* GetBrightnessLibrary(); BurnLibrary* GetBurnLibrary(); + CertLibrary* GetCertLibrary(); CryptohomeLibrary* GetCryptohomeLibrary(); InputMethodLibrary* GetInputMethodLibrary(); LibCrosServiceLibrary* GetLibCrosServiceLibrary(); @@ -154,6 +157,7 @@ class CrosLibrary { Library<BrightnessLibrary> brightness_lib_; Library<BurnLibrary> burn_lib_; + Library<CertLibrary> cert_lib_; Library<CryptohomeLibrary> crypto_lib_; Library<InputMethodLibrary> input_method_lib_; Library<LibCrosServiceLibrary> libcros_service_lib_; diff --git a/chrome/browser/chromeos/login/user_manager.cc b/chrome/browser/chromeos/login/user_manager.cc index 535b59c..d2e9d52 100644 --- a/chrome/browser/chromeos/login/user_manager.cc +++ b/chrome/browser/chromeos/login/user_manager.cc @@ -571,14 +571,19 @@ class RealTPMTokenInfoDelegate : public crypto::TPMTokenInfoDelegate { public: RealTPMTokenInfoDelegate(); virtual ~RealTPMTokenInfoDelegate(); - virtual bool IsTokenReady() const; + virtual bool IsTokenAvailable() const OVERRIDE; + virtual bool IsTokenReady() const OVERRIDE; virtual void GetTokenInfo(std::string* token_name, - std::string* user_pin) const; + std::string* user_pin) const OVERRIDE; }; RealTPMTokenInfoDelegate::RealTPMTokenInfoDelegate() {} RealTPMTokenInfoDelegate::~RealTPMTokenInfoDelegate() {} +bool RealTPMTokenInfoDelegate::IsTokenAvailable() const { + return CrosLibrary::Get()->GetCryptohomeLibrary()->TpmIsEnabled(); +} + bool RealTPMTokenInfoDelegate::IsTokenReady() const { return CrosLibrary::Get()->GetCryptohomeLibrary()->Pkcs11IsTpmTokenReady(); } diff --git a/chrome/browser/chromeos/options/vpn_config_view.cc b/chrome/browser/chromeos/options/vpn_config_view.cc index a11e98d..144d3d7 100644 --- a/chrome/browser/chromeos/options/vpn_config_view.cc +++ b/chrome/browser/chromeos/options/vpn_config_view.cc @@ -68,134 +68,76 @@ class ProviderTypeComboboxModel : public ui::ComboboxModel { DISALLOW_COPY_AND_ASSIGN(ProviderTypeComboboxModel); }; -// TODO(stevenjb): Integrate with changes from chromium-os:15829. class ServerCACertComboboxModel : public ui::ComboboxModel { public: - ServerCACertComboboxModel() { - net::CertDatabase cert_db; - net::CertificateList cert_list; - cert_db.ListCerts(&cert_list); - // Find all the CA certificates. - for (net::CertificateList::const_iterator it = cert_list.begin(); - it != cert_list.end(); ++it) { - net::X509Certificate* cert = it->get(); - net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); - net::CertType type = x509_certificate_model::GetType(cert_handle); - if (type == net::CA_CERT) { - // Exclude root CA certificates that are built into Chrome. - std::string token_name = - x509_certificate_model::GetTokenName(cert_handle); - if (token_name != kRootCertificateTokenName) - ca_certs_.push_back(*it); - } - } + explicit ServerCACertComboboxModel(CertLibrary* cert_library) + : cert_library_(cert_library) { } virtual ~ServerCACertComboboxModel() {} - virtual int GetItemCount() { - return static_cast<int>(ca_certs_.size() + 1); // "Default" + certs + if (!cert_library_->CertificatesLoaded()) + return 1; // "Loading" + // "Default" + certs. + return cert_library_->GetCACertificates().Size() + 1; } - - virtual string16 GetItemAt(int index) { - if (index == 0) + virtual string16 GetItemAt(int combo_index) { + if (!cert_library_->CertificatesLoaded()) + return l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_LOADING); + if (combo_index == 0) return l10n_util::GetStringUTF16( IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_SERVER_CA_DEFAULT); - int cert_index = index - 1; - if (cert_index >= 0 && cert_index < static_cast<int>(ca_certs_.size())) { - net::X509Certificate* cert = ca_certs_[cert_index].get(); - std::string name = - x509_certificate_model::GetCertNameOrNickname(cert->os_cert_handle()); - return UTF8ToUTF16(name); - } - return string16(); - } - - int GetCertCount() { - return static_cast<int>(ca_certs_.size()); - } - - std::string GetCertNssNickname(int cert_index) { - if (0 <= cert_index && cert_index < static_cast<int>(ca_certs_.size())) { - net::X509Certificate* cert = ca_certs_[cert_index].get(); - return x509_certificate_model::GetNickname(cert->os_cert_handle()); - } - return std::string(); + int cert_index = combo_index - 1; + return cert_library_->GetCACertificates().GetDisplayStringAt(cert_index); } - private: - net::CertificateList ca_certs_; + CertLibrary* cert_library_; DISALLOW_COPY_AND_ASSIGN(ServerCACertComboboxModel); }; -// TODO(stevenjb): Integrate with changes from chromium-os:15829. class UserCertComboboxModel : public ui::ComboboxModel { public: - UserCertComboboxModel() { - net::CertDatabase cert_db; - net::CertificateList cert_list; - cert_db.ListCerts(&cert_list); - // Find all the user certificates. There shouldn't be many. - for (net::CertificateList::const_iterator it = cert_list.begin(); - it != cert_list.end(); ++it) { - net::X509Certificate* cert = it->get(); - net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); - net::CertType type = x509_certificate_model::GetType(cert_handle); - if (type == net::USER_CERT) - user_certs_.push_back(*it); - } + explicit UserCertComboboxModel(CertLibrary* cert_library) + : cert_library_(cert_library) { } virtual ~UserCertComboboxModel() {} - virtual int GetItemCount() { - if (user_certs_.empty()) - return 1; // "None installed" item - return static_cast<int>(user_certs_.size()); + if (!cert_library_->CertificatesLoaded()) + return 1; // "Loading" + int num_certs = cert_library_->GetUserCertificates().Size(); + if (num_certs == 0) + return 1; // "None installed" + return num_certs; } - - virtual string16 GetItemAt(int index) { - if (user_certs_.empty()) { - // "None installed" item. + virtual string16 GetItemAt(int combo_index) { + if (!cert_library_->CertificatesLoaded()) + return l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_LOADING); + if (cert_library_->GetUserCertificates().Size() == 0) return l10n_util::GetStringUTF16( IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_USER_CERT_NONE_INSTALLED); - } - if (index >= 0 && index < static_cast<int>(user_certs_.size())) { - net::X509Certificate* cert = user_certs_[index].get(); - std::string name = - x509_certificate_model::GetCertNameOrNickname(cert->os_cert_handle()); - return UTF8ToUTF16(name); - } - return string16(); - } - - bool HaveCerts() { - return !user_certs_.empty(); - } - - // Gets PKCS#11 certificate ID, or empty string on failure. - std::string GetCertID(int index) { - if (0 <= index && index < static_cast<int>(user_certs_.size())) { - net::X509Certificate* cert = user_certs_[index].get(); - return x509_certificate_model::GetPkcs11Id(cert->os_cert_handle()); - } - return std::string(); + return cert_library_->GetUserCertificates().GetDisplayStringAt(combo_index); } - private: - net::CertificateList user_certs_; + CertLibrary* cert_library_; DISALLOW_COPY_AND_ASSIGN(UserCertComboboxModel); }; VPNConfigView::VPNConfigView(NetworkConfigView* parent, VirtualNetwork* vpn) - : ChildNetworkConfigView(parent, vpn) { + : ChildNetworkConfigView(parent, vpn), + cert_library_(NULL) { Init(vpn); } VPNConfigView::VPNConfigView(NetworkConfigView* parent) - : ChildNetworkConfigView(parent) { + : ChildNetworkConfigView(parent), + cert_library_(NULL) { Init(NULL); } VPNConfigView::~VPNConfigView() { + if (cert_library_) + cert_library_->RemoveObserver(this); } void VPNConfigView::UpdateCanLogin() { @@ -218,41 +160,13 @@ bool VPNConfigView::CanLogin() { return true; } -void VPNConfigView::UpdateErrorLabel() { - std::string error_msg; - if (UserCertRequired() && !HaveUserCerts()) - error_msg = l10n_util::GetStringUTF8( - IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PLEASE_INSTALL_USER_CERT); - if (!service_path_.empty()) { - // TODO(kuan): differentiate between bad psk and user passphrases. - NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); - VirtualNetwork* vpn = cros->FindVirtualNetworkByPath(service_path_); - if (vpn && vpn->failed()) { - if (vpn->error() == ERROR_BAD_PASSPHRASE) { - error_msg = l10n_util::GetStringUTF8( - IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_PASSPHRASE); - } else { - error_msg = vpn->GetErrorString(); - } - } - } - if (!error_msg.empty()) { - error_label_->SetText(UTF8ToWide(error_msg)); - error_label_->SetVisible(true); - } else { - error_label_->SetVisible(false); - } -} - bool VPNConfigView::UserCertRequired() const { return provider_type_ == VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_USER_CERT || provider_type_ == VirtualNetwork::PROVIDER_TYPE_OPEN_VPN; } bool VPNConfigView::HaveUserCerts() const { - UserCertComboboxModel* model = static_cast<UserCertComboboxModel*>( - user_cert_combobox_->model()); - return model->HaveCerts(); + return cert_library_->GetUserCertificates().Size() > 0; } void VPNConfigView::ContentsChanged(views::Textfield* sender, @@ -294,8 +208,7 @@ void VPNConfigView::ItemChanged(views::Combobox* combo_box, return; if (combo_box == provider_type_combobox_) { provider_type_ = static_cast<VirtualNetwork::ProviderType>(new_index); - EnableControls(); - UpdateErrorLabel(); + Refresh(); } else if (combo_box == user_cert_combobox_) { // Nothing to do for now. } else if (combo_box == server_ca_cert_combobox_) { @@ -306,6 +219,10 @@ void VPNConfigView::ItemChanged(views::Combobox* combo_box, UpdateCanLogin(); } +void VPNConfigView::OnCertificatesLoaded(bool initial_load) { + Refresh(); +} + bool VPNConfigView::Login() { NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); if (service_path_.empty()) { @@ -422,29 +339,41 @@ const std::string VPNConfigView::GetUserPassphrase() const { } const std::string VPNConfigView::GetServerCACertNssNickname() const { + DCHECK(server_ca_cert_combobox_); + DCHECK(cert_library_); int selected = server_ca_cert_combobox_->selected_item(); if (selected == 0) { // First item is "Default". return std::string(); } else { + DCHECK(cert_library_); + DCHECK(cert_library_->GetCACertificates().Size() > 0); int cert_index = selected - 1; - ServerCACertComboboxModel* model = static_cast<ServerCACertComboboxModel*>( - server_ca_cert_combobox_->model()); - return model->GetCertNssNickname(cert_index); + return cert_library_->GetCACertificates().GetNicknameAt(cert_index); } } const std::string VPNConfigView::GetUserCertID() const { - int selected = user_cert_combobox_->selected_item(); - UserCertComboboxModel* model = static_cast<UserCertComboboxModel*>( - user_cert_combobox_->model()); - return model->GetCertID(selected); + DCHECK(user_cert_combobox_); + DCHECK(cert_library_); + if (cert_library_->GetUserCertificates().Size() == 0) { + return std::string(); // "None installed" + } else { + // Certificates are listed in the order they appear in the model. + int selected = user_cert_combobox_->selected_item(); + return cert_library_->GetUserCertificates().GetPkcs11IdAt(selected); + } } void VPNConfigView::Init(VirtualNetwork* vpn) { views::GridLayout* layout = views::GridLayout::CreatePanel(this); SetLayoutManager(layout); + // VPN may require certificates, so always set the library and observe. + cert_library_ = chromeos::CrosLibrary::Get()->GetCertLibrary(); + cert_library_->AddObserver(this); + cert_library_->RequestCertificates(); + int column_view_set_id = 0; views::ColumnSet* column_set = layout->AddColumnSet(column_view_set_id); // Label. @@ -540,19 +469,8 @@ void VPNConfigView::Init(VirtualNetwork* vpn) { IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_SERVER_CA))); layout->AddView(server_ca_cert_label_); ServerCACertComboboxModel* server_ca_cert_model = - new ServerCACertComboboxModel(); + new ServerCACertComboboxModel(cert_library_); server_ca_cert_combobox_ = new views::Combobox(server_ca_cert_model); - if (vpn && !vpn->ca_cert_nss().empty()) { - // Select the current server CA certificate in the combobox. - for (int i = 0; i < server_ca_cert_model->GetCertCount(); ++i) { - std::string cert_name = server_ca_cert_model->GetCertNssNickname(i); - if (cert_name == vpn->ca_cert_nss()) { - int item_index = i + 1; // First item is "Default" - server_ca_cert_combobox_->SetSelectedItem(item_index); - break; - } - } - } layout->AddView(server_ca_cert_combobox_); layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); @@ -561,19 +479,10 @@ void VPNConfigView::Init(VirtualNetwork* vpn) { user_cert_label_ = new views::Label(UTF16ToWide(l10n_util::GetStringUTF16( IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_CERT))); layout->AddView(user_cert_label_); - UserCertComboboxModel* user_cert_model = new UserCertComboboxModel(); + UserCertComboboxModel* user_cert_model = + new UserCertComboboxModel(cert_library_); user_cert_combobox_ = new views::Combobox(user_cert_model); user_cert_combobox_->set_listener(this); - if (vpn && !vpn->client_cert_id().empty()) { - // Select the current user certificate in the combobox. - for (int i = 0; i < user_cert_model->GetItemCount(); ++i) { - std::string cert_id = user_cert_model->GetCertID(i); - if (cert_id == vpn->client_cert_id()) { - user_cert_combobox_->SetSelectedItem(i); - break; - } - } - } layout->AddView(user_cert_combobox_); layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); @@ -609,14 +518,14 @@ void VPNConfigView::Init(VirtualNetwork* vpn) { error_label_->SetColor(SK_ColorRED); layout->AddView(error_label_); - // Enable controls based on provider type combo. - EnableControls(); - - // Set or hide the error text. - UpdateErrorLabel(); + // Set or hide the UI, update comboboxes and error labels. + Refresh(); } -void VPNConfigView::EnableControls() { +void VPNConfigView::Refresh() { + NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); + + // Enable controls. switch (provider_type_) { case VirtualNetwork::PROVIDER_TYPE_L2TP_IPSEC_PSK: psk_passphrase_label_->SetEnabled(true); @@ -648,6 +557,61 @@ void VPNConfigView::EnableControls() { NOTREACHED(); break; } + + // Set certificate combo boxes. + VirtualNetwork* vpn = cros->FindVirtualNetworkByPath(service_path_); + server_ca_cert_combobox_->ModelChanged(); + if (server_ca_cert_combobox_->IsEnabled() && + (vpn && !vpn->ca_cert_nss().empty())) { + // Select the current server CA certificate in the combobox. + int cert_index = cert_library_->GetCACertificates().FindCertByNickname( + vpn->ca_cert_nss()); + if (cert_index >= 0) { + // Skip item for "Default" + server_ca_cert_combobox_->SetSelectedItem(1 + cert_index); + } else { + server_ca_cert_combobox_->SetSelectedItem(0); + } + } else { + server_ca_cert_combobox_->SetSelectedItem(0); + } + + user_cert_combobox_->ModelChanged(); + if (user_cert_combobox_->IsEnabled() && + (vpn && !vpn->client_cert_id().empty())) { + int cert_index = cert_library_->GetUserCertificates().FindCertByPkcs11Id( + vpn->client_cert_id()); + if (cert_index >= 0) + user_cert_combobox_->SetSelectedItem(cert_index); + else + user_cert_combobox_->SetSelectedItem(0); + } else { + user_cert_combobox_->SetSelectedItem(0); + } + + // Error message. + std::string error_msg; + if (UserCertRequired() && !HaveUserCerts()) + error_msg = l10n_util::GetStringUTF8( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PLEASE_INSTALL_USER_CERT); + if (!service_path_.empty()) { + // TODO(kuan): differentiate between bad psk and user passphrases. + VirtualNetwork* vpn = cros->FindVirtualNetworkByPath(service_path_); + if (vpn && vpn->failed()) { + if (vpn->error() == ERROR_BAD_PASSPHRASE) { + error_msg = l10n_util::GetStringUTF8( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_BAD_PASSPHRASE); + } else { + error_msg = vpn->GetErrorString(); + } + } + } + if (!error_msg.empty()) { + error_label_->SetText(UTF8ToWide(error_msg)); + error_label_->SetVisible(true); + } else { + error_label_->SetVisible(false); + } } } // namespace chromeos diff --git a/chrome/browser/chromeos/options/vpn_config_view.h b/chrome/browser/chromeos/options/vpn_config_view.h index a2c6c5c..3280545 100644 --- a/chrome/browser/chromeos/options/vpn_config_view.h +++ b/chrome/browser/chromeos/options/vpn_config_view.h @@ -9,7 +9,7 @@ #include <string> #include "base/string16.h" -#include "chrome/browser/chromeos/cros/network_library.h" +#include "chrome/browser/chromeos/cros/cert_library.h" #include "chrome/browser/chromeos/options/network_config_view.h" #include "chrome/browser/ui/shell_dialogs.h" #include "views/controls/button/button.h" @@ -27,24 +27,29 @@ namespace chromeos { class VPNConfigView : public ChildNetworkConfigView, public views::TextfieldController, public views::ButtonListener, - public views::Combobox::Listener { + public views::Combobox::Listener, + public CertLibrary::Observer { public: VPNConfigView(NetworkConfigView* parent, VirtualNetwork* vpn); explicit VPNConfigView(NetworkConfigView* parent); virtual ~VPNConfigView(); // views::TextfieldController methods. - virtual void ContentsChanged(views::Textfield* sender, - const string16& new_contents); - virtual bool HandleKeyEvent(views::Textfield* sender, - const views::KeyEvent& key_event); + virtual void ContentsChanged( + views::Textfield* sender, const string16& new_contents) OVERRIDE; + virtual bool HandleKeyEvent( + views::Textfield* sender, const views::KeyEvent& key_event) OVERRIDE; // views::ButtonListener - virtual void ButtonPressed(views::Button* sender, const views::Event& event); + virtual void ButtonPressed( + views::Button* sender, const views::Event& event) OVERRIDE; // views::Combobox::Listener - virtual void ItemChanged(views::Combobox* combo_box, - int prev_index, int new_index); + virtual void ItemChanged( + views::Combobox* combo_box, int prev_index, int new_index) OVERRIDE; + + // CertLibrary::Observer: + virtual void OnCertificatesLoaded(bool initial_load) OVERRIDE; // ChildNetworkConfigView implementation. virtual string16 GetTitle() OVERRIDE; @@ -57,14 +62,11 @@ class VPNConfigView : public ChildNetworkConfigView, // Initializes data members and create UI controls. void Init(VirtualNetwork* vpn); - void EnableControls(); + void Refresh(); // Update state of the Login button. void UpdateCanLogin(); - // Update the error text label. - void UpdateErrorLabel(); - // Returns true if the provider type requires a user certificate. bool UserCertRequired() const; @@ -84,6 +86,8 @@ class VPNConfigView : public ChildNetworkConfigView, const std::string GetServerCACertNssNickname() const; const std::string GetUserCertID() const; + CertLibrary* cert_library_; + std::string server_hostname_; string16 service_name_from_server_; bool service_text_modified_; diff --git a/chrome/browser/chromeos/options/wifi_config_model.cc b/chrome/browser/chromeos/options/wifi_config_model.cc deleted file mode 100644 index 9147d8c..0000000 --- a/chrome/browser/chromeos/options/wifi_config_model.cc +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/chromeos/options/wifi_config_model.h" - -#include <algorithm> - -#include "base/utf_string_conversions.h" -#include "chrome/browser/browser_process.h" // g_browser_process -#include "chrome/common/net/x509_certificate_model.h" -#include "crypto/nss_util.h" // crypto::GetTPMTokenInfo() -#include "net/base/cert_database.h" -#include "net/base/x509_certificate.h" -#include "ui/base/l10n/l10n_util_collator.h" // CompareString16WithCollator -#include "unicode/coll.h" // icu::Collator - -namespace chromeos { - -namespace { - -typedef scoped_refptr<net::X509Certificate> X509CertificateRefPtr; - -// Root CA certificates that are built into Chrome use this token name. -const char* const kRootCertificateTokenName = "Builtin Object Token"; - -// Returns a user-visible name for a given certificate. -string16 GetCertDisplayString(const net::X509Certificate* cert) { - DCHECK(cert); - std::string name_or_nick = - x509_certificate_model::GetCertNameOrNickname(cert->os_cert_handle()); - return UTF8ToUTF16(name_or_nick); -} - -// Comparison functor for locale-sensitive sorting of certificates by name. -class CertNameComparator { - public: - explicit CertNameComparator(icu::Collator* collator) - : collator_(collator) { - } - - bool operator()(const X509CertificateRefPtr& lhs, - const X509CertificateRefPtr& rhs) const { - string16 lhs_name = GetCertDisplayString(lhs); - string16 rhs_name = GetCertDisplayString(rhs); - if (collator_ == NULL) - return lhs_name < rhs_name; - return l10n_util::CompareString16WithCollator( - collator_, lhs_name, rhs_name) == UCOL_LESS; - } - - private: - icu::Collator* collator_; -}; - -} // namespace - -WifiConfigModel::WifiConfigModel() { -} - -WifiConfigModel::~WifiConfigModel() { -} - -void WifiConfigModel::UpdateCertificates() { - // CertDatabase and its wrappers do not have random access to certificates, - // so build filtered lists once. - net::CertificateList cert_list; - cert_db_.ListCerts(&cert_list); - - // Need TPM token name to filter user certificates. - std::string tpm_token_name; - if (crypto::IsTPMTokenReady()) { - std::string unused_pin; - // TODO(jamescook): Make this asynchronous. It results in a synchronous - // D-Bus call to cryptohome. - crypto::GetTPMTokenInfo(&tpm_token_name, &unused_pin); - } else { - LOG(WARNING) << "TPM token not ready"; - } - - for (net::CertificateList::const_iterator it = cert_list.begin(); - it != cert_list.end(); - ++it) { - net::X509Certificate* cert = it->get(); - net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); - net::CertType type = x509_certificate_model::GetType(cert_handle); - switch (type) { - case net::USER_CERT: { - // Only include user certs that are in the TPM token (and hence - // available via PKCS#11 to flimflam and wpa_supplicant). - std::string cert_token_name = - x509_certificate_model::GetTokenName(cert_handle); - if (cert_token_name == tpm_token_name) - user_certs_.push_back(*it); - break; - } - case net::CA_CERT: { - // Exclude root CA certificates that are built into Chrome. - std::string token_name = - x509_certificate_model::GetTokenName(cert_handle); - if (token_name != kRootCertificateTokenName) - server_ca_certs_.push_back(*it); - break; - } - default: - // We only care about those two types. - break; - } - } - - // Perform locale-sensitive sorting by certificate name. - scoped_ptr<icu::Collator> collator; - UErrorCode error = U_ZERO_ERROR; - collator.reset( - icu::Collator::createInstance( - icu::Locale(g_browser_process->GetApplicationLocale().c_str()), - error)); - if (U_FAILURE(error)) - collator.reset(NULL); - CertNameComparator cert_name_comparator(collator.get()); - std::sort(user_certs_.begin(), user_certs_.end(), cert_name_comparator); - std::sort(server_ca_certs_.begin(), server_ca_certs_.end(), - cert_name_comparator); -} - -int WifiConfigModel::GetUserCertCount() const { - return static_cast<int>(user_certs_.size()); -} - -string16 WifiConfigModel::GetUserCertName(int cert_index) const { - DCHECK_GE(cert_index, 0); - DCHECK_LT(cert_index, static_cast<int>(user_certs_.size())); - net::X509Certificate* cert = user_certs_[cert_index].get(); - return GetCertDisplayString(cert); -} - -std::string WifiConfigModel::GetUserCertPkcs11Id(int cert_index) const { - DCHECK_GE(cert_index, 0); - DCHECK_LT(cert_index, static_cast<int>(user_certs_.size())); - net::X509Certificate* cert = user_certs_[cert_index].get(); - net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); - return x509_certificate_model::GetPkcs11Id(cert_handle); -} - -int WifiConfigModel::GetUserCertIndex(const std::string& pkcs11_id) const { - // The list of user certs is small, so just test each one. - for (int index = 0; index < static_cast<int>(user_certs_.size()); ++index) { - net::X509Certificate* cert = user_certs_[index].get(); - net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); - std::string id = x509_certificate_model::GetPkcs11Id(cert_handle); - if (id == pkcs11_id) - return index; - } - // Not found. - return -1; -} - -int WifiConfigModel::GetServerCaCertCount() const { - return static_cast<int>(server_ca_certs_.size()); -} - -string16 WifiConfigModel::GetServerCaCertName(int cert_index) const { - DCHECK_GE(cert_index, 0); - DCHECK_LT(cert_index, static_cast<int>(server_ca_certs_.size())); - net::X509Certificate* cert = server_ca_certs_[cert_index].get(); - return GetCertDisplayString(cert); -} - -std::string WifiConfigModel::GetServerCaCertNssNickname(int cert_index) const { - DCHECK_GE(cert_index, 0); - DCHECK_LT(cert_index, static_cast<int>(server_ca_certs_.size())); - net::X509Certificate* cert = server_ca_certs_[cert_index].get(); - net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); - return x509_certificate_model::GetNickname(cert_handle); -} - -int WifiConfigModel::GetServerCaCertIndex( - const std::string& nss_nickname) const { - // List of server certs is small, so just test each one. - for (int i = 0; i < static_cast<int>(server_ca_certs_.size()); ++i) { - net::X509Certificate* cert = server_ca_certs_[i].get(); - net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); - std::string nickname = x509_certificate_model::GetNickname(cert_handle); - if (nickname == nss_nickname) - return i; - } - // Not found. - return -1; -} - -} // namespace chromeos diff --git a/chrome/browser/chromeos/options/wifi_config_model.h b/chrome/browser/chromeos/options/wifi_config_model.h deleted file mode 100644 index b56822b..0000000 --- a/chrome/browser/chromeos/options/wifi_config_model.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_CHROMEOS_OPTIONS_WIFI_CONFIG_MODEL_H_ -#define CHROME_BROWSER_CHROMEOS_OPTIONS_WIFI_CONFIG_MODEL_H_ -#pragma once - -#include <string> - -#include "base/string16.h" -#include "net/base/cert_database.h" - -namespace chromeos { - -// Data model for Wi-Fi connection configuration dialog. Mostly concerned -// with certificate management for Extensible Authentication Protocol (EAP) -// enterprise networks. -class WifiConfigModel { - public: - // Constructs a model with empty lists of certificates. If you are - // configuring a 802.1X network, call UpdateCertificates() to build the - // internal cache of certificate names and IDs. - WifiConfigModel(); - ~WifiConfigModel(); - - // Updates the cached certificate lists. - void UpdateCertificates(); - - // Returns the number of user certificates. - int GetUserCertCount() const; - - // Returns a user-visible name for a given user certificate. - string16 GetUserCertName(int cert_index) const; - - // Returns the PKCS#11 ID for a given user certificate. - std::string GetUserCertPkcs11Id(int cert_index) const; - - // Returns the cert_index for a given PKCS#11 user certificate ID, - // or -1 if no certificate with that ID exists. - int GetUserCertIndex(const std::string& pkcs11_id) const; - - // Returns the number of server CA certificates. - int GetServerCaCertCount() const; - - // Returns a user-visible name for a given server CA certificate. - string16 GetServerCaCertName(int cert_index) const; - - // Returns the NSS nickname for a given server CA certificate. - std::string GetServerCaCertNssNickname(int cert_index) const; - - // Returns the cert_index for a given server CA certificate NSS nickname, - // or -1 if no certificate with that ID exists. - int GetServerCaCertIndex(const std::string& nss_nickname) const; - - private: - net::CertDatabase cert_db_; - - // List of user certificates, sorted by name. - net::CertificateList user_certs_; - - // List of server CA certificates, sorted by name. - net::CertificateList server_ca_certs_; - - DISALLOW_COPY_AND_ASSIGN(WifiConfigModel); -}; - -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_OPTIONS_WIFI_CONFIG_MODEL_H_ diff --git a/chrome/browser/chromeos/options/wifi_config_view.cc b/chrome/browser/chromeos/options/wifi_config_view.cc index 63e640c..d39be7b 100644 --- a/chrome/browser/chromeos/options/wifi_config_view.cc +++ b/chrome/browser/chromeos/options/wifi_config_view.cc @@ -7,8 +7,8 @@ #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/cros/network_library.h" #include "chrome/browser/chromeos/login/user_manager.h" -#include "chrome/browser/chromeos/options/wifi_config_model.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "grit/locale_settings.h" @@ -179,15 +179,21 @@ class ComboboxWithWidth : public views::Combobox { class ServerCACertComboboxModel : public ui::ComboboxModel { public: - explicit ServerCACertComboboxModel(WifiConfigModel* wifi_config_model) - : wifi_config_model_(wifi_config_model) { + explicit ServerCACertComboboxModel(CertLibrary* cert_library) + : cert_library_(cert_library) { + DCHECK(cert_library); } virtual ~ServerCACertComboboxModel() {} virtual int GetItemCount() { + if (!cert_library_->CertificatesLoaded()) + return 1; // "Loading" // First "Default", then the certs, then "Do not check". - return wifi_config_model_->GetServerCaCertCount() + 2; + return cert_library_->GetCACertificates().Size() + 2; } virtual string16 GetItemAt(int combo_index) { + if (!cert_library_->CertificatesLoaded()) + return l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_LOADING); if (combo_index == 0) return l10n_util::GetStringUTF16( IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_SERVER_CA_DEFAULT); @@ -195,46 +201,53 @@ class ServerCACertComboboxModel : public ui::ComboboxModel { return l10n_util::GetStringUTF16( IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_SERVER_CA_DO_NOT_CHECK); int cert_index = combo_index - 1; - return wifi_config_model_->GetServerCaCertName(cert_index); + return cert_library_->GetCACertificates().GetDisplayStringAt(cert_index); } private: - WifiConfigModel* wifi_config_model_; + CertLibrary* cert_library_; DISALLOW_COPY_AND_ASSIGN(ServerCACertComboboxModel); }; -class ClientCertComboboxModel : public ui::ComboboxModel { +class UserCertComboboxModel : public ui::ComboboxModel { public: - explicit ClientCertComboboxModel(WifiConfigModel* wifi_config_model) - : wifi_config_model_(wifi_config_model) { + explicit UserCertComboboxModel(CertLibrary* cert_library) + : cert_library_(cert_library) { + DCHECK(cert_library); } - virtual ~ClientCertComboboxModel() {} + virtual ~UserCertComboboxModel() {} virtual int GetItemCount() { - if (wifi_config_model_->GetUserCertCount() == 0) - return 1; // "None installed" item. - return wifi_config_model_->GetUserCertCount(); + if (!cert_library_->CertificatesLoaded()) + return 1; // "Loading" + int num_certs = cert_library_->GetUserCertificates().Size(); + if (num_certs == 0) + return 1; // "None installed" + return num_certs; } virtual string16 GetItemAt(int combo_index) { - if (wifi_config_model_->GetUserCertCount() == 0) + if (!cert_library_->CertificatesLoaded()) + return l10n_util::GetStringUTF16( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_LOADING); + if (cert_library_->GetUserCertificates().Size() == 0) return l10n_util::GetStringUTF16( IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_USER_CERT_NONE_INSTALLED); - return wifi_config_model_->GetUserCertName(combo_index); + return cert_library_->GetUserCertificates().GetDisplayStringAt(combo_index); } private: - WifiConfigModel* wifi_config_model_; - DISALLOW_COPY_AND_ASSIGN(ClientCertComboboxModel); + CertLibrary* cert_library_; + DISALLOW_COPY_AND_ASSIGN(UserCertComboboxModel); }; } // namespace WifiConfigView::WifiConfigView(NetworkConfigView* parent, WifiNetwork* wifi) : ChildNetworkConfigView(parent, wifi), - wifi_config_model_(new WifiConfigModel()), + cert_library_(NULL), ssid_textfield_(NULL), eap_method_combobox_(NULL), phase_2_auth_label_(NULL), phase_2_auth_combobox_(NULL), - client_cert_label_(NULL), - client_cert_combobox_(NULL), + user_cert_label_(NULL), + user_cert_combobox_(NULL), server_ca_cert_label_(NULL), server_ca_cert_combobox_(NULL), identity_label_(NULL), @@ -252,13 +265,13 @@ WifiConfigView::WifiConfigView(NetworkConfigView* parent, WifiNetwork* wifi) WifiConfigView::WifiConfigView(NetworkConfigView* parent, bool show_8021x) : ChildNetworkConfigView(parent), - wifi_config_model_(new WifiConfigModel()), + cert_library_(NULL), ssid_textfield_(NULL), eap_method_combobox_(NULL), phase_2_auth_label_(NULL), phase_2_auth_combobox_(NULL), - client_cert_label_(NULL), - client_cert_combobox_(NULL), + user_cert_label_(NULL), + user_cert_combobox_(NULL), server_ca_cert_label_(NULL), server_ca_cert_combobox_(NULL), identity_label_(NULL), @@ -275,6 +288,8 @@ WifiConfigView::WifiConfigView(NetworkConfigView* parent, bool show_8021x) } WifiConfigView::~WifiConfigView() { + if (cert_library_) + cert_library_->RemoveObserver(this); } string16 WifiConfigView::GetTitle() { @@ -300,18 +315,23 @@ bool WifiConfigView::CanLogin() { && eap_method_combobox_->selected_item() == EAP_METHOD_INDEX_NONE) return false; - // Show an error and block login if certs are required but user has none. - if (UserCertRequired() && wifi_config_model_->GetUserCertCount() == 0) + // Block login if certs are required but user has none. + if (UserCertRequired() && cert_library_->GetUserCertificates().Size() == 0) return false; return true; } -bool WifiConfigView::UserCertRequired() const { +bool WifiConfigView::UserCertRequired() { + if (!cert_library_) + return false; // return false until cert_library_ is initialized. // Only EAP-TLS requires a user certificate. - return eap_method_combobox_ && + if (eap_method_combobox_ && eap_method_combobox_->IsEnabled() && - eap_method_combobox_->selected_item() == EAP_METHOD_INDEX_TLS; + eap_method_combobox_->selected_item() == EAP_METHOD_INDEX_TLS) { + return true; + } + return false; } void WifiConfigView::UpdateDialogButtons() { @@ -319,6 +339,7 @@ void WifiConfigView::UpdateDialogButtons() { } void WifiConfigView::RefreshEapFields() { + DCHECK(cert_library_); int selected = eap_method_combobox_->selected_item(); // If EAP method changes, the phase 2 auth choices may have changed also. @@ -335,16 +356,23 @@ void WifiConfigView::RefreshEapFields() { if (!passphrase_textfield_->IsEnabled()) passphrase_textfield_->SetText(string16()); - // Client certs only for EAP-TLS - bool is_tls = selected == EAP_METHOD_INDEX_TLS; - client_cert_label_->SetEnabled(is_tls); - bool have_user_certs = wifi_config_model_->GetUserCertCount() > 0; - client_cert_combobox_->SetEnabled(is_tls && have_user_certs); + // User certs only for EAP-TLS + bool certs_loading = !cert_library_->CertificatesLoaded(); + bool user_cert_enabled = (selected == EAP_METHOD_INDEX_TLS); + user_cert_label_->SetEnabled(user_cert_enabled); + bool have_user_certs = + !certs_loading && cert_library_->GetUserCertificates().Size() > 0; + user_cert_combobox_->SetEnabled(user_cert_enabled && have_user_certs); + user_cert_combobox_->ModelChanged(); + user_cert_combobox_->SetSelectedItem(0); // No server CA certs for LEAP - server_ca_cert_combobox_->SetEnabled(selected != EAP_METHOD_INDEX_NONE && - selected != EAP_METHOD_INDEX_LEAP); - server_ca_cert_label_->SetEnabled(server_ca_cert_combobox_->IsEnabled()); + bool ca_cert_enabled = + (selected != EAP_METHOD_INDEX_NONE && selected != EAP_METHOD_INDEX_LEAP); + server_ca_cert_label_->SetEnabled(ca_cert_enabled); + server_ca_cert_combobox_->SetEnabled(ca_cert_enabled && !certs_loading); + server_ca_cert_combobox_->ModelChanged(); + server_ca_cert_combobox_->SetSelectedItem(0); // No anonymous identity if no phase 2 auth. identity_anonymous_textfield_->SetEnabled( @@ -357,9 +385,17 @@ void WifiConfigView::RefreshEapFields() { void WifiConfigView::UpdateErrorLabel() { std::string error_msg; - if (UserCertRequired() && wifi_config_model_->GetUserCertCount() == 0) - error_msg = l10n_util::GetStringUTF8( - IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PLEASE_INSTALL_USER_CERT); + if (UserCertRequired() && + cert_library_->CertificatesLoaded() && + cert_library_->GetUserCertificates().Size() == 0) { + if (!UserManager::Get()->user_is_logged_in()) { + error_msg = l10n_util::GetStringUTF8( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_LOGIN_FOR_USER_CERT); + } else { + error_msg = l10n_util::GetStringUTF8( + IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PLEASE_INSTALL_USER_CERT); + } + } if (!service_path_.empty()) { NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); const WifiNetwork* wifi = cros->FindWifiNetworkByPath(service_path_); @@ -438,6 +474,11 @@ void WifiConfigView::ItemChanged(views::Combobox* combo_box, UpdateDialogButtons(); } +void WifiConfigView::OnCertificatesLoaded(bool initial_load) { + RefreshEapFields(); + UpdateErrorLabel(); +} + bool WifiConfigView::Login() { NetworkLibrary* cros = CrosLibrary::Get()->GetNetworkLibrary(); if (service_path_.empty()) { @@ -540,6 +581,7 @@ EAPPhase2Auth WifiConfigView::GetEapPhase2Auth() const { std::string WifiConfigView::GetEapServerCaCertNssNickname() const { DCHECK(server_ca_cert_combobox_); + DCHECK(cert_library_); int selected = server_ca_cert_combobox_->selected_item(); if (selected == 0) { // First item is "Default". @@ -549,8 +591,9 @@ std::string WifiConfigView::GetEapServerCaCertNssNickname() const { // Last item is "Do not check". return std::string(); } else { + DCHECK(cert_library_); int cert_index = selected - 1; - return wifi_config_model_->GetServerCaCertNssNickname(cert_index); + return cert_library_->GetCACertificates().GetNicknameAt(cert_index); } } @@ -561,13 +604,14 @@ bool WifiConfigView::GetEapUseSystemCas() const { } std::string WifiConfigView::GetEapClientCertPkcs11Id() const { - DCHECK(client_cert_combobox_); - if (wifi_config_model_->GetUserCertCount() == 0) { + DCHECK(user_cert_combobox_); + DCHECK(cert_library_); + if (cert_library_->GetUserCertificates().Size() == 0) { return std::string(); // "None installed" } else { // Certificates are listed in the order they appear in the model. - int selected = client_cert_combobox_->selected_item(); - return wifi_config_model_->GetUserCertPkcs11Id(selected); + int selected = user_cert_combobox_->selected_item(); + return cert_library_->GetUserCertificates().GetPkcs11IdAt(selected); } } @@ -656,9 +700,12 @@ void WifiConfigView::Init(WifiNetwork* wifi, bool show_8021x) { layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); } + // Only enumerate certificates in the data model for 802.1X networks. if (show_8021x) { - // Only enumerate certificates in the data model for 802.1X networks. - wifi_config_model_->UpdateCertificates(); + // Initialize cert_library_ for 802.1X netoworks. + cert_library_ = chromeos::CrosLibrary::Get()->GetCertLibrary(); + cert_library_->AddObserver(this); + cert_library_->RequestCertificates(); // EAP method layout->StartRow(0, column_view_set_id); @@ -690,7 +737,7 @@ void WifiConfigView::Init(WifiNetwork* wifi, bool show_8021x) { IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_SERVER_CA))); layout->AddView(server_ca_cert_label_); server_ca_cert_combobox_ = new ComboboxWithWidth( - new ServerCACertComboboxModel(wifi_config_model_.get()), + new ServerCACertComboboxModel(cert_library_), ChildNetworkConfigView::kPassphraseWidth); server_ca_cert_label_->SetEnabled(false); server_ca_cert_combobox_->SetEnabled(false); @@ -698,18 +745,18 @@ void WifiConfigView::Init(WifiNetwork* wifi, bool show_8021x) { layout->AddView(server_ca_cert_combobox_); layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); - // Client certificate + // User certificate layout->StartRow(0, column_view_set_id); - client_cert_label_ = new views::Label( + user_cert_label_ = new views::Label( UTF16ToWide(l10n_util::GetStringUTF16( IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT))); - layout->AddView(client_cert_label_); - client_cert_combobox_ = new views::Combobox( - new ClientCertComboboxModel(wifi_config_model_.get())); - client_cert_label_->SetEnabled(false); - client_cert_combobox_->SetEnabled(false); - client_cert_combobox_->set_listener(this); - layout->AddView(client_cert_combobox_); + layout->AddView(user_cert_label_); + user_cert_combobox_ = new views::Combobox( + new UserCertComboboxModel(cert_library_)); + user_cert_label_->SetEnabled(false); + user_cert_combobox_->SetEnabled(false); + user_cert_combobox_->set_listener(this); + layout->AddView(user_cert_combobox_); layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); // Identity @@ -843,7 +890,8 @@ void WifiConfigView::Init(WifiNetwork* wifi, bool show_8021x) { } } else { // select the certificate if available - int cert_index = wifi_config_model_->GetServerCaCertIndex(nss_nickname); + int cert_index = + cert_library_->GetCACertificates().FindCertByNickname(nss_nickname); if (cert_index >= 0) { // Skip item for "Default" server_ca_cert_combobox_->SetSelectedItem(1 + cert_index); @@ -851,14 +899,15 @@ void WifiConfigView::Init(WifiNetwork* wifi, bool show_8021x) { } } - // Client certificate - if (client_cert_combobox_->IsEnabled()) { + // User certificate + if (user_cert_combobox_->IsEnabled()) { const std::string& pkcs11_id = (wifi ? wifi->eap_client_cert_pkcs11_id() : std::string()); if (!pkcs11_id.empty()) { - int cert_index = wifi_config_model_->GetUserCertIndex(pkcs11_id); + int cert_index = + cert_library_->GetUserCertificates().FindCertByPkcs11Id(pkcs11_id); if (cert_index >= 0) { - client_cert_combobox_->SetSelectedItem(cert_index); + user_cert_combobox_->SetSelectedItem(cert_index); } } } diff --git a/chrome/browser/chromeos/options/wifi_config_view.h b/chrome/browser/chromeos/options/wifi_config_view.h index da5ae79..6f21e45 100644 --- a/chrome/browser/chromeos/options/wifi_config_view.h +++ b/chrome/browser/chromeos/options/wifi_config_view.h @@ -10,7 +10,7 @@ #include "base/memory/scoped_ptr.h" #include "base/string16.h" -#include "chrome/browser/chromeos/cros/network_library.h" +#include "chrome/browser/chromeos/cros/cert_library.h" #include "chrome/browser/chromeos/options/network_config_view.h" #include "ui/base/models/combobox_model.h" #include "views/controls/button/button.h" @@ -23,17 +23,17 @@ class Checkbox; class ImageButton; class Label; } + class FilePath; namespace chromeos { -class WifiConfigModel; - // A dialog box for showing a password textfield. class WifiConfigView : public ChildNetworkConfigView, public views::TextfieldController, public views::ButtonListener, - public views::Combobox::Listener { + public views::Combobox::Listener, + public CertLibrary::Observer { public: // Wifi login dialog for wifi network |wifi|. |wifi| must be a non NULL // pointer to a WifiNetwork in NetworkLibrary. @@ -43,17 +43,21 @@ class WifiConfigView : public ChildNetworkConfigView, virtual ~WifiConfigView(); // views::TextfieldController: - virtual void ContentsChanged(views::Textfield* sender, - const string16& new_contents); - virtual bool HandleKeyEvent(views::Textfield* sender, - const views::KeyEvent& key_event); + virtual void ContentsChanged( + views::Textfield* sender, const string16& new_contents) OVERRIDE; + virtual bool HandleKeyEvent( + views::Textfield* sender, const views::KeyEvent& key_event) OVERRIDE; // views::ButtonListener: - virtual void ButtonPressed(views::Button* sender, const views::Event& event); + virtual void ButtonPressed( + views::Button* sender, const views::Event& event) OVERRIDE; // views::Combobox::Listener: - virtual void ItemChanged(views::Combobox* combo_box, - int prev_index, int new_index); + virtual void ItemChanged( + views::Combobox* combo_box, int prev_index, int new_index) OVERRIDE; + + // CertLibrary::Observer: + virtual void OnCertificatesLoaded(bool initial_load) OVERRIDE; // ChildNetworkConfigView implementation. virtual string16 GetTitle() OVERRIDE; @@ -83,7 +87,7 @@ class WifiConfigView : public ChildNetworkConfigView, bool GetSaveCredentials() const; // Returns true if the EAP method requires a user certificate. - bool UserCertRequired() const; + bool UserCertRequired(); // Updates state of the Login button. void UpdateDialogButtons(); @@ -94,14 +98,14 @@ class WifiConfigView : public ChildNetworkConfigView, // Updates the error text label. void UpdateErrorLabel(); - scoped_ptr<WifiConfigModel> wifi_config_model_; + CertLibrary* cert_library_; views::Textfield* ssid_textfield_; views::Combobox* eap_method_combobox_; views::Label* phase_2_auth_label_; views::Combobox* phase_2_auth_combobox_; - views::Label* client_cert_label_; - views::Combobox* client_cert_combobox_; + views::Label* user_cert_label_; + views::Combobox* user_cert_combobox_; views::Label* server_ca_cert_label_; views::Combobox* server_ca_cert_combobox_; views::Label* identity_label_; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 435c88b..ea52c53 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -359,6 +359,8 @@ 'browser/chromeos/cros/brightness_library.h', 'browser/chromeos/cros/burn_library.cc', 'browser/chromeos/cros/burn_library.h', + 'browser/chromeos/cros/cert_library.cc', + 'browser/chromeos/cros/cert_library.h', 'browser/chromeos/cros/cros_library.cc', 'browser/chromeos/cros/cros_library.h', 'browser/chromeos/cros/cros_library_loader.cc', @@ -654,8 +656,6 @@ 'browser/chromeos/options/network_config_view.h', 'browser/chromeos/options/take_photo_dialog.cc', 'browser/chromeos/options/take_photo_dialog.h', - 'browser/chromeos/options/wifi_config_model.cc', - 'browser/chromeos/options/wifi_config_model.h', 'browser/chromeos/options/wifi_config_view.cc', 'browser/chromeos/options/wifi_config_view.h', 'browser/chromeos/options/vpn_config_view.cc', diff --git a/crypto/nss_util.cc b/crypto/nss_util.cc index e484abe..3b393fc 100644 --- a/crypto/nss_util.cc +++ b/crypto/nss_util.cc @@ -226,6 +226,47 @@ class NSSInitSingleton { EnsureTPMTokenReady(); } + // This is called whenever we want to make sure opencryptoki is + // properly loaded, because it can fail shortly after the initial + // login while the PINs are being initialized, and we want to retry + // if this happens. + bool EnsureTPMTokenReady() { + // If EnableTPMTokenForNSS hasn't been called, or if everything is + // already initialized, then this call succeeds. + if (tpm_token_info_delegate_.get() == NULL || + (opencryptoki_module_ && tpm_slot_)) { + return true; + } + + if (tpm_token_info_delegate_->IsTokenReady()) { + // This tries to load the opencryptoki module so NSS can talk to + // the hardware TPM. + if (!opencryptoki_module_) { + opencryptoki_module_ = LoadModule( + kOpencryptokiModuleName, + kOpencryptokiPath, + // trustOrder=100 -- means it'll select this as the most + // trusted slot for the mechanisms it provides. + // slotParams=... -- selects RSA as the only mechanism, and only + // asks for the password when necessary (instead of every + // time, or after a timeout). + "trustOrder=100 slotParams=(1={slotFlags=[RSA] askpw=only})"); + } + if (opencryptoki_module_) { + // If this gets set, then we'll use the TPM for certs with + // private keys, otherwise we'll fall back to the software + // implementation. + tpm_slot_ = GetTPMSlot(); + return tpm_slot_ != NULL; + } + } + return false; + } + + bool IsTPMTokenAvailable() { + return tpm_token_info_delegate_->IsTokenAvailable(); + } + void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { tpm_token_info_delegate_->GetTokenInfo(token_name, user_pin); } @@ -239,6 +280,7 @@ class NSSInitSingleton { GetTPMTokenInfo(&token_name, NULL); return FindSlotWithTokenName(token_name); } + #endif // defined(OS_CHROMEOS) @@ -487,45 +529,6 @@ class NSSInitSingleton { return db_slot; } -#if defined(OS_CHROMEOS) - // This is called whenever we want to make sure opencryptoki is - // properly loaded, because it can fail shortly after the initial - // login while the PINs are being initialized, and we want to retry - // if this happens. - bool EnsureTPMTokenReady() { - // If EnableTPMTokenForNSS hasn't been called, or if everything is - // already initialized, then this call succeeds. - if (tpm_token_info_delegate_.get() == NULL || - (opencryptoki_module_ && tpm_slot_)) { - return true; - } - - if (tpm_token_info_delegate_->IsTokenReady()) { - // This tries to load the opencryptoki module so NSS can talk to - // the hardware TPM. - if (!opencryptoki_module_) { - opencryptoki_module_ = LoadModule( - kOpencryptokiModuleName, - kOpencryptokiPath, - // trustOrder=100 -- means it'll select this as the most - // trusted slot for the mechanisms it provides. - // slotParams=... -- selects RSA as the only mechanism, and only - // asks for the password when necessary (instead of every - // time, or after a timeout). - "trustOrder=100 slotParams=(1={slotFlags=[RSA] askpw=only})"); - } - if (opencryptoki_module_) { - // If this gets set, then we'll use the TPM for certs with - // private keys, otherwise we'll fall back to the software - // implementation. - tpm_slot_ = GetTPMSlot(); - return tpm_slot_ != NULL; - } - } - return false; - } -#endif - // If this is set to true NSS is forced to be initialized without a DB. static bool force_nodb_init_; @@ -680,10 +683,18 @@ void GetTPMTokenInfo(std::string* token_name, std::string* user_pin) { g_nss_singleton.Get().GetTPMTokenInfo(token_name, user_pin); } +bool IsTPMTokenAvailable() { + return g_nss_singleton.Get().IsTPMTokenAvailable(); +} + bool IsTPMTokenReady() { return g_nss_singleton.Get().IsTPMTokenReady(); } +bool EnsureTPMTokenReady() { + return g_nss_singleton.Get().EnsureTPMTokenReady(); +} + #endif // defined(OS_CHROMEOS) // TODO(port): Implement this more simply. We can convert by subtracting an diff --git a/crypto/nss_util.h b/crypto/nss_util.h index 1244db9..19298ca 100644 --- a/crypto/nss_util.h +++ b/crypto/nss_util.h @@ -93,7 +93,17 @@ class TPMTokenInfoDelegate { public: TPMTokenInfoDelegate(); virtual ~TPMTokenInfoDelegate(); + + // Returns true if the hardware supports a TPM Token and the TPM is enabled. + virtual bool IsTokenAvailable() const = 0; + + // Returns true if the TPM and PKCS#11 token slot is ready to be used. + // If IsTokenAvailable() is false this should return false. + // If IsTokenAvailable() is true, this should eventually return true. virtual bool IsTokenReady() const = 0; + + // Fetches token properties. TODO(stevenjb): make this interface asynchronous + // so that the implementation does not have to be blocking. virtual void GetTokenInfo(std::string* token_name, std::string* user_pin) const = 0; }; @@ -110,11 +120,18 @@ void EnableTPMTokenForNSS(TPMTokenInfoDelegate* delegate); // EnableTPMTokenForNSS has been called with a non-null delegate. void GetTPMTokenInfo(std::string* token_name, std::string* user_pin); +// Returns true if the machine has a TPM and it can be used to store tokens. +bool IsTPMTokenAvailable(); + // Returns true if the TPM is owned and PKCS#11 initialized with the // user and security officer PINs, and has been enabled in NSS by // calling EnableTPMForNSS, and opencryptoki has been successfully // loaded into NSS. bool IsTPMTokenReady(); + +// Same as IsTPMTokenReady() except this attempts to initialize the token +// if necessary. +bool EnsureTPMTokenReady(); #endif // Convert a NSS PRTime value into a base::Time object. |