// 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 "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); 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: 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(cert_index >= 0); DCHECK(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(cert_index >= 0); DCHECK(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(cert_index >= 0); DCHECK(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(cert_index >= 0); DCHECK(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