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