Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 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/component_updater/sth_set_component_installer.h" | |
| 6 | |
| 7 #include <string> | |
| 8 #include <utility> | |
| 9 #include <vector> | |
| 10 | |
| 11 #include "base/bind.h" | |
| 12 #include "base/files/file_enumerator.h" | |
| 13 #include "base/files/file_path.h" | |
| 14 #include "base/files/file_util.h" | |
| 15 #include "base/logging.h" | |
| 16 #include "base/macros.h" | |
| 17 #include "base/path_service.h" | |
| 18 #include "base/strings/string_number_conversions.h" | |
| 19 #include "base/values.h" | |
| 20 #include "base/version.h" | |
| 21 #include "components/component_updater/component_updater_paths.h" | |
| 22 #include "components/safe_json/safe_json_parser.h" | |
| 23 #include "content/public/browser/browser_thread.h" | |
| 24 #include "crypto/sha2.h" | |
| 25 #include "net/cert/ct_known_logs_static.h" | |
| 26 #include "net/cert/ct_log_response_parser.h" | |
| 27 #include "net/cert/signed_tree_head.h" | |
| 28 | |
| 29 using component_updater::ComponentUpdateService; | |
| 30 | |
| 31 namespace { | |
| 32 const base::FilePath::CharType kSTHsDirName[] = FILE_PATH_LITERAL("sths"); | |
| 33 } // namespace | |
| 34 | |
| 35 namespace component_updater { | |
| 36 | |
| 37 // The SHA256 of the SubjectPublicKeyInfo used to sign the extension. | |
| 38 // The extension id is: aplidfpohcjpojgnkjpkibbkcghkogef | |
|
waffles
2016/04/01 17:01:55
We will use ojjgnpkioondelmggbekfhllhdaimnho
Eran Messeri
2016/04/04 13:10:02
Done.
| |
| 39 const uint8_t kPublicKeySHA256[32] = { | |
| 40 0x0f, 0xb8, 0x35, 0xfe, 0x72, 0x9f, 0xe9, 0x6d, 0xa9, 0xfa, 0x81, | |
| 41 0x1a, 0x26, 0x7a, 0xe6, 0x45, 0x22, 0x50, 0xc4, 0xd4, 0x01, 0xcc, | |
| 42 0x33, 0x90, 0x1c, 0xe9, 0x44, 0x37, 0xc4, 0xa0, 0x2e, 0x02}; | |
|
waffles
2016/04/01 17:01:55
We will use e996dfa8eed34bc6614a57bb7308cd7e519bcc
Eran Messeri
2016/04/04 13:10:02
Done, thanks.
| |
| 43 | |
| 44 const char kSTHSetFetcherManifestName[] = "Signed Tree Heads"; | |
| 45 | |
| 46 STHSetComponentInstallerTraits::STHSetComponentInstallerTraits( | |
| 47 scoped_ptr<net::ct::STHObserver> sth_observer) | |
| 48 : sth_observer_(std::move(sth_observer)) { | |
| 49 VLOG(1) << "XXX: STHSetComponentInstallerTraits::c'tor"; | |
|
waffles
2016/04/01 17:01:55
These logging statements should be cleaned up prio
Eran Messeri
2016/04/04 13:10:02
Done - removed debugging statements, I did leave s
| |
| 50 } | |
| 51 | |
| 52 STHSetComponentInstallerTraits::~STHSetComponentInstallerTraits() { | |
| 53 VLOG(1) << "XXX: STHSetComponentInstallerTraits::d'tor"; | |
| 54 } | |
| 55 | |
| 56 bool STHSetComponentInstallerTraits::CanAutoUpdate() const { | |
| 57 return true; | |
| 58 } | |
| 59 | |
| 60 bool STHSetComponentInstallerTraits::OnCustomInstall( | |
| 61 const base::DictionaryValue& manifest, | |
| 62 const base::FilePath& install_dir) { | |
| 63 VLOG(1) << "Entering STHSetComponentInstallerTraits::OnCustomInstall."; | |
| 64 | |
| 65 return true; // Nothing custom here. | |
| 66 } | |
| 67 | |
| 68 base::FilePath STHSetComponentInstallerTraits::GetInstalledPath( | |
| 69 const base::FilePath& base) { | |
| 70 return base.Append(FILE_PATH_LITERAL("_platform_specific")) | |
| 71 .Append(FILE_PATH_LITERAL("all")) | |
| 72 .Append(kSTHsDirName); | |
| 73 } | |
| 74 | |
| 75 void STHSetComponentInstallerTraits::ComponentReady( | |
| 76 const base::Version& version, | |
| 77 const base::FilePath& install_dir, | |
| 78 scoped_ptr<base::DictionaryValue> manifest) { | |
| 79 VLOG(1) << "Component ready, version " << version.GetString() << " in " | |
| 80 << install_dir.value(); | |
| 81 | |
| 82 if (!content::BrowserThread::PostBlockingPoolTask( | |
| 83 FROM_HERE, | |
| 84 base::Bind(&STHSetComponentInstallerTraits::LoadSTHsFromDisk, | |
| 85 base::Unretained(this), GetInstalledPath(install_dir), | |
| 86 version))) { | |
| 87 NOTREACHED(); | |
|
waffles
2016/04/01 17:01:55
Not sure about this.
Eran Messeri
2016/04/04 13:10:02
That's a pattern used in other components - will b
| |
| 88 } | |
| 89 } | |
| 90 | |
| 91 // Called during startup and installation before ComponentReady(). | |
| 92 bool STHSetComponentInstallerTraits::VerifyInstallation( | |
| 93 const base::DictionaryValue& manifest, | |
| 94 const base::FilePath& install_dir) const { | |
| 95 return base::PathExists(GetInstalledPath(install_dir)); | |
| 96 } | |
| 97 | |
| 98 base::FilePath STHSetComponentInstallerTraits::GetBaseDirectory() const { | |
| 99 base::FilePath result; | |
| 100 PathService::Get(DIR_CERT_TRANS_TREE_STATES, &result); | |
| 101 return result; | |
| 102 } | |
| 103 | |
| 104 void STHSetComponentInstallerTraits::GetHash(std::vector<uint8_t>* hash) const { | |
| 105 hash->assign(kPublicKeySHA256, | |
| 106 kPublicKeySHA256 + arraysize(kPublicKeySHA256)); | |
| 107 } | |
| 108 | |
| 109 std::string STHSetComponentInstallerTraits::GetName() const { | |
| 110 return kSTHSetFetcherManifestName; | |
| 111 } | |
| 112 | |
| 113 void STHSetComponentInstallerTraits::LoadSTHsFromDisk( | |
| 114 const base::FilePath& sths_path, | |
| 115 const base::Version& version) { | |
| 116 if (sths_path.empty()) | |
| 117 return; | |
| 118 | |
| 119 base::FileEnumerator sth_file_enumerator(sths_path, false, | |
| 120 base::FileEnumerator::FILES, | |
| 121 FILE_PATH_LITERAL("*.sth")); | |
| 122 base::FilePath sth_file_path; | |
| 123 | |
| 124 while (!(sth_file_path = sth_file_enumerator.Next()).empty()) { | |
| 125 VLOG(1) << "Reading STH from file: " << sth_file_path.value(); | |
| 126 | |
| 127 std::string log_id_hex = | |
| 128 sth_file_path.BaseName().RemoveExtension().MaybeAsASCII(); | |
| 129 if (log_id_hex.empty()) { | |
| 130 DVLOG(1) << "Error extracting log_id from: " | |
| 131 << sth_file_path.BaseName().LossyDisplayName(); | |
| 132 continue; | |
| 133 } | |
| 134 | |
| 135 std::vector<uint8_t> decoding_output; | |
| 136 if (!base::HexStringToBytes(log_id_hex, &decoding_output)) { | |
| 137 DVLOG(1) << "Failed to decode Log ID: " << log_id_hex; | |
| 138 continue; | |
| 139 } | |
| 140 | |
| 141 std::string log_id; | |
| 142 log_id.assign(reinterpret_cast<const char*>(&decoding_output[0]), | |
| 143 decoding_output.size()); | |
| 144 | |
| 145 std::string json_sth; | |
| 146 if (!base::ReadFileToString(sth_file_path, &json_sth)) { | |
| 147 VLOG(1) << "Failed reading from " << sth_file_path.value(); | |
| 148 continue; | |
| 149 } | |
| 150 | |
| 151 VLOG(1) << "STH: Successfully read: " << json_sth; | |
| 152 safe_json::SafeJsonParser::Parse( | |
|
waffles
2016/04/01 17:01:55
Hm, I wonder if it is a good idea to do this kind
Eran Messeri
2016/04/03 05:24:10
Good point - do you have any metrics on how many c
| |
| 153 json_sth, | |
| 154 base::Bind(&STHSetComponentInstallerTraits::OnJsonParseSuccess, | |
| 155 base::Unretained(this), log_id), | |
| 156 base::Bind(&STHSetComponentInstallerTraits::OnJsonParseError, | |
| 157 base::Unretained(this), log_id)); | |
| 158 } | |
| 159 } | |
| 160 | |
| 161 void STHSetComponentInstallerTraits::OnJsonParseSuccess( | |
| 162 std::string log_id, | |
| 163 scoped_ptr<base::Value> parsed_json) { | |
| 164 net::ct::SignedTreeHead signed_tree_head; | |
| 165 VLOG(0) << "STH parsing success for log: " | |
| 166 << base::HexEncode(log_id.data(), log_id.length()); | |
| 167 if (!net::ct::FillSignedTreeHead(*(parsed_json.get()), &signed_tree_head)) { | |
| 168 LOG(WARNING) << "Failed to fill in signed tree head."; | |
| 169 return; | |
| 170 } | |
| 171 | |
| 172 // The log id is not a part of the response, fill in manually. | |
| 173 signed_tree_head.log_id = log_id; | |
| 174 content::BrowserThread::PostTask( | |
| 175 content::BrowserThread::IO, FROM_HERE, | |
| 176 base::Bind(&net::ct::STHObserver::NewSTHObserved, | |
| 177 base::Unretained(sth_observer_.get()), signed_tree_head)); | |
| 178 } | |
| 179 | |
| 180 void STHSetComponentInstallerTraits::OnJsonParseError( | |
| 181 std::string log_id, | |
| 182 const std::string& error) { | |
| 183 VLOG(0) << "STH loading failed: " << error | |
| 184 << " for log: " << base::HexEncode(log_id.data(), log_id.length()); | |
| 185 } | |
| 186 | |
| 187 void RegisterSTHSetComponent( | |
| 188 ComponentUpdateService* cus, | |
| 189 const base::FilePath& user_data_dir, | |
| 190 scoped_ptr<net::ct::STHObserver> sth_observer) { | |
| 191 VLOG(1) << "Registering STH Set fetcher component."; | |
| 192 | |
| 193 scoped_ptr<ComponentInstallerTraits> traits( | |
| 194 new STHSetComponentInstallerTraits(std::move(sth_observer))); | |
| 195 // |cus| will take ownership of |installer| during installer->Register(cus). | |
| 196 DefaultComponentInstaller* installer = | |
| 197 new DefaultComponentInstaller(std::move(traits)); | |
| 198 installer->Register(cus, base::Closure()); | |
| 199 } | |
| 200 | |
| 201 } // namespace component_updater | |
| OLD | NEW |