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