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.
5 #include "chrome/browser/net/crl_set_fetcher.h"
8 #include "base/files/file_util.h"
9 #include "base/numerics/safe_conversions.h"
10 #include "base/rand_util.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/time/time.h"
13 #include "base/trace_event/trace_event.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 "components/update_client/update_client.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "net/cert/crl_set.h"
21 #include "net/cert/crl_set_storage.h"
22 #include "net/ssl/ssl_config_service.h"
24 using component_updater::ComponentUpdateService
;
25 using content::BrowserThread
;
27 CRLSetFetcher::CRLSetFetcher() : cus_(NULL
) {}
29 void CRLSetFetcher::SetCRLSetFilePath(const base::FilePath
& path
) {
30 crl_path_
= path
.Append(chrome::kCRLSetFilename
);
33 base::FilePath
CRLSetFetcher::GetCRLSetFilePath() const {
37 void CRLSetFetcher::StartInitialLoad(ComponentUpdateService
* cus
,
38 const base::FilePath
& path
) {
39 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
42 SetCRLSetFilePath(path
);
45 if (!BrowserThread::PostTask(
46 BrowserThread::FILE, FROM_HERE
,
47 base::Bind(&CRLSetFetcher::DoInitialLoadFromDisk
, this))) {
52 void CRLSetFetcher::DeleteFromDisk(const base::FilePath
& path
) {
53 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
57 SetCRLSetFilePath(path
);
58 if (!BrowserThread::PostTask(
59 BrowserThread::FILE, FROM_HERE
,
60 base::Bind(&CRLSetFetcher::DoDeleteFromDisk
, this))) {
65 void CRLSetFetcher::DoInitialLoadFromDisk() {
66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
68 LoadFromDisk(GetCRLSetFilePath(), &crl_set_
);
70 uint32 sequence_of_loaded_crl
= 0;
72 sequence_of_loaded_crl
= crl_set_
->sequence();
74 // Get updates, advertising the sequence number of the CRL set that we just
76 if (!BrowserThread::PostTask(
77 BrowserThread::UI
, FROM_HERE
,
79 &CRLSetFetcher::RegisterComponent
,
81 sequence_of_loaded_crl
))) {
86 void CRLSetFetcher::LoadFromDisk(base::FilePath path
,
87 scoped_refptr
<net::CRLSet
>* out_crl_set
) {
88 TRACE_EVENT0("CRLSetFetcher", "LoadFromDisk");
90 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
92 std::string crl_set_bytes
;
94 TRACE_EVENT0("CRLSetFetcher", "ReadFileToString");
95 if (!base::ReadFileToString(path
, &crl_set_bytes
))
99 if (!net::CRLSetStorage::Parse(crl_set_bytes
, out_crl_set
)) {
100 LOG(WARNING
) << "Failed to parse CRL set from " << path
.MaybeAsASCII();
104 VLOG(1) << "Loaded " << crl_set_bytes
.size() << " bytes of CRL set from disk";
106 if (!BrowserThread::PostTask(
107 BrowserThread::IO
, FROM_HERE
,
109 &CRLSetFetcher::SetCRLSetIfNewer
, this, *out_crl_set
))) {
114 void CRLSetFetcher::SetCRLSetIfNewer(
115 scoped_refptr
<net::CRLSet
> crl_set
) {
116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
118 scoped_refptr
<net::CRLSet
> old_crl_set(net::SSLConfigService::GetCRLSet());
119 if (old_crl_set
.get() && old_crl_set
->sequence() > crl_set
->sequence()) {
120 LOG(WARNING
) << "Refusing to downgrade CRL set from #"
121 << old_crl_set
->sequence()
123 << crl_set
->sequence();
125 net::SSLConfigService::SetCRLSet(crl_set
);
126 VLOG(1) << "Installed CRL set #" << crl_set
->sequence();
130 // kPublicKeySHA256 is the SHA256 hash of the SubjectPublicKeyInfo of the key
131 // that's used to sign generated CRL sets.
132 static const uint8 kPublicKeySHA256
[32] = {
133 0x75, 0xda, 0xf8, 0xcb, 0x77, 0x68, 0x40, 0x33,
134 0x65, 0x4c, 0x97, 0xe5, 0xc5, 0x1b, 0xcd, 0x81,
135 0x7b, 0x1e, 0xeb, 0x11, 0x2c, 0xe1, 0xa4, 0x33,
136 0x8c, 0xf5, 0x72, 0x5e, 0xed, 0xb8, 0x43, 0x97,
139 void CRLSetFetcher::RegisterComponent(uint32 sequence_of_loaded_crl
) {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
142 update_client::CrxComponent component
;
143 component
.pk_hash
.assign(kPublicKeySHA256
,
144 kPublicKeySHA256
+ sizeof(kPublicKeySHA256
));
145 component
.installer
= this;
146 component
.name
= "CRLSet";
147 component
.version
= Version(base::UintToString(sequence_of_loaded_crl
));
148 component
.allow_background_download
= false;
149 if (!component
.version
.IsValid()) {
151 component
.version
= Version("0");
154 if (cus_
->RegisterComponent(component
) !=
155 ComponentUpdateService::kOk
) {
156 NOTREACHED() << "RegisterComponent returned error";
160 void CRLSetFetcher::DoDeleteFromDisk() {
161 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
163 DeleteFile(GetCRLSetFilePath(), false /* not recursive */);
166 void CRLSetFetcher::OnUpdateError(int error
) {
167 LOG(WARNING
) << "CRLSetFetcher got error " << error
168 << " from component installer";
171 bool CRLSetFetcher::Install(const base::DictionaryValue
& manifest
,
172 const base::FilePath
& unpack_path
) {
173 base::FilePath crl_set_file_path
=
174 unpack_path
.Append(FILE_PATH_LITERAL("crl-set"));
175 base::FilePath save_to
= GetCRLSetFilePath();
177 std::string crl_set_bytes
;
178 if (!base::ReadFileToString(crl_set_file_path
, &crl_set_bytes
)) {
179 LOG(WARNING
) << "Failed to find crl-set file inside CRX";
184 if (!net::CRLSetStorage::GetIsDeltaUpdate(crl_set_bytes
, &is_delta
)) {
185 LOG(WARNING
) << "GetIsDeltaUpdate failed on CRL set from update CRX";
189 if (is_delta
&& !crl_set_
.get()) {
190 // The update server gave us a delta update, but we don't have any base
191 // revision to apply it to.
192 LOG(WARNING
) << "Received unsolicited delta update.";
197 if (!net::CRLSetStorage::Parse(crl_set_bytes
, &crl_set_
)) {
198 LOG(WARNING
) << "Failed to parse CRL set from update CRX";
201 int size
= base::checked_cast
<int>(crl_set_bytes
.size());
202 if (base::WriteFile(save_to
, crl_set_bytes
.data(), size
) != size
) {
203 LOG(WARNING
) << "Failed to save new CRL set to disk";
204 // We don't return false here because we can still use this CRL set. When
205 // we restart we might revert to an older version, then we'll
206 // advertise the older version to Omaha and everything will still work.
209 scoped_refptr
<net::CRLSet
> new_crl_set
;
210 if (!net::CRLSetStorage::ApplyDelta(
211 crl_set_
.get(), crl_set_bytes
, &new_crl_set
)) {
212 LOG(WARNING
) << "Failed to parse delta CRL set";
215 VLOG(1) << "Applied CRL set delta #" << crl_set_
->sequence()
216 << "->#" << new_crl_set
->sequence();
217 const std::string new_crl_set_bytes
=
218 net::CRLSetStorage::Serialize(new_crl_set
.get());
219 int size
= base::checked_cast
<int>(new_crl_set_bytes
.size());
220 if (base::WriteFile(save_to
, new_crl_set_bytes
.data(), size
) != size
) {
221 LOG(WARNING
) << "Failed to save new CRL set to disk";
222 // We don't return false here because we can still use this CRL set. When
223 // we restart we might revert to an older version, then we'll
224 // advertise the older version to Omaha and everything will still work.
226 crl_set_
= new_crl_set
;
229 if (!BrowserThread::PostTask(
230 BrowserThread::IO
, FROM_HERE
,
232 &CRLSetFetcher::SetCRLSetIfNewer
, this, crl_set_
))) {
239 bool CRLSetFetcher::GetInstalledFile(
240 const std::string
& file
, base::FilePath
* installed_file
) {
244 bool CRLSetFetcher::Uninstall() {
248 CRLSetFetcher::~CRLSetFetcher() {}