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/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"
23 using component_updater::ComponentUpdateService
;
24 using content::BrowserThread
;
26 CRLSetFetcher::CRLSetFetcher() : cus_(NULL
) {}
28 void CRLSetFetcher::SetCRLSetFilePath(const base::FilePath
& path
) {
29 crl_path_
= path
.Append(chrome::kCRLSetFilename
);
32 base::FilePath
CRLSetFetcher::GetCRLSetFilePath() const {
36 void CRLSetFetcher::StartInitialLoad(ComponentUpdateService
* cus
,
37 const base::FilePath
& path
) {
38 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
41 SetCRLSetFilePath(path
);
44 if (!BrowserThread::PostTask(
45 BrowserThread::FILE, FROM_HERE
,
46 base::Bind(&CRLSetFetcher::DoInitialLoadFromDisk
, this))) {
51 void CRLSetFetcher::DeleteFromDisk(const base::FilePath
& path
) {
52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
56 SetCRLSetFilePath(path
);
57 if (!BrowserThread::PostTask(
58 BrowserThread::FILE, FROM_HERE
,
59 base::Bind(&CRLSetFetcher::DoDeleteFromDisk
, this))) {
64 void CRLSetFetcher::DoInitialLoadFromDisk() {
65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
67 LoadFromDisk(GetCRLSetFilePath(), &crl_set_
);
69 uint32 sequence_of_loaded_crl
= 0;
71 sequence_of_loaded_crl
= crl_set_
->sequence();
73 // Get updates, advertising the sequence number of the CRL set that we just
75 if (!BrowserThread::PostTask(
76 BrowserThread::UI
, FROM_HERE
,
78 &CRLSetFetcher::RegisterComponent
,
80 sequence_of_loaded_crl
))) {
85 void CRLSetFetcher::LoadFromDisk(base::FilePath path
,
86 scoped_refptr
<net::CRLSet
>* out_crl_set
) {
87 TRACE_EVENT0("CRLSetFetcher", "LoadFromDisk");
89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
91 std::string crl_set_bytes
;
93 TRACE_EVENT0("CRLSetFetcher", "ReadFileToString");
94 if (!base::ReadFileToString(path
, &crl_set_bytes
))
98 if (!net::CRLSetStorage::Parse(crl_set_bytes
, out_crl_set
)) {
99 LOG(WARNING
) << "Failed to parse CRL set from " << path
.MaybeAsASCII();
103 VLOG(1) << "Loaded " << crl_set_bytes
.size() << " bytes of CRL set from disk";
105 if (!BrowserThread::PostTask(
106 BrowserThread::IO
, FROM_HERE
,
108 &CRLSetFetcher::SetCRLSetIfNewer
, this, *out_crl_set
))) {
113 void CRLSetFetcher::SetCRLSetIfNewer(
114 scoped_refptr
<net::CRLSet
> crl_set
) {
115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
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()
122 << crl_set
->sequence();
124 net::SSLConfigService::SetCRLSet(crl_set
);
125 VLOG(1) << "Installed CRL set #" << crl_set
->sequence();
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,
138 void CRLSetFetcher::RegisterComponent(uint32 sequence_of_loaded_crl
) {
139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
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()) {
150 component
.version
= Version("0");
153 if (cus_
->RegisterComponent(component
) !=
154 ComponentUpdateService::kOk
) {
155 NOTREACHED() << "RegisterComponent returned error";
159 void CRLSetFetcher::DoDeleteFromDisk() {
160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
162 DeleteFile(GetCRLSetFilePath(), false /* not recursive */);
165 void CRLSetFetcher::OnUpdateError(int error
) {
166 LOG(WARNING
) << "CRLSetFetcher got error " << error
167 << " from component installer";
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();
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";
183 if (!net::CRLSetStorage::GetIsDeltaUpdate(crl_set_bytes
, &is_delta
)) {
184 LOG(WARNING
) << "GetIsDeltaUpdate failed on CRL set from update CRX";
189 if (!net::CRLSetStorage::Parse(crl_set_bytes
, &crl_set_
)) {
190 LOG(WARNING
) << "Failed to parse CRL set from update CRX";
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.
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";
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.
218 crl_set_
= new_crl_set
;
221 if (!BrowserThread::PostTask(
222 BrowserThread::IO
, FROM_HERE
,
224 &CRLSetFetcher::SetCRLSetIfNewer
, this, crl_set_
))) {
231 bool CRLSetFetcher::GetInstalledFile(
232 const std::string
& file
, base::FilePath
* installed_file
) {
236 CRLSetFetcher::~CRLSetFetcher() {}