• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CRLSetFetcher()26 CRLSetFetcher::CRLSetFetcher() : cus_(NULL) {}
27 
SetCRLSetFilePath(const base::FilePath & path)28 void CRLSetFetcher::SetCRLSetFilePath(const base::FilePath& path) {
29   crl_path_ = path.Append(chrome::kCRLSetFilename);
30 }
31 
GetCRLSetFilePath() const32 base::FilePath CRLSetFetcher::GetCRLSetFilePath() const {
33   return crl_path_;
34 }
35 
StartInitialLoad(ComponentUpdateService * cus,const base::FilePath & path)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 
DeleteFromDisk(const base::FilePath & path)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 
DoInitialLoadFromDisk()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 
LoadFromDisk(base::FilePath path,scoped_refptr<net::CRLSet> * out_crl_set)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 
SetCRLSetIfNewer(scoped_refptr<net::CRLSet> crl_set)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 
RegisterComponent(uint32 sequence_of_loaded_crl)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 
DoDeleteFromDisk()159 void CRLSetFetcher::DoDeleteFromDisk() {
160   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
161 
162   DeleteFile(GetCRLSetFilePath(), false /* not recursive */);
163 }
164 
OnUpdateError(int error)165 void CRLSetFetcher::OnUpdateError(int error) {
166   LOG(WARNING) << "CRLSetFetcher got error " << error
167                << " from component installer";
168 }
169 
Install(const base::DictionaryValue & manifest,const base::FilePath & unpack_path)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 
GetInstalledFile(const std::string & file,base::FilePath * installed_file)231 bool CRLSetFetcher::GetInstalledFile(
232     const std::string& file, base::FilePath* installed_file) {
233   return false;
234 }
235 
~CRLSetFetcher()236 CRLSetFetcher::~CRLSetFetcher() {}
237