1 // Copyright 2014 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/component_updater/ev_whitelist_component_installer.h"
10 #include "base/bind.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/lazy_instance.h"
14 #include "base/logging.h"
15 #include "base/numerics/safe_conversions.h"
16 #include "base/path_service.h"
17 #include "base/version.h"
18 #include "components/component_updater/component_updater_paths.h"
19 #include "components/packed_ct_ev_whitelist/packed_ct_ev_whitelist.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "net/ssl/ssl_config_service.h"
23 using component_updater::ComponentUpdateService
;
26 const base::FilePath::CharType kCompressedEVWhitelistFileName
[] =
27 FILE_PATH_LITERAL("ev_hashes_whitelist.bin");
29 base::FilePath
GetEVWhitelistFilePath(const base::FilePath
& base_path
) {
30 return base_path
.Append(kCompressedEVWhitelistFileName
);
33 void UpdateNewWhitelistData(const base::FilePath
& new_whitelist_file
,
34 const base::FilePath
& stored_whitelist_path
,
35 const base::Version
& version
) {
36 VLOG(1) << "Reading new EV whitelist from file: "
37 << new_whitelist_file
.value();
38 std::string compressed_list
;
39 if (!base::ReadFileToString(new_whitelist_file
, &compressed_list
)) {
40 VLOG(1) << "Failed reading from " << new_whitelist_file
.value();
44 scoped_refptr
<net::ct::EVCertsWhitelist
> new_whitelist(
45 new packed_ct_ev_whitelist::PackedEVCertsWhitelist(compressed_list
,
47 if (!new_whitelist
->IsValid()) {
48 VLOG(1) << "Failed uncompressing EV certs whitelist.";
52 if (base::IsValueInRangeForNumericType
<int>(compressed_list
.size())) {
53 const int list_size
= base::checked_cast
<int>(compressed_list
.size());
54 if (base::WriteFile(stored_whitelist_path
, compressed_list
.data(),
55 list_size
) != list_size
) {
56 LOG(WARNING
) << "Failed to save new EV whitelist to file.";
60 packed_ct_ev_whitelist::SetEVCertsWhitelist(new_whitelist
);
63 void DoInitialLoadFromDisk(const base::FilePath
& stored_whitelist_path
) {
64 if (stored_whitelist_path
.empty()) {
68 VLOG(1) << "Initial load: reading EV whitelist from file: "
69 << stored_whitelist_path
.value();
70 std::string compressed_list
;
71 if (!base::ReadFileToString(stored_whitelist_path
, &compressed_list
)) {
72 VLOG(1) << "Failed reading from " << stored_whitelist_path
.value();
76 // The version number is unknown as the list is loaded from disk, not
78 // In practice very quickly the component updater will call ComponentReady
79 // which will have a valid version.
80 scoped_refptr
<net::ct::EVCertsWhitelist
> new_whitelist(
81 new packed_ct_ev_whitelist::PackedEVCertsWhitelist(compressed_list
,
83 if (!new_whitelist
->IsValid()) {
84 VLOG(1) << "Failed uncompressing EV certs whitelist.";
88 VLOG(1) << "EV whitelist: Sucessfully loaded initial data.";
89 packed_ct_ev_whitelist::SetEVCertsWhitelist(new_whitelist
);
94 namespace component_updater
{
96 // The SHA256 of the SubjectPublicKeyInfo used to sign the extension.
97 // The extension id is: oafdbfcohdcjandcenmccfopbeklnicp
98 const uint8_t kPublicKeySHA256
[32] = {
99 0xe0, 0x53, 0x15, 0x2e, 0x73, 0x29, 0x0d, 0x32, 0x4d, 0xc2, 0x25,
100 0xef, 0x14, 0xab, 0xd8, 0x2f, 0x84, 0xf5, 0x85, 0x9e, 0xc0, 0xfa,
101 0x94, 0xbc, 0x99, 0xc9, 0x5a, 0x27, 0x55, 0x19, 0x83, 0xef};
103 const char kEVWhitelistManifestName
[] = "EV Certs CT whitelist";
105 EVWhitelistComponentInstallerTraits::EVWhitelistComponentInstallerTraits(
106 const base::FilePath
& base_path
)
107 : ev_whitelist_path_(GetEVWhitelistFilePath(base_path
)) {
110 bool EVWhitelistComponentInstallerTraits::CanAutoUpdate() const {
114 bool EVWhitelistComponentInstallerTraits::OnCustomInstall(
115 const base::DictionaryValue
& manifest
,
116 const base::FilePath
& install_dir
) {
117 VLOG(1) << "Entering EVWhitelistComponentInstallerTraits::OnCustomInstall.";
119 return true; // Nothing custom here.
122 base::FilePath
EVWhitelistComponentInstallerTraits::GetInstalledPath(
123 const base::FilePath
& base
) {
124 // EV whitelist is encoded the same way for all platforms
125 return base
.Append(FILE_PATH_LITERAL("_platform_specific"))
126 .Append(FILE_PATH_LITERAL("all"))
127 .Append(kCompressedEVWhitelistFileName
);
130 void EVWhitelistComponentInstallerTraits::ComponentReady(
131 const base::Version
& version
,
132 const base::FilePath
& path
,
133 scoped_ptr
<base::DictionaryValue
> manifest
) {
134 VLOG(1) << "Component ready, version " << version
.GetString() << " in "
137 const base::FilePath whitelist_file
= GetInstalledPath(path
);
138 content::BrowserThread::PostBlockingPoolTask(
139 FROM_HERE
, base::Bind(&UpdateNewWhitelistData
, whitelist_file
,
140 ev_whitelist_path_
, version
));
143 bool EVWhitelistComponentInstallerTraits::VerifyInstallation(
144 const base::DictionaryValue
& manifest
,
145 const base::FilePath
& install_dir
) const {
146 const base::FilePath expected_file
= GetInstalledPath(install_dir
);
147 VLOG(1) << "Verifying install: " << expected_file
.value();
148 if (!base::PathExists(expected_file
)) {
149 VLOG(1) << "File missing.";
153 std::string compressed_whitelist
;
154 if (!base::ReadFileToString(expected_file
, &compressed_whitelist
)) {
155 VLOG(1) << "Failed reading the compressed EV hashes whitelist.";
159 VLOG(1) << "Whitelist size: " << compressed_whitelist
.size();
161 return !compressed_whitelist
.empty();
164 base::FilePath
EVWhitelistComponentInstallerTraits::GetBaseDirectory() const {
165 base::FilePath result
;
166 PathService::Get(DIR_COMPONENT_EV_WHITELIST
, &result
);
170 void EVWhitelistComponentInstallerTraits::GetHash(
171 std::vector
<uint8_t>* hash
) const {
172 hash
->assign(kPublicKeySHA256
,
173 kPublicKeySHA256
+ arraysize(kPublicKeySHA256
));
176 std::string
EVWhitelistComponentInstallerTraits::GetName() const {
177 return kEVWhitelistManifestName
;
180 void RegisterEVWhitelistComponent(ComponentUpdateService
* cus
,
181 const base::FilePath
& path
) {
182 VLOG(1) << "Registering EV whitelist component.";
184 scoped_ptr
<ComponentInstallerTraits
> traits(
185 new EVWhitelistComponentInstallerTraits(path
));
186 // |cus| will take ownership of |installer| during installer->Register(cus).
187 DefaultComponentInstaller
* installer
=
188 new DefaultComponentInstaller(traits
.Pass());
189 installer
->Register(cus
, base::Closure());
191 if (!content::BrowserThread::PostBlockingPoolTask(
193 base::Bind(&DoInitialLoadFromDisk
, GetEVWhitelistFilePath(path
)))) {
198 } // namespace component_updater