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.
5 #include "chrome/browser/chromeos/options/cert_library.h"
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"
36 // Root CA certificates that are built into Chrome use this token name.
37 const char kRootCertificateTokenName
[] = "Builtin Object Token";
39 base::string16
GetDisplayString(net::X509Certificate
* cert
,
40 bool hardware_backed
) {
42 if (!cert
->subject().organization_names
.empty())
43 org
= cert
->subject().organization_names
[0];
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()));
52 if (hardware_backed
) {
53 return l10n_util::GetStringFUTF16(
54 IDS_CERT_MANAGER_HARDWARE_BACKED_KEY_FORMAT_LONG
,
57 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED
));
59 return l10n_util::GetStringFUTF16(
60 IDS_CERT_MANAGER_KEY_FORMAT_LONG
,
66 std::string
CertToPEM(const net::X509Certificate
& cert
) {
67 std::string pem_encoded_cert
;
68 if (!net::X509Certificate::GetPEMEncoded(cert
.os_cert_handle(),
70 LOG(ERROR
) << "Couldn't PEM-encode certificate";
73 return pem_encoded_cert
;
78 class CertNameComparator
{
80 explicit CertNameComparator(icu::Collator
* collator
)
81 : collator_(collator
) {
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
;
95 icu::Collator
* collator_
;
98 static CertLibrary
* g_cert_library
= NULL
;
101 void CertLibrary::Initialize() {
102 CHECK(!g_cert_library
);
103 g_cert_library
= new CertLibrary();
107 void CertLibrary::Shutdown() {
108 CHECK(g_cert_library
);
109 delete g_cert_library
;
110 g_cert_library
= NULL
;
114 CertLibrary
* CertLibrary::Get() {
115 CHECK(g_cert_library
) << "CertLibrary::Get() called before Initialize()";
116 return g_cert_library
;
120 bool CertLibrary::IsInitialized() {
121 return g_cert_library
;
124 CertLibrary::CertLibrary() {
125 CertLoader::Get()->AddObserver(this);
128 CertLibrary::~CertLibrary() {
129 CertLoader::Get()->RemoveObserver(this);
132 void CertLibrary::AddObserver(CertLibrary::Observer
* observer
) {
133 observer_list_
.AddObserver(observer
);
136 void CertLibrary::RemoveObserver(CertLibrary::Observer
* observer
) {
137 observer_list_
.RemoveObserver(observer
);
140 bool CertLibrary::CertificatesLoading() const {
141 return CertLoader::Get()->CertificatesLoading();
144 bool CertLibrary::CertificatesLoaded() const {
145 return CertLoader::Get()->certificates_loaded();
148 bool CertLibrary::IsHardwareBacked() const {
149 return CertLoader::Get()->IsHardwareBacked();
152 std::string
CertLibrary::GetTPMSlotID() const {
153 return base::IntToString(CertLoader::Get()->TPMTokenSlotID());
156 int CertLibrary::NumCertificates(CertType type
) const {
157 const net::CertificateList
& cert_list
= GetCertificateListForType(type
);
158 return static_cast<int>(cert_list
.size());
161 base::string16
CertLibrary::GetCertDisplayStringAt(CertType type
,
163 net::X509Certificate
* cert
= GetCertificateAt(type
, index
);
164 bool hardware_backed
= IsCertHardwareBackedAt(type
, index
);
165 return GetDisplayString(cert
, hardware_backed
);
168 std::string
CertLibrary::GetServerCACertPEMAt(int index
) const {
169 return CertToPEM(*GetCertificateAt(CERT_TYPE_SERVER_CA
, index
));
172 std::string
CertLibrary::GetUserCertPkcs11IdAt(int index
) const {
173 net::X509Certificate
* cert
= GetCertificateAt(CERT_TYPE_USER
, index
);
174 return CertLoader::GetPkcs11IdForCert(*cert
);
177 bool CertLibrary::IsCertHardwareBackedAt(CertType type
, int index
) const {
178 net::X509Certificate
* cert
= GetCertificateAt(type
, index
);
179 return CertLoader::Get()->IsCertificateHardwareBacked(cert
);
182 int CertLibrary::GetServerCACertIndexByPEM(
183 const std::string
& pem_encoded
) const {
184 int num_certs
= NumCertificates(CERT_TYPE_SERVER_CA
);
185 for (int index
= 0; index
< num_certs
; ++index
) {
186 net::X509Certificate
* cert
= GetCertificateAt(CERT_TYPE_SERVER_CA
, index
);
187 if (CertToPEM(*cert
) != pem_encoded
)
194 int CertLibrary::GetUserCertIndexByPkcs11Id(
195 const std::string
& pkcs11_id
) const {
196 int num_certs
= NumCertificates(CERT_TYPE_USER
);
197 for (int index
= 0; index
< num_certs
; ++index
) {
198 net::X509Certificate
* cert
= GetCertificateAt(CERT_TYPE_USER
, index
);
199 std::string id
= CertLoader::GetPkcs11IdForCert(*cert
);
203 return -1; // Not found.
206 void CertLibrary::OnCertificatesLoaded(const net::CertificateList
& cert_list
,
208 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
209 VLOG(1) << "CertLibrary::OnCertificatesLoaded: " << cert_list
.size();
212 server_certs_
.clear();
213 server_ca_certs_
.clear();
215 // Add certificates to the appropriate list.
216 for (net::CertificateList::const_iterator iter
= cert_list
.begin();
217 iter
!= cert_list
.end(); ++iter
) {
218 certs_
.push_back(iter
->get());
219 net::X509Certificate::OSCertHandle cert_handle
=
220 iter
->get()->os_cert_handle();
221 net::CertType type
= x509_certificate_model::GetType(cert_handle
);
224 user_certs_
.push_back(iter
->get());
226 case net::SERVER_CERT
:
227 server_certs_
.push_back(iter
->get());
230 // Exclude root CA certificates that are built into Chrome.
231 std::string token_name
=
232 x509_certificate_model::GetTokenName(cert_handle
);
233 if (token_name
!= kRootCertificateTokenName
)
234 server_ca_certs_
.push_back(iter
->get());
242 // Perform locale-sensitive sorting by certificate name.
243 UErrorCode error
= U_ZERO_ERROR
;
244 scoped_ptr
<icu::Collator
> collator(icu::Collator::createInstance(
245 icu::Locale(g_browser_process
->GetApplicationLocale().c_str()), error
));
246 if (U_FAILURE(error
))
248 CertNameComparator
cert_name_comparator(collator
.get());
249 std::sort(certs_
.begin(), certs_
.end(), cert_name_comparator
);
250 std::sort(user_certs_
.begin(), user_certs_
.end(), cert_name_comparator
);
251 std::sort(server_certs_
.begin(), server_certs_
.end(), cert_name_comparator
);
252 std::sort(server_ca_certs_
.begin(), server_ca_certs_
.end(),
253 cert_name_comparator
);
255 VLOG(1) << "certs_: " << certs_
.size();
256 VLOG(1) << "user_certs_: " << user_certs_
.size();
257 VLOG(1) << "server_certs_: " << server_certs_
.size();
258 VLOG(1) << "server_ca_certs_: " << server_ca_certs_
.size();
260 FOR_EACH_OBSERVER(CertLibrary::Observer
, observer_list_
,
261 OnCertificatesLoaded(initial_load
));
264 net::X509Certificate
* CertLibrary::GetCertificateAt(CertType type
,
266 const net::CertificateList
& cert_list
= GetCertificateListForType(type
);
268 DCHECK_LT(index
, static_cast<int>(cert_list
.size()));
269 return cert_list
[index
].get();
272 const net::CertificateList
& CertLibrary::GetCertificateListForType(
273 CertType type
) const {
274 if (type
== CERT_TYPE_USER
)
276 if (type
== CERT_TYPE_SERVER
)
277 return server_certs_
;
278 if (type
== CERT_TYPE_SERVER_CA
)
279 return server_ca_certs_
;
280 DCHECK(type
== CERT_TYPE_DEFAULT
);
284 } // namespace chromeos