Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / options / cert_library.cc
1 // Copyright 2013 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/cert_library.h"
6
7 #include <algorithm>
8
9 #include "base/command_line.h"
10 #include "base/i18n/string_compare.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/observer_list_threadsafe.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/browser_process.h"  // g_browser_process
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/common/net/x509_certificate_model.h"
19 #include "chromeos/dbus/cryptohome_client.h"
20 #include "chromeos/dbus/dbus_thread_manager.h"
21 #include "chromeos/login/login_state.h"
22 #include "chromeos/network/onc/onc_utils.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "crypto/nss_util.h"
25 #include "grit/generated_resources.h"
26 #include "net/cert/cert_database.h"
27 #include "net/cert/nss_cert_database.h"
28 #include "third_party/icu/source/i18n/unicode/coll.h"  // icu::Collator
29 #include "ui/base/l10n/l10n_util.h"
30 #include "ui/base/l10n/l10n_util_collator.h"
31
32 namespace chromeos {
33
34 namespace {
35
36 // Root CA certificates that are built into Chrome use this token name.
37 const char kRootCertificateTokenName[] = "Builtin Object Token";
38
39 base::string16 GetDisplayString(net::X509Certificate* cert,
40                                 bool hardware_backed) {
41   std::string org;
42   if (!cert->subject().organization_names.empty())
43     org = cert->subject().organization_names[0];
44   if (org.empty())
45     org = cert->subject().GetDisplayName();
46   base::string16 issued_by = base::UTF8ToUTF16(
47       x509_certificate_model::GetIssuerCommonName(cert->os_cert_handle(),
48                                                   org));  // alternative text
49   base::string16 issued_to = base::UTF8ToUTF16(
50       x509_certificate_model::GetCertNameOrNickname(cert->os_cert_handle()));
51
52   if (hardware_backed) {
53     return l10n_util::GetStringFUTF16(
54         IDS_CERT_MANAGER_HARDWARE_BACKED_KEY_FORMAT_LONG,
55         issued_by,
56         issued_to,
57         l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED));
58   } else {
59     return l10n_util::GetStringFUTF16(
60         IDS_CERT_MANAGER_KEY_FORMAT_LONG,
61         issued_by,
62         issued_to);
63   }
64 }
65
66 std::string CertToPEM(const net::X509Certificate& cert) {
67   std::string pem_encoded_cert;
68   if (!net::X509Certificate::GetPEMEncoded(cert.os_cert_handle(),
69                                            &pem_encoded_cert)) {
70     LOG(ERROR) << "Couldn't PEM-encode certificate";
71     return std::string();
72   }
73   return pem_encoded_cert;
74 }
75
76 }  // namespace
77
78 class CertNameComparator {
79  public:
80   explicit CertNameComparator(icu::Collator* collator)
81       : collator_(collator) {
82   }
83
84   bool operator()(const scoped_refptr<net::X509Certificate>& lhs,
85                   const scoped_refptr<net::X509Certificate>& rhs) const {
86     base::string16 lhs_name = GetDisplayString(lhs.get(), false);
87     base::string16 rhs_name = GetDisplayString(rhs.get(), false);
88     if (collator_ == NULL)
89       return lhs_name < rhs_name;
90     return base::i18n::CompareString16WithCollator(
91         collator_, lhs_name, rhs_name) == UCOL_LESS;
92   }
93
94  private:
95   icu::Collator* collator_;
96 };
97
98 static CertLibrary* g_cert_library = NULL;
99
100 // static
101 void CertLibrary::Initialize() {
102   CHECK(!g_cert_library);
103   g_cert_library = new CertLibrary();
104 }
105
106 // static
107 void CertLibrary::Shutdown() {
108   CHECK(g_cert_library);
109   delete g_cert_library;
110   g_cert_library = NULL;
111 }
112
113 // static
114 CertLibrary* CertLibrary::Get() {
115   CHECK(g_cert_library) << "CertLibrary::Get() called before Initialize()";
116   return g_cert_library;
117 }
118
119 // static
120 bool CertLibrary::IsInitialized() {
121   return g_cert_library;
122 }
123
124 CertLibrary::CertLibrary() {
125   CertLoader::Get()->AddObserver(this);
126 }
127
128 CertLibrary::~CertLibrary() {
129   CertLoader::Get()->RemoveObserver(this);
130 }
131
132 void CertLibrary::AddObserver(CertLibrary::Observer* observer) {
133   observer_list_.AddObserver(observer);
134 }
135
136 void CertLibrary::RemoveObserver(CertLibrary::Observer* observer) {
137   observer_list_.RemoveObserver(observer);
138 }
139
140 bool CertLibrary::CertificatesLoading() const {
141   return CertLoader::Get()->CertificatesLoading();
142 }
143
144 bool CertLibrary::CertificatesLoaded() const {
145   return CertLoader::Get()->certificates_loaded();
146 }
147
148 bool CertLibrary::IsHardwareBacked() const {
149   return CertLoader::Get()->IsHardwareBacked();
150 }
151
152 int CertLibrary::NumCertificates(CertType type) const {
153   const net::CertificateList& cert_list = GetCertificateListForType(type);
154   return static_cast<int>(cert_list.size());
155 }
156
157 base::string16 CertLibrary::GetCertDisplayStringAt(CertType type,
158                                                    int index) const {
159   net::X509Certificate* cert = GetCertificateAt(type, index);
160   bool hardware_backed = IsCertHardwareBackedAt(type, index);
161   return GetDisplayString(cert, hardware_backed);
162 }
163
164 std::string CertLibrary::GetServerCACertPEMAt(int index) const {
165   return CertToPEM(*GetCertificateAt(CERT_TYPE_SERVER_CA, index));
166 }
167
168 std::string CertLibrary::GetUserCertPkcs11IdAt(int index) const {
169   net::X509Certificate* cert = GetCertificateAt(CERT_TYPE_USER, index);
170   return CertLoader::GetPkcs11IdForCert(*cert);
171 }
172
173 bool CertLibrary::IsCertHardwareBackedAt(CertType type, int index) const {
174   net::X509Certificate* cert = GetCertificateAt(type, index);
175   return CertLoader::Get()->IsCertificateHardwareBacked(cert);
176 }
177
178 int CertLibrary::GetServerCACertIndexByPEM(
179     const std::string& pem_encoded) const {
180   int num_certs = NumCertificates(CERT_TYPE_SERVER_CA);
181   for (int index = 0; index < num_certs; ++index) {
182     net::X509Certificate* cert = GetCertificateAt(CERT_TYPE_SERVER_CA, index);
183     if (CertToPEM(*cert) != pem_encoded)
184       continue;
185     return index;
186   }
187   return -1;
188 }
189
190 int CertLibrary::GetUserCertIndexByPkcs11Id(
191     const std::string& pkcs11_id) const {
192   int num_certs = NumCertificates(CERT_TYPE_USER);
193   for (int index = 0; index < num_certs; ++index) {
194     net::X509Certificate* cert = GetCertificateAt(CERT_TYPE_USER, index);
195     std::string id = CertLoader::GetPkcs11IdForCert(*cert);
196     if (id == pkcs11_id)
197       return index;
198   }
199   return -1;  // Not found.
200 }
201
202 void CertLibrary::OnCertificatesLoaded(const net::CertificateList& cert_list,
203                                        bool initial_load) {
204   CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
205   VLOG(1) << "CertLibrary::OnCertificatesLoaded: " << cert_list.size();
206   certs_.clear();
207   user_certs_.clear();
208   server_certs_.clear();
209   server_ca_certs_.clear();
210
211   // Add certificates to the appropriate list.
212   for (net::CertificateList::const_iterator iter = cert_list.begin();
213        iter != cert_list.end(); ++iter) {
214     certs_.push_back(iter->get());
215     net::X509Certificate::OSCertHandle cert_handle =
216         iter->get()->os_cert_handle();
217     net::CertType type = x509_certificate_model::GetType(cert_handle);
218     switch (type) {
219       case net::USER_CERT:
220         user_certs_.push_back(iter->get());
221         break;
222       case net::SERVER_CERT:
223         server_certs_.push_back(iter->get());
224         break;
225       case net::CA_CERT: {
226         // Exclude root CA certificates that are built into Chrome.
227         std::string token_name =
228             x509_certificate_model::GetTokenName(cert_handle);
229         if (token_name != kRootCertificateTokenName)
230           server_ca_certs_.push_back(iter->get());
231         break;
232       }
233       default:
234         break;
235     }
236   }
237
238   // Perform locale-sensitive sorting by certificate name.
239   UErrorCode error = U_ZERO_ERROR;
240   scoped_ptr<icu::Collator> collator(icu::Collator::createInstance(
241       icu::Locale(g_browser_process->GetApplicationLocale().c_str()), error));
242   if (U_FAILURE(error))
243     collator.reset();
244   CertNameComparator cert_name_comparator(collator.get());
245   std::sort(certs_.begin(), certs_.end(), cert_name_comparator);
246   std::sort(user_certs_.begin(), user_certs_.end(), cert_name_comparator);
247   std::sort(server_certs_.begin(), server_certs_.end(), cert_name_comparator);
248   std::sort(server_ca_certs_.begin(), server_ca_certs_.end(),
249             cert_name_comparator);
250
251   VLOG(1) << "certs_: " << certs_.size();
252   VLOG(1) << "user_certs_: " << user_certs_.size();
253   VLOG(1) << "server_certs_: " << server_certs_.size();
254   VLOG(1) << "server_ca_certs_: " << server_ca_certs_.size();
255
256   FOR_EACH_OBSERVER(CertLibrary::Observer, observer_list_,
257                     OnCertificatesLoaded(initial_load));
258 }
259
260 net::X509Certificate* CertLibrary::GetCertificateAt(CertType type,
261                                                     int index) const {
262   const net::CertificateList& cert_list = GetCertificateListForType(type);
263   DCHECK_GE(index, 0);
264   DCHECK_LT(index, static_cast<int>(cert_list.size()));
265   return cert_list[index].get();
266 }
267
268 const net::CertificateList& CertLibrary::GetCertificateListForType(
269     CertType type) const {
270   if (type == CERT_TYPE_USER)
271     return user_certs_;
272   if (type == CERT_TYPE_SERVER)
273     return server_certs_;
274   if (type == CERT_TYPE_SERVER_CA)
275     return server_ca_certs_;
276   DCHECK(type == CERT_TYPE_DEFAULT);
277   return certs_;
278 }
279
280 }  // namespace chromeos