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 17namespace chromeos { 18 19namespace { 20 21typedef scoped_refptr<net::X509Certificate> X509CertificateRefPtr; 22 23// Root CA certificates that are built into Chrome use this token name. 24const char* const kRootCertificateTokenName = "Builtin Object Token"; 25 26// Returns a user-visible name for a given certificate. 27string16 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. 35class 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 57WifiConfigModel::WifiConfigModel() { 58} 59 60WifiConfigModel::~WifiConfigModel() { 61} 62 63void 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 107int WifiConfigModel::GetUserCertCount() const { 108 return static_cast<int>(user_certs_.size()); 109} 110 111string16 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 118std::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 126int 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 139int WifiConfigModel::GetServerCaCertCount() const { 140 return static_cast<int>(server_ca_certs_.size()); 141} 142 143string16 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 150std::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 158int 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