Home | History | Annotate | Download | only in browser
      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/certificate_manager_model.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/i18n/time_formatting.h"
      9 #include "base/logging.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "chrome/browser/net/nss_context.h"
     12 #include "chrome/browser/ui/crypto_module_password_dialog_nss.h"
     13 #include "chrome/common/net/x509_certificate_model.h"
     14 #include "chrome/grit/generated_resources.h"
     15 #include "content/public/browser/browser_context.h"
     16 #include "content/public/browser/browser_thread.h"
     17 #include "content/public/browser/resource_context.h"
     18 #include "crypto/nss_util.h"
     19 #include "net/base/crypto_module.h"
     20 #include "net/base/net_errors.h"
     21 #include "net/cert/x509_certificate.h"
     22 #include "ui/base/l10n/l10n_util.h"
     23 
     24 using content::BrowserThread;
     25 
     26 // CertificateManagerModel is created on the UI thread. It needs a
     27 // NSSCertDatabase handle (and on ChromeOS it needs to get the TPM status) which
     28 // needs to be done on the IO thread.
     29 //
     30 // The initialization flow is roughly:
     31 //
     32 //               UI thread                              IO Thread
     33 //
     34 //   CertificateManagerModel::Create
     35 //                  \--------------------------------------v
     36 //                                CertificateManagerModel::GetCertDBOnIOThread
     37 //                                                         |
     38 //                                     GetNSSCertDatabaseForResourceContext
     39 //                                                         |
     40 //                               CertificateManagerModel::DidGetCertDBOnIOThread
     41 //                                                         |
     42 //                                       crypto::IsTPMTokenEnabledForNSS
     43 //                  v--------------------------------------/
     44 // CertificateManagerModel::DidGetCertDBOnUIThread
     45 //                  |
     46 //     new CertificateManagerModel
     47 //                  |
     48 //               callback
     49 
     50 // static
     51 void CertificateManagerModel::Create(
     52     content::BrowserContext* browser_context,
     53     CertificateManagerModel::Observer* observer,
     54     const CreationCallback& callback) {
     55   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     56   BrowserThread::PostTask(
     57       BrowserThread::IO,
     58       FROM_HERE,
     59       base::Bind(&CertificateManagerModel::GetCertDBOnIOThread,
     60                  browser_context->GetResourceContext(),
     61                  observer,
     62                  callback));
     63 }
     64 
     65 CertificateManagerModel::CertificateManagerModel(
     66     net::NSSCertDatabase* nss_cert_database,
     67     bool is_user_db_available,
     68     bool is_tpm_available,
     69     Observer* observer)
     70     : cert_db_(nss_cert_database),
     71       is_user_db_available_(is_user_db_available),
     72       is_tpm_available_(is_tpm_available),
     73       observer_(observer) {
     74   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     75 }
     76 
     77 CertificateManagerModel::~CertificateManagerModel() {
     78 }
     79 
     80 void CertificateManagerModel::Refresh() {
     81   DVLOG(1) << "refresh started";
     82   net::CryptoModuleList modules;
     83   cert_db_->ListModules(&modules, false);
     84   DVLOG(1) << "refresh waiting for unlocking...";
     85   chrome::UnlockSlotsIfNecessary(
     86       modules,
     87       chrome::kCryptoModulePasswordListCerts,
     88       net::HostPortPair(),  // unused.
     89       NULL, // TODO(mattm): supply parent window.
     90       base::Bind(&CertificateManagerModel::RefreshSlotsUnlocked,
     91                  base::Unretained(this)));
     92 }
     93 
     94 void CertificateManagerModel::RefreshSlotsUnlocked() {
     95   DVLOG(1) << "refresh listing certs...";
     96   // TODO(tbarzic): Use async |ListCerts|.
     97   cert_db_->ListCertsSync(&cert_list_);
     98   observer_->CertificatesRefreshed();
     99   DVLOG(1) << "refresh finished";
    100 }
    101 
    102 void CertificateManagerModel::FilterAndBuildOrgGroupingMap(
    103     net::CertType filter_type,
    104     CertificateManagerModel::OrgGroupingMap* map) const {
    105   for (net::CertificateList::const_iterator i = cert_list_.begin();
    106        i != cert_list_.end(); ++i) {
    107     net::X509Certificate* cert = i->get();
    108     net::CertType type =
    109         x509_certificate_model::GetType(cert->os_cert_handle());
    110     if (type != filter_type)
    111       continue;
    112 
    113     std::string org;
    114     if (!cert->subject().organization_names.empty())
    115       org = cert->subject().organization_names[0];
    116     if (org.empty())
    117       org = cert->subject().GetDisplayName();
    118 
    119     (*map)[org].push_back(cert);
    120   }
    121 }
    122 
    123 base::string16 CertificateManagerModel::GetColumnText(
    124     const net::X509Certificate& cert,
    125     Column column) const {
    126   base::string16 rv;
    127   switch (column) {
    128     case COL_SUBJECT_NAME:
    129       rv = base::UTF8ToUTF16(
    130           x509_certificate_model::GetCertNameOrNickname(cert.os_cert_handle()));
    131 
    132       // TODO(xiyuan): Put this into a column when we have js tree-table.
    133       if (IsHardwareBacked(&cert)) {
    134         rv = l10n_util::GetStringFUTF16(
    135             IDS_CERT_MANAGER_HARDWARE_BACKED_KEY_FORMAT,
    136             rv,
    137             l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED));
    138       }
    139       break;
    140     case COL_CERTIFICATE_STORE:
    141       rv = base::UTF8ToUTF16(
    142           x509_certificate_model::GetTokenName(cert.os_cert_handle()));
    143       break;
    144     case COL_SERIAL_NUMBER:
    145       rv = base::ASCIIToUTF16(x509_certificate_model::GetSerialNumberHexified(
    146           cert.os_cert_handle(), std::string()));
    147       break;
    148     case COL_EXPIRES_ON:
    149       if (!cert.valid_expiry().is_null())
    150         rv = base::TimeFormatShortDateNumeric(cert.valid_expiry());
    151       break;
    152     default:
    153       NOTREACHED();
    154   }
    155   return rv;
    156 }
    157 
    158 int CertificateManagerModel::ImportFromPKCS12(net::CryptoModule* module,
    159                                               const std::string& data,
    160                                               const base::string16& password,
    161                                               bool is_extractable) {
    162   int result = cert_db_->ImportFromPKCS12(module, data, password,
    163                                           is_extractable, NULL);
    164   if (result == net::OK)
    165     Refresh();
    166   return result;
    167 }
    168 
    169 bool CertificateManagerModel::ImportCACerts(
    170     const net::CertificateList& certificates,
    171     net::NSSCertDatabase::TrustBits trust_bits,
    172     net::NSSCertDatabase::ImportCertFailureList* not_imported) {
    173   bool result = cert_db_->ImportCACerts(certificates, trust_bits, not_imported);
    174   if (result && not_imported->size() != certificates.size())
    175     Refresh();
    176   return result;
    177 }
    178 
    179 bool CertificateManagerModel::ImportServerCert(
    180     const net::CertificateList& certificates,
    181     net::NSSCertDatabase::TrustBits trust_bits,
    182     net::NSSCertDatabase::ImportCertFailureList* not_imported) {
    183   bool result = cert_db_->ImportServerCert(certificates, trust_bits,
    184                                            not_imported);
    185   if (result && not_imported->size() != certificates.size())
    186     Refresh();
    187   return result;
    188 }
    189 
    190 bool CertificateManagerModel::SetCertTrust(
    191     const net::X509Certificate* cert,
    192     net::CertType type,
    193     net::NSSCertDatabase::TrustBits trust_bits) {
    194   return cert_db_->SetCertTrust(cert, type, trust_bits);
    195 }
    196 
    197 bool CertificateManagerModel::Delete(net::X509Certificate* cert) {
    198   bool result = cert_db_->DeleteCertAndKey(cert);
    199   if (result)
    200     Refresh();
    201   return result;
    202 }
    203 
    204 bool CertificateManagerModel::IsHardwareBacked(
    205     const net::X509Certificate* cert) const {
    206   return cert_db_->IsHardwareBacked(cert);
    207 }
    208 
    209 // static
    210 void CertificateManagerModel::DidGetCertDBOnUIThread(
    211     net::NSSCertDatabase* cert_db,
    212     bool is_user_db_available,
    213     bool is_tpm_available,
    214     CertificateManagerModel::Observer* observer,
    215     const CreationCallback& callback) {
    216   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    217 
    218   scoped_ptr<CertificateManagerModel> model(new CertificateManagerModel(
    219       cert_db, is_user_db_available, is_tpm_available, observer));
    220   callback.Run(model.Pass());
    221 }
    222 
    223 // static
    224 void CertificateManagerModel::DidGetCertDBOnIOThread(
    225     CertificateManagerModel::Observer* observer,
    226     const CreationCallback& callback,
    227     net::NSSCertDatabase* cert_db) {
    228   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    229 
    230   bool is_user_db_available = cert_db->GetPublicSlot();
    231   bool is_tpm_available = false;
    232 #if defined(OS_CHROMEOS)
    233   is_tpm_available = crypto::IsTPMTokenEnabledForNSS();
    234 #endif
    235   BrowserThread::PostTask(
    236       BrowserThread::UI,
    237       FROM_HERE,
    238       base::Bind(&CertificateManagerModel::DidGetCertDBOnUIThread,
    239                  cert_db,
    240                  is_user_db_available,
    241                  is_tpm_available,
    242                  observer,
    243                  callback));
    244 }
    245 
    246 // static
    247 void CertificateManagerModel::GetCertDBOnIOThread(
    248     content::ResourceContext* context,
    249     CertificateManagerModel::Observer* observer,
    250     const CreationCallback& callback) {
    251   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    252   net::NSSCertDatabase* cert_db = GetNSSCertDatabaseForResourceContext(
    253       context,
    254       base::Bind(&CertificateManagerModel::DidGetCertDBOnIOThread,
    255                  observer,
    256                  callback));
    257   if (cert_db)
    258     DidGetCertDBOnIOThread(observer, callback, cert_db);
    259 }
    260