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.
GetCertDisplayString(const net::X509Certificate * cert)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:
CertNameComparator(icu::Collator * collator)37 explicit CertNameComparator(icu::Collator* collator)
38 : collator_(collator) {
39 }
40
operator ()(const X509CertificateRefPtr & lhs,const X509CertificateRefPtr & rhs) const41 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
WifiConfigModel()57 WifiConfigModel::WifiConfigModel() {
58 }
59
~WifiConfigModel()60 WifiConfigModel::~WifiConfigModel() {
61 }
62
UpdateCertificates()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
GetUserCertCount() const107 int WifiConfigModel::GetUserCertCount() const {
108 return static_cast<int>(user_certs_.size());
109 }
110
GetUserCertName(int cert_index) const111 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
GetUserCertPkcs11Id(int cert_index) const118 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
GetUserCertIndex(const std::string & pkcs11_id) const126 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
GetServerCaCertCount() const139 int WifiConfigModel::GetServerCaCertCount() const {
140 return static_cast<int>(server_ca_certs_.size());
141 }
142
GetServerCaCertName(int cert_index) const143 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
GetServerCaCertNssNickname(int cert_index) const150 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
GetServerCaCertIndex(const std::string & nss_nickname) const158 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