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