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 "chrome/grit/generated_resources.h" 20 #include "chromeos/dbus/cryptohome_client.h" 21 #include "chromeos/dbus/dbus_thread_manager.h" 22 #include "chromeos/login/login_state.h" 23 #include "chromeos/network/onc/onc_utils.h" 24 #include "content/public/browser/browser_thread.h" 25 #include "crypto/nss_util.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, int* slot_id) const { 169 net::X509Certificate* cert = GetCertificateAt(CERT_TYPE_USER, index); 170 return CertLoader::GetPkcs11IdAndSlotForCert(*cert, slot_id); 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 int slot_id = -1; 196 std::string id = CertLoader::GetPkcs11IdAndSlotForCert(*cert, &slot_id); 197 if (id == pkcs11_id) 198 return index; 199 } 200 return -1; // Not found. 201 } 202 203 void CertLibrary::OnCertificatesLoaded(const net::CertificateList& cert_list, 204 bool initial_load) { 205 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 206 VLOG(1) << "CertLibrary::OnCertificatesLoaded: " << cert_list.size(); 207 certs_.clear(); 208 user_certs_.clear(); 209 server_certs_.clear(); 210 server_ca_certs_.clear(); 211 212 // Add certificates to the appropriate list. 213 for (net::CertificateList::const_iterator iter = cert_list.begin(); 214 iter != cert_list.end(); ++iter) { 215 certs_.push_back(iter->get()); 216 net::X509Certificate::OSCertHandle cert_handle = 217 iter->get()->os_cert_handle(); 218 net::CertType type = x509_certificate_model::GetType(cert_handle); 219 switch (type) { 220 case net::USER_CERT: 221 user_certs_.push_back(iter->get()); 222 break; 223 case net::SERVER_CERT: 224 server_certs_.push_back(iter->get()); 225 break; 226 case net::CA_CERT: { 227 // Exclude root CA certificates that are built into Chrome. 228 std::string token_name = 229 x509_certificate_model::GetTokenName(cert_handle); 230 if (token_name != kRootCertificateTokenName) 231 server_ca_certs_.push_back(iter->get()); 232 break; 233 } 234 default: 235 break; 236 } 237 } 238 239 // Perform locale-sensitive sorting by certificate name. 240 UErrorCode error = U_ZERO_ERROR; 241 scoped_ptr<icu::Collator> collator(icu::Collator::createInstance( 242 icu::Locale(g_browser_process->GetApplicationLocale().c_str()), error)); 243 if (U_FAILURE(error)) 244 collator.reset(); 245 CertNameComparator cert_name_comparator(collator.get()); 246 std::sort(certs_.begin(), certs_.end(), cert_name_comparator); 247 std::sort(user_certs_.begin(), user_certs_.end(), cert_name_comparator); 248 std::sort(server_certs_.begin(), server_certs_.end(), cert_name_comparator); 249 std::sort(server_ca_certs_.begin(), server_ca_certs_.end(), 250 cert_name_comparator); 251 252 VLOG(1) << "certs_: " << certs_.size(); 253 VLOG(1) << "user_certs_: " << user_certs_.size(); 254 VLOG(1) << "server_certs_: " << server_certs_.size(); 255 VLOG(1) << "server_ca_certs_: " << server_ca_certs_.size(); 256 257 FOR_EACH_OBSERVER(CertLibrary::Observer, observer_list_, 258 OnCertificatesLoaded(initial_load)); 259 } 260 261 net::X509Certificate* CertLibrary::GetCertificateAt(CertType type, 262 int index) const { 263 const net::CertificateList& cert_list = GetCertificateListForType(type); 264 DCHECK_GE(index, 0); 265 DCHECK_LT(index, static_cast<int>(cert_list.size())); 266 return cert_list[index].get(); 267 } 268 269 const net::CertificateList& CertLibrary::GetCertificateListForType( 270 CertType type) const { 271 if (type == CERT_TYPE_USER) 272 return user_certs_; 273 if (type == CERT_TYPE_SERVER) 274 return server_certs_; 275 if (type == CERT_TYPE_SERVER_CA) 276 return server_ca_certs_; 277 DCHECK(type == CERT_TYPE_DEFAULT); 278 return certs_; 279 } 280 281 } // namespace chromeos 282