Home | History | Annotate | Download | only in cros
      1 // Copyright (c) 2012 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/cros/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 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   string16 issued_by = UTF8ToUTF16(
     46       x509_certificate_model::GetIssuerCommonName(cert->os_cert_handle(),
     47                                                   org));  // alternative text
     48   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     string16 lhs_name = GetDisplayString(lhs.get(), false);
     86     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 string16 CertLibrary::GetCertDisplayStringAt(CertType type, int index) const {
    157   net::X509Certificate* cert = GetCertificateAt(type, index);
    158   bool hardware_backed = IsCertHardwareBackedAt(type, index);
    159   return GetDisplayString(cert, hardware_backed);
    160 }
    161 
    162 std::string CertLibrary::GetCertPEMAt(CertType type, int index) const {
    163   return CertToPEM(*GetCertificateAt(type, index));
    164 }
    165 
    166 std::string CertLibrary::GetCertPkcs11IdAt(CertType type, int index) const {
    167   net::X509Certificate* cert = GetCertificateAt(type, index);
    168   return x509_certificate_model::GetPkcs11Id(cert->os_cert_handle());
    169 }
    170 
    171 bool CertLibrary::IsCertHardwareBackedAt(CertType type, int index) const {
    172   if (!CertLoader::Get()->IsHardwareBacked())
    173     return false;
    174   net::X509Certificate* cert = GetCertificateAt(type, index);
    175   std::string cert_token_name =
    176       x509_certificate_model::GetTokenName(cert->os_cert_handle());
    177   return cert_token_name ==
    178       CertLoader::Get()->tpm_token_name();
    179 }
    180 
    181 int CertLibrary::GetCertIndexByPEM(CertType type,
    182                                    const std::string& pem_encoded) const {
    183   int num_certs = NumCertificates(type);
    184   for (int index = 0; index < num_certs; ++index) {
    185     net::X509Certificate* cert = GetCertificateAt(type, index);
    186     if (CertToPEM(*cert) != pem_encoded)
    187       continue;
    188     return index;
    189   }
    190   return -1;
    191 }
    192 
    193 int CertLibrary::GetCertIndexByPkcs11Id(CertType type,
    194                                         const std::string& pkcs11_id) const {
    195   int num_certs = NumCertificates(type);
    196   for (int index = 0; index < num_certs; ++index) {
    197     net::X509Certificate* cert = GetCertificateAt(type, index);
    198     net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle();
    199     std::string id = x509_certificate_model::GetPkcs11Id(cert_handle);
    200     if (id == pkcs11_id)
    201       return index;
    202   }
    203   return -1;  // Not found.
    204 }
    205 
    206 void CertLibrary::OnCertificatesLoaded(const net::CertificateList& cert_list,
    207                                        bool initial_load) {
    208   CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    209   VLOG(1) << "CertLibrary::OnCertificatesLoaded: " << cert_list.size();
    210   certs_.clear();
    211   user_certs_.clear();
    212   server_certs_.clear();
    213   server_ca_certs_.clear();
    214 
    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);
    222     switch (type) {
    223       case net::USER_CERT:
    224         user_certs_.push_back(iter->get());
    225         break;
    226       case net::SERVER_CERT:
    227         server_certs_.push_back(iter->get());
    228         break;
    229       case net::CA_CERT: {
    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());
    235         break;
    236       }
    237       default:
    238         break;
    239     }
    240   }
    241 
    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))
    247     collator.reset();
    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);
    254 
    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();
    259 
    260   FOR_EACH_OBSERVER(CertLibrary::Observer, observer_list_,
    261                     OnCertificatesLoaded(initial_load));
    262 }
    263 
    264 net::X509Certificate* CertLibrary::GetCertificateAt(CertType type,
    265                                                     int index) const {
    266   const net::CertificateList& cert_list = GetCertificateListForType(type);
    267   DCHECK_GE(index, 0);
    268   DCHECK_LT(index, static_cast<int>(cert_list.size()));
    269   return cert_list[index].get();
    270 }
    271 
    272 const net::CertificateList& CertLibrary::GetCertificateListForType(
    273     CertType type) const {
    274   if (type == CERT_TYPE_USER)
    275     return user_certs_;
    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);
    281   return certs_;
    282 }
    283 
    284 }  // namespace chromeos
    285