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