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/files/file_util.h"
     10 #include "base/numerics/safe_conversions.h"
     11 #include "base/rand_util.h"
     12 #include "base/strings/string_number_conversions.h"
     13 #include "base/time/time.h"
     14 #include "chrome/browser/profiles/profile.h"
     15 #include "chrome/common/chrome_constants.h"
     16 #include "chrome/common/chrome_paths.h"
     17 #include "components/component_updater/component_updater_service.h"
     18 #include "content/public/browser/browser_thread.h"
     19 #include "net/cert/crl_set.h"
     20 #include "net/cert/crl_set_storage.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 void CRLSetFetcher::SetCRLSetFilePath(const base::FilePath& path) {
     29   crl_path_ = path.Append(chrome::kCRLSetFilename);
     30 }
     31 
     32 base::FilePath CRLSetFetcher::GetCRLSetFilePath() const {
     33   return crl_path_;
     34 }
     35 
     36 void CRLSetFetcher::StartInitialLoad(ComponentUpdateService* cus,
     37                                      const base::FilePath& path) {
     38   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     39   if (path.empty())
     40     return;
     41   SetCRLSetFilePath(path);
     42   cus_ = cus;
     43 
     44   if (!BrowserThread::PostTask(
     45           BrowserThread::FILE, FROM_HERE,
     46           base::Bind(&CRLSetFetcher::DoInitialLoadFromDisk, this))) {
     47     NOTREACHED();
     48   }
     49 }
     50 
     51 void CRLSetFetcher::DeleteFromDisk(const base::FilePath& path) {
     52   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     53 
     54   if (path.empty())
     55     return;
     56   SetCRLSetFilePath(path);
     57   if (!BrowserThread::PostTask(
     58           BrowserThread::FILE, FROM_HERE,
     59           base::Bind(&CRLSetFetcher::DoDeleteFromDisk, this))) {
     60     NOTREACHED();
     61   }
     62 }
     63 
     64 void CRLSetFetcher::DoInitialLoadFromDisk() {
     65   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     66 
     67   LoadFromDisk(GetCRLSetFilePath(), &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::CRLSetStorage::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   DeleteFile(GetCRLSetFilePath(), false /* not recursive */);
    163 }
    164 
    165 void CRLSetFetcher::OnUpdateError(int error) {
    166   LOG(WARNING) << "CRLSetFetcher got error " << error
    167                << " from component installer";
    168 }
    169 
    170 bool CRLSetFetcher::Install(const base::DictionaryValue& manifest,
    171                             const base::FilePath& unpack_path) {
    172   base::FilePath crl_set_file_path =
    173       unpack_path.Append(FILE_PATH_LITERAL("crl-set"));
    174   base::FilePath save_to = GetCRLSetFilePath();
    175 
    176   std::string crl_set_bytes;
    177   if (!base::ReadFileToString(crl_set_file_path, &crl_set_bytes)) {
    178     LOG(WARNING) << "Failed to find crl-set file inside CRX";
    179     return false;
    180   }
    181 
    182   bool is_delta;
    183   if (!net::CRLSetStorage::GetIsDeltaUpdate(crl_set_bytes, &is_delta)) {
    184     LOG(WARNING) << "GetIsDeltaUpdate failed on CRL set from update CRX";
    185     return false;
    186   }
    187 
    188   if (!is_delta) {
    189     if (!net::CRLSetStorage::Parse(crl_set_bytes, &crl_set_)) {
    190       LOG(WARNING) << "Failed to parse CRL set from update CRX";
    191       return false;
    192     }
    193     int size = base::checked_cast<int>(crl_set_bytes.size());
    194     if (base::WriteFile(save_to, crl_set_bytes.data(), size) != size) {
    195       LOG(WARNING) << "Failed to save new CRL set to disk";
    196       // We don't return false here because we can still use this CRL set. When
    197       // we restart we might revert to an older version, then we'll
    198       // advertise the older version to Omaha and everything will still work.
    199     }
    200   } else {
    201     scoped_refptr<net::CRLSet> new_crl_set;
    202     if (!net::CRLSetStorage::ApplyDelta(
    203             crl_set_.get(), crl_set_bytes, &new_crl_set)) {
    204       LOG(WARNING) << "Failed to parse delta CRL set";
    205       return false;
    206     }
    207     VLOG(1) << "Applied CRL set delta #" << crl_set_->sequence()
    208             << "->#" << new_crl_set->sequence();
    209     const std::string new_crl_set_bytes =
    210         net::CRLSetStorage::Serialize(new_crl_set.get());
    211     int size = base::checked_cast<int>(new_crl_set_bytes.size());
    212     if (base::WriteFile(save_to, new_crl_set_bytes.data(), size) != size) {
    213       LOG(WARNING) << "Failed to save new CRL set to disk";
    214       // We don't return false here because we can still use this CRL set. When
    215       // we restart we might revert to an older version, then we'll
    216       // advertise the older version to Omaha and everything will still work.
    217     }
    218     crl_set_ = new_crl_set;
    219   }
    220 
    221   if (!BrowserThread::PostTask(
    222           BrowserThread::IO, FROM_HERE,
    223           base::Bind(
    224               &CRLSetFetcher::SetCRLSetIfNewer, this, crl_set_))) {
    225     NOTREACHED();
    226   }
    227 
    228   return true;
    229 }
    230 
    231 bool CRLSetFetcher::GetInstalledFile(
    232     const std::string& file, base::FilePath* installed_file) {
    233   return false;
    234 }
    235 
    236 CRLSetFetcher::~CRLSetFetcher() {}
    237