1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Use of this source code is governed by a BSD-style license that can be 3ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// found in the LICENSE file. 4ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/chromeos/options/wifi_config_model.h" 6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <algorithm> 8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/utf_string_conversions.h" 10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/browser_process.h" // g_browser_process 11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/net/x509_certificate_model.h" 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "net/base/cert_database.h" 13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "net/base/x509_certificate.h" 14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "ui/base/l10n/l10n_util_collator.h" // CompareString16WithCollator 15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "unicode/coll.h" // icu::Collator 16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace chromeos { 18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace { 20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsentypedef scoped_refptr<net::X509Certificate> X509CertificateRefPtr; 22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Root CA certificates that are built into Chrome use this token name. 24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst char* const kRootCertificateTokenName = "Builtin Object Token"; 25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Returns a user-visible name for a given certificate. 27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstring16 GetCertDisplayString(const net::X509Certificate* cert) { 28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(cert); 29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::string name_or_nick = 30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen x509_certificate_model::GetCertNameOrNickname(cert->os_cert_handle()); 31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return UTF8ToUTF16(name_or_nick); 32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Comparison functor for locale-sensitive sorting of certificates by name. 35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass CertNameComparator { 36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen public: 37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen explicit CertNameComparator(icu::Collator* collator) 38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen : collator_(collator) { 39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool operator()(const X509CertificateRefPtr& lhs, 42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const X509CertificateRefPtr& rhs) const { 43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen string16 lhs_name = GetCertDisplayString(lhs); 44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen string16 rhs_name = GetCertDisplayString(rhs); 45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (collator_ == NULL) 46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return lhs_name < rhs_name; 47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return l10n_util::CompareString16WithCollator( 48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen collator_, lhs_name, rhs_name) == UCOL_LESS; 49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen private: 52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen icu::Collator* collator_; 53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}; 54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} // namespace 56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenWifiConfigModel::WifiConfigModel() { 58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenWifiConfigModel::~WifiConfigModel() { 61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid WifiConfigModel::UpdateCertificates() { 64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // CertDatabase and its wrappers do not have random access to certificates, 65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // so build filtered lists once. 66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::CertificateList cert_list; 67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen cert_db_.ListCerts(&cert_list); 68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (net::CertificateList::const_iterator it = cert_list.begin(); 69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen it != cert_list.end(); 70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ++it) { 71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::X509Certificate* cert = it->get(); 72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); 73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::CertType type = x509_certificate_model::GetType(cert_handle); 74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen switch (type) { 75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case net::USER_CERT: 76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen user_certs_.push_back(*it); 77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen break; 78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen case net::CA_CERT: { 79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Exclude root CA certificates that are built into Chrome. 80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::string token_name = 81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen x509_certificate_model::GetTokenName(cert_handle); 82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (token_name != kRootCertificateTokenName) 83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen server_ca_certs_.push_back(*it); 84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen break; 85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen default: 87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // We only care about those two types. 88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen break; 89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Perform locale-sensitive sorting by certificate name. 93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen scoped_ptr<icu::Collator> collator; 94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen UErrorCode error = U_ZERO_ERROR; 95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen collator.reset( 96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen icu::Collator::createInstance( 97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen icu::Locale(g_browser_process->GetApplicationLocale().c_str()), 98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen error)); 99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (U_FAILURE(error)) 100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen collator.reset(NULL); 101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen CertNameComparator cert_name_comparator(collator.get()); 102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::sort(user_certs_.begin(), user_certs_.end(), cert_name_comparator); 103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::sort(server_ca_certs_.begin(), server_ca_certs_.end(), 104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen cert_name_comparator); 105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint WifiConfigModel::GetUserCertCount() const { 108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return static_cast<int>(user_certs_.size()); 109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstring16 WifiConfigModel::GetUserCertName(int cert_index) const { 112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(cert_index >= 0); 113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(cert_index < static_cast<int>(user_certs_.size())); 114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::X509Certificate* cert = user_certs_[cert_index].get(); 115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return GetCertDisplayString(cert); 116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstd::string WifiConfigModel::GetUserCertPkcs11Id(int cert_index) const { 119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(cert_index >= 0); 120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(cert_index < static_cast<int>(user_certs_.size())); 121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::X509Certificate* cert = user_certs_[cert_index].get(); 122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); 123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return x509_certificate_model::GetPkcs11Id(cert_handle); 124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint WifiConfigModel::GetUserCertIndex(const std::string& pkcs11_id) const { 127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // The list of user certs is small, so just test each one. 128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (int index = 0; index < static_cast<int>(user_certs_.size()); ++index) { 129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::X509Certificate* cert = user_certs_[index].get(); 130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); 131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::string id = x509_certificate_model::GetPkcs11Id(cert_handle); 132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (id == pkcs11_id) 133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return index; 134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Not found. 136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return -1; 137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint WifiConfigModel::GetServerCaCertCount() const { 140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return static_cast<int>(server_ca_certs_.size()); 141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstring16 WifiConfigModel::GetServerCaCertName(int cert_index) const { 144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(cert_index >= 0); 145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(cert_index < static_cast<int>(server_ca_certs_.size())); 146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::X509Certificate* cert = server_ca_certs_[cert_index].get(); 147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return GetCertDisplayString(cert); 148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstd::string WifiConfigModel::GetServerCaCertNssNickname(int cert_index) const { 151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(cert_index >= 0); 152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen DCHECK(cert_index < static_cast<int>(server_ca_certs_.size())); 153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::X509Certificate* cert = server_ca_certs_[cert_index].get(); 154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); 155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return x509_certificate_model::GetNickname(cert_handle); 156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint WifiConfigModel::GetServerCaCertIndex( 159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const std::string& nss_nickname) const { 160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // List of server certs is small, so just test each one. 161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen for (int i = 0; i < static_cast<int>(server_ca_certs_.size()); ++i) { 162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::X509Certificate* cert = server_ca_certs_[i].get(); 163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); 164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen std::string nickname = x509_certificate_model::GetNickname(cert_handle); 165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen if (nickname == nss_nickname) 166ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return i; 167ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen } 168ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Not found. 169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen return -1; 170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} 171ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} // namespace chromeos 173