Home | History | Annotate | Download | only in net
      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/net/crl_set_fetcher.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/debug/trace_event.h"
      9 #include "base/file_util.h"
     10 #include "base/numerics/safe_conversions.h"
     11 #include "base/path_service.h"
     12 #include "base/rand_util.h"
     13 #include "base/strings/string_number_conversions.h"
     14 #include "base/time/time.h"
     15 #include "chrome/browser/component_updater/component_updater_service.h"
     16 #include "chrome/browser/profiles/profile.h"
     17 #include "chrome/common/chrome_constants.h"
     18 #include "chrome/common/chrome_paths.h"
     19 #include "content/public/browser/browser_thread.h"
     20 #include "net/cert/crl_set.h"
     21 #include "net/ssl/ssl_config_service.h"
     22 
     23 using component_updater::ComponentUpdateService;
     24 using content::BrowserThread;
     25 
     26 CRLSetFetcher::CRLSetFetcher() : cus_(NULL) {}
     27 
     28 bool CRLSetFetcher::GetCRLSetFilePath(base::FilePath* path) const {
     29   bool ok = PathService::Get(chrome::DIR_USER_DATA, path);
     30   if (!ok) {
     31     NOTREACHED();
     32     return false;
     33   }
     34   *path = path->Append(chrome::kCRLSetFilename);
     35   return true;
     36 }
     37 
     38 void CRLSetFetcher::StartInitialLoad(ComponentUpdateService* cus) {
     39   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     40 
     41   cus_ = cus;
     42 
     43   if (!BrowserThread::PostTask(
     44           BrowserThread::FILE, FROM_HERE,
     45           base::Bind(&CRLSetFetcher::DoInitialLoadFromDisk, this))) {
     46     NOTREACHED();
     47   }
     48 }
     49 
     50 void CRLSetFetcher::DeleteFromDisk() {
     51   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     52 
     53   if (!BrowserThread::PostTask(
     54           BrowserThread::FILE, FROM_HERE,
     55           base::Bind(&CRLSetFetcher::DoDeleteFromDisk, this))) {
     56     NOTREACHED();
     57   }
     58 }
     59 
     60 void CRLSetFetcher::DoInitialLoadFromDisk() {
     61   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     62 
     63   base::FilePath crl_set_file_path;
     64   if (!GetCRLSetFilePath(&crl_set_file_path))
     65     return;
     66 
     67   LoadFromDisk(crl_set_file_path, &crl_set_);
     68 
     69   uint32 sequence_of_loaded_crl = 0;
     70   if (crl_set_.get())
     71     sequence_of_loaded_crl = crl_set_->sequence();
     72 
     73   // Get updates, advertising the sequence number of the CRL set that we just
     74   // loaded, if any.
     75   if (!BrowserThread::PostTask(
     76           BrowserThread::UI, FROM_HERE,
     77           base::Bind(
     78               &CRLSetFetcher::RegisterComponent,
     79               this,
     80               sequence_of_loaded_crl))) {
     81     NOTREACHED();
     82   }
     83 }
     84 
     85 void CRLSetFetcher::LoadFromDisk(base::FilePath path,
     86                                  scoped_refptr<net::CRLSet>* out_crl_set) {
     87   TRACE_EVENT0("CRLSetFetcher", "LoadFromDisk");
     88 
     89   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     90 
     91   std::string crl_set_bytes;
     92   {
     93     TRACE_EVENT0("CRLSetFetcher", "ReadFileToString");
     94     if (!base::ReadFileToString(path, &crl_set_bytes))
     95       return;
     96   }
     97 
     98   if (!net::CRLSet::Parse(crl_set_bytes, out_crl_set)) {
     99     LOG(WARNING) << "Failed to parse CRL set from " << path.MaybeAsASCII();
    100     return;
    101   }
    102 
    103   VLOG(1) << "Loaded " << crl_set_bytes.size() << " bytes of CRL set from disk";
    104 
    105   if (!BrowserThread::PostTask(
    106           BrowserThread::IO, FROM_HERE,
    107           base::Bind(
    108               &CRLSetFetcher::SetCRLSetIfNewer, this, *out_crl_set))) {
    109     NOTREACHED();
    110   }
    111 }
    112 
    113 void CRLSetFetcher::SetCRLSetIfNewer(
    114     scoped_refptr<net::CRLSet> crl_set) {
    115   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    116 
    117   scoped_refptr<net::CRLSet> old_crl_set(net::SSLConfigService::GetCRLSet());
    118   if (old_crl_set.get() && old_crl_set->sequence() > crl_set->sequence()) {
    119     LOG(WARNING) << "Refusing to downgrade CRL set from #"
    120                  << old_crl_set->sequence()
    121                  << "to #"
    122                  << crl_set->sequence();
    123   } else {
    124     net::SSLConfigService::SetCRLSet(crl_set);
    125     VLOG(1) << "Installed CRL set #" << crl_set->sequence();
    126   }
    127 }
    128 
    129 // kPublicKeySHA256 is the SHA256 hash of the SubjectPublicKeyInfo of the key
    130 // that's used to sign generated CRL sets.
    131 static const uint8 kPublicKeySHA256[32] = {
    132   0x75, 0xda, 0xf8, 0xcb, 0x77, 0x68, 0x40, 0x33,
    133   0x65, 0x4c, 0x97, 0xe5, 0xc5, 0x1b, 0xcd, 0x81,
    134   0x7b, 0x1e, 0xeb, 0x11, 0x2c, 0xe1, 0xa4, 0x33,
    135   0x8c, 0xf5, 0x72, 0x5e, 0xed, 0xb8, 0x43, 0x97,
    136 };
    137 
    138 void CRLSetFetcher::RegisterComponent(uint32 sequence_of_loaded_crl) {
    139   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    140 
    141   component_updater::CrxComponent component;
    142   component.pk_hash.assign(kPublicKeySHA256,
    143                            kPublicKeySHA256 + sizeof(kPublicKeySHA256));
    144   component.installer = this;
    145   component.name = "CRLSet";
    146   component.version = Version(base::UintToString(sequence_of_loaded_crl));
    147   component.allow_background_download = false;
    148   if (!component.version.IsValid()) {
    149     NOTREACHED();
    150     component.version = Version("0");
    151   }
    152 
    153   if (cus_->RegisterComponent(component) !=
    154       ComponentUpdateService::kOk) {
    155     NOTREACHED() << "RegisterComponent returned error";
    156   }
    157 }
    158 
    159 void CRLSetFetcher::DoDeleteFromDisk() {
    160   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    161 
    162   base::FilePath crl_set_file_path;
    163   if (!GetCRLSetFilePath(&crl_set_file_path))
    164     return;
    165 
    166   DeleteFile(crl_set_file_path, false /* not recursive */);
    167 }
    168 
    169 void CRLSetFetcher::OnUpdateError(int error) {
    170   LOG(WARNING) << "CRLSetFetcher got error " << error
    171                << " from component installer";
    172 }
    173 
    174 bool CRLSetFetcher::Install(const base::DictionaryValue& manifest,
    175                             const base::FilePath& unpack_path) {
    176   base::FilePath crl_set_file_path =
    177       unpack_path.Append(FILE_PATH_LITERAL("crl-set"));
    178   base::FilePath save_to;
    179   if (!GetCRLSetFilePath(&save_to))
    180     return true;
    181 
    182   std::string crl_set_bytes;
    183   if (!base::ReadFileToString(crl_set_file_path, &crl_set_bytes)) {
    184     LOG(WARNING) << "Failed to find crl-set file inside CRX";
    185     return false;
    186   }
    187 
    188   bool is_delta;
    189   if (!net::CRLSet::GetIsDeltaUpdate(crl_set_bytes, &is_delta)) {
    190     LOG(WARNING) << "GetIsDeltaUpdate failed on CRL set from update CRX";
    191     return false;
    192   }
    193 
    194   if (!is_delta) {
    195     if (!net::CRLSet::Parse(crl_set_bytes, &crl_set_)) {
    196       LOG(WARNING) << "Failed to parse CRL set from update CRX";
    197       return false;
    198     }
    199     int size = base::checked_cast<int>(crl_set_bytes.size());
    200     if (base::WriteFile(save_to, crl_set_bytes.data(), size) != size) {
    201       LOG(WARNING) << "Failed to save new CRL set to disk";
    202       // We don't return false here because we can still use this CRL set. When
    203       // we restart we might revert to an older version, then we'll
    204       // advertise the older version to Omaha and everything will still work.
    205     }
    206   } else {
    207     scoped_refptr<net::CRLSet> new_crl_set;
    208     if (!crl_set_->ApplyDelta(crl_set_bytes, &new_crl_set)) {
    209       LOG(WARNING) << "Failed to parse delta CRL set";
    210       return false;
    211     }
    212     VLOG(1) << "Applied CRL set delta #" << crl_set_->sequence()
    213             << "->#" << new_crl_set->sequence();
    214     const std::string new_crl_set_bytes = new_crl_set->Serialize();
    215     int size = base::checked_cast<int>(new_crl_set_bytes.size());
    216     if (base::WriteFile(save_to, new_crl_set_bytes.data(), size) != size) {
    217       LOG(WARNING) << "Failed to save new CRL set to disk";
    218       // We don't return false here because we can still use this CRL set. When
    219       // we restart we might revert to an older version, then we'll
    220       // advertise the older version to Omaha and everything will still work.
    221     }
    222     crl_set_ = new_crl_set;
    223   }
    224 
    225   if (!BrowserThread::PostTask(
    226           BrowserThread::IO, FROM_HERE,
    227           base::Bind(
    228               &CRLSetFetcher::SetCRLSetIfNewer, this, crl_set_))) {
    229     NOTREACHED();
    230   }
    231 
    232   return true;
    233 }
    234 
    235 bool CRLSetFetcher::GetInstalledFile(
    236     const std::string& file, base::FilePath* installed_file) {
    237   return false;
    238 }
    239 
    240 CRLSetFetcher::~CRLSetFetcher() {}
    241