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_CURRENTLY_ON(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_CURRENTLY_ON(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_CURRENTLY_ON(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_CURRENTLY_ON(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_CURRENTLY_ON(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_CURRENTLY_ON(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 NOTREACHED() << "RegisterComponent returned error";
158 void CRLSetFetcher::DoDeleteFromDisk() {
159 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
161 DeleteFile(GetCRLSetFilePath(), false /* not recursive */);
164 void CRLSetFetcher::OnUpdateError(int error
) {
165 LOG(WARNING
) << "CRLSetFetcher got error " << error
166 << " from component installer";
169 bool CRLSetFetcher::Install(const base::DictionaryValue
& manifest
,
170 const base::FilePath
& unpack_path
) {
171 base::FilePath crl_set_file_path
=
172 unpack_path
.Append(FILE_PATH_LITERAL("crl-set"));
173 base::FilePath save_to
= GetCRLSetFilePath();
175 std::string crl_set_bytes
;
176 if (!base::ReadFileToString(crl_set_file_path
, &crl_set_bytes
)) {
177 LOG(WARNING
) << "Failed to find crl-set file inside CRX";
182 if (!net::CRLSetStorage::GetIsDeltaUpdate(crl_set_bytes
, &is_delta
)) {
183 LOG(WARNING
) << "GetIsDeltaUpdate failed on CRL set from update CRX";
187 if (is_delta
&& !crl_set_
.get()) {
188 // The update server gave us a delta update, but we don't have any base
189 // revision to apply it to.
190 LOG(WARNING
) << "Received unsolicited delta update.";
195 if (!net::CRLSetStorage::Parse(crl_set_bytes
, &crl_set_
)) {
196 LOG(WARNING
) << "Failed to parse CRL set from update CRX";
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.
207 scoped_refptr
<net::CRLSet
> new_crl_set
;
208 if (!net::CRLSetStorage::ApplyDelta(
209 crl_set_
.get(), crl_set_bytes
, &new_crl_set
)) {
210 LOG(WARNING
) << "Failed to parse delta CRL set";
213 VLOG(1) << "Applied CRL set delta #" << crl_set_
->sequence()
214 << "->#" << new_crl_set
->sequence();
215 const std::string new_crl_set_bytes
=
216 net::CRLSetStorage::Serialize(new_crl_set
.get());
217 int size
= base::checked_cast
<int>(new_crl_set_bytes
.size());
218 if (base::WriteFile(save_to
, new_crl_set_bytes
.data(), size
) != size
) {
219 LOG(WARNING
) << "Failed to save new CRL set to disk";
220 // We don't return false here because we can still use this CRL set. When
221 // we restart we might revert to an older version, then we'll
222 // advertise the older version to Omaha and everything will still work.
224 crl_set_
= new_crl_set
;
227 if (!BrowserThread::PostTask(
228 BrowserThread::IO
, FROM_HERE
,
230 &CRLSetFetcher::SetCRLSetIfNewer
, this, crl_set_
))) {
237 bool CRLSetFetcher::GetInstalledFile(
238 const std::string
& file
, base::FilePath
* installed_file
) {
242 bool CRLSetFetcher::Uninstall() {
246 CRLSetFetcher::~CRLSetFetcher() {}