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. 4 5 #include "components/component_updater/component_unpacker.h" 6 7 #include <stdint.h> 8 #include <string> 9 #include <vector> 10 11 #include "base/bind.h" 12 #include "base/files/file_path.h" 13 #include "base/files/file_util.h" 14 #include "base/files/scoped_file.h" 15 #include "base/json/json_file_value_serializer.h" 16 #include "base/location.h" 17 #include "base/logging.h" 18 #include "base/numerics/safe_conversions.h" 19 #include "base/strings/string_number_conversions.h" 20 #include "base/strings/stringprintf.h" 21 #include "base/values.h" 22 #include "components/component_updater/component_patcher.h" 23 #include "components/component_updater/component_patcher_operation.h" 24 #include "components/component_updater/component_updater_service.h" 25 #include "components/crx_file/constants.h" 26 #include "components/crx_file/crx_file.h" 27 #include "crypto/secure_hash.h" 28 #include "crypto/signature_verifier.h" 29 #include "third_party/zlib/google/zip.h" 30 31 using crypto::SecureHash; 32 33 namespace component_updater { 34 35 namespace { 36 37 // This class makes sure that the CRX digital signature is valid 38 // and well formed. 39 class CRXValidator { 40 public: 41 explicit CRXValidator(FILE* crx_file) : valid_(false), is_delta_(false) { 42 crx_file::CrxFile::Header header; 43 size_t len = fread(&header, 1, sizeof(header), crx_file); 44 if (len < sizeof(header)) 45 return; 46 47 crx_file::CrxFile::Error error; 48 scoped_ptr<crx_file::CrxFile> crx( 49 crx_file::CrxFile::Parse(header, &error)); 50 if (!crx.get()) 51 return; 52 is_delta_ = crx_file::CrxFile::HeaderIsDelta(header); 53 54 std::vector<uint8_t> key(header.key_size); 55 len = fread(&key[0], sizeof(uint8_t), header.key_size, crx_file); 56 if (len < header.key_size) 57 return; 58 59 std::vector<uint8_t> signature(header.signature_size); 60 len = 61 fread(&signature[0], sizeof(uint8_t), header.signature_size, crx_file); 62 if (len < header.signature_size) 63 return; 64 65 crypto::SignatureVerifier verifier; 66 if (!verifier.VerifyInit(crx_file::kSignatureAlgorithm, 67 base::checked_cast<int>( 68 sizeof(crx_file::kSignatureAlgorithm)), 69 &signature[0], 70 base::checked_cast<int>(signature.size()), 71 &key[0], 72 base::checked_cast<int>(key.size()))) { 73 // Signature verification initialization failed. This is most likely 74 // caused by a public key in the wrong format (should encode algorithm). 75 return; 76 } 77 78 const size_t kBufSize = 8 * 1024; 79 scoped_ptr<uint8_t[]> buf(new uint8_t[kBufSize]); 80 while ((len = fread(buf.get(), 1, kBufSize, crx_file)) > 0) 81 verifier.VerifyUpdate(buf.get(), base::checked_cast<int>(len)); 82 83 if (!verifier.VerifyFinal()) 84 return; 85 86 public_key_.swap(key); 87 valid_ = true; 88 } 89 90 bool valid() const { return valid_; } 91 92 bool is_delta() const { return is_delta_; } 93 94 const std::vector<uint8_t>& public_key() const { return public_key_; } 95 96 private: 97 bool valid_; 98 bool is_delta_; 99 std::vector<uint8_t> public_key_; 100 }; 101 102 } // namespace 103 104 ComponentUnpacker::ComponentUnpacker( 105 const std::vector<uint8_t>& pk_hash, 106 const base::FilePath& path, 107 const std::string& fingerprint, 108 ComponentInstaller* installer, 109 scoped_refptr<OutOfProcessPatcher> out_of_process_patcher, 110 scoped_refptr<base::SequencedTaskRunner> task_runner) 111 : pk_hash_(pk_hash), 112 path_(path), 113 is_delta_(false), 114 fingerprint_(fingerprint), 115 installer_(installer), 116 out_of_process_patcher_(out_of_process_patcher), 117 error_(kNone), 118 extended_error_(0), 119 task_runner_(task_runner) { 120 } 121 122 // TODO(cpu): add a specific attribute check to a component json that the 123 // extension unpacker will reject, so that a component cannot be installed 124 // as an extension. 125 scoped_ptr<base::DictionaryValue> ReadManifest( 126 const base::FilePath& unpack_path) { 127 base::FilePath manifest = 128 unpack_path.Append(FILE_PATH_LITERAL("manifest.json")); 129 if (!base::PathExists(manifest)) 130 return scoped_ptr<base::DictionaryValue>(); 131 JSONFileValueSerializer serializer(manifest); 132 std::string error; 133 scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error)); 134 if (!root.get()) 135 return scoped_ptr<base::DictionaryValue>(); 136 if (!root->IsType(base::Value::TYPE_DICTIONARY)) 137 return scoped_ptr<base::DictionaryValue>(); 138 return scoped_ptr<base::DictionaryValue>( 139 static_cast<base::DictionaryValue*>(root.release())).Pass(); 140 } 141 142 bool ComponentUnpacker::UnpackInternal() { 143 return Verify() && Unzip() && BeginPatching(); 144 } 145 146 void ComponentUnpacker::Unpack(const Callback& callback) { 147 callback_ = callback; 148 if (!UnpackInternal()) 149 Finish(); 150 } 151 152 bool ComponentUnpacker::Verify() { 153 VLOG(1) << "Verifying component: " << path_.value(); 154 if (pk_hash_.empty() || path_.empty()) { 155 error_ = kInvalidParams; 156 return false; 157 } 158 // First, validate the CRX header and signature. As of today 159 // this is SHA1 with RSA 1024. 160 base::ScopedFILE file(base::OpenFile(path_, "rb")); 161 if (!file.get()) { 162 error_ = kInvalidFile; 163 return false; 164 } 165 CRXValidator validator(file.get()); 166 file.reset(); 167 if (!validator.valid()) { 168 error_ = kInvalidFile; 169 return false; 170 } 171 is_delta_ = validator.is_delta(); 172 173 // File is valid and the digital signature matches. Now make sure 174 // the public key hash matches the expected hash. If they do we fully 175 // trust this CRX. 176 uint8_t hash[32] = {}; 177 scoped_ptr<SecureHash> sha256(SecureHash::Create(SecureHash::SHA256)); 178 sha256->Update(&(validator.public_key()[0]), validator.public_key().size()); 179 sha256->Finish(hash, arraysize(hash)); 180 181 if (!std::equal(pk_hash_.begin(), pk_hash_.end(), hash)) { 182 VLOG(1) << "Hash mismatch: " << path_.value(); 183 error_ = kInvalidId; 184 return false; 185 } 186 VLOG(1) << "Verification successful: " << path_.value(); 187 return true; 188 } 189 190 bool ComponentUnpacker::Unzip() { 191 base::FilePath& destination = is_delta_ ? unpack_diff_path_ : unpack_path_; 192 VLOG(1) << "Unpacking in: " << destination.value(); 193 if (!base::CreateNewTempDirectory(base::FilePath::StringType(), 194 &destination)) { 195 VLOG(1) << "Unable to create temporary directory for unpacking."; 196 error_ = kUnzipPathError; 197 return false; 198 } 199 if (!zip::Unzip(path_, destination)) { 200 VLOG(1) << "Unzipping failed."; 201 error_ = kUnzipFailed; 202 return false; 203 } 204 VLOG(1) << "Unpacked successfully"; 205 return true; 206 } 207 208 bool ComponentUnpacker::BeginPatching() { 209 if (is_delta_) { // Package is a diff package. 210 // Use a different temp directory for the patch output files. 211 if (!base::CreateNewTempDirectory(base::FilePath::StringType(), 212 &unpack_path_)) { 213 error_ = kUnzipPathError; 214 return false; 215 } 216 patcher_ = new ComponentPatcher(unpack_diff_path_, 217 unpack_path_, 218 installer_, 219 out_of_process_patcher_, 220 task_runner_); 221 task_runner_->PostTask( 222 FROM_HERE, 223 base::Bind(&ComponentPatcher::Start, 224 patcher_, 225 base::Bind(&ComponentUnpacker::EndPatching, 226 scoped_refptr<ComponentUnpacker>(this)))); 227 } else { 228 task_runner_->PostTask(FROM_HERE, 229 base::Bind(&ComponentUnpacker::EndPatching, 230 scoped_refptr<ComponentUnpacker>(this), 231 kNone, 232 0)); 233 } 234 return true; 235 } 236 237 void ComponentUnpacker::EndPatching(Error error, int extended_error) { 238 error_ = error; 239 extended_error_ = extended_error; 240 patcher_ = NULL; 241 if (error_ != kNone) { 242 Finish(); 243 return; 244 } 245 // Optimization: clean up patch files early, in case disk space is too low to 246 // install otherwise. 247 if (!unpack_diff_path_.empty()) { 248 base::DeleteFile(unpack_diff_path_, true); 249 unpack_diff_path_.clear(); 250 } 251 Install(); 252 Finish(); 253 } 254 255 void ComponentUnpacker::Install() { 256 // Write the fingerprint to disk. 257 if (static_cast<int>(fingerprint_.size()) != 258 base::WriteFile( 259 unpack_path_.Append(FILE_PATH_LITERAL("manifest.fingerprint")), 260 fingerprint_.c_str(), 261 base::checked_cast<int>(fingerprint_.size()))) { 262 error_ = kFingerprintWriteFailed; 263 return; 264 } 265 scoped_ptr<base::DictionaryValue> manifest(ReadManifest(unpack_path_)); 266 if (!manifest.get()) { 267 error_ = kBadManifest; 268 return; 269 } 270 DCHECK(error_ == kNone); 271 if (!installer_->Install(*manifest, unpack_path_)) { 272 error_ = kInstallerError; 273 return; 274 } 275 } 276 277 void ComponentUnpacker::Finish() { 278 if (!unpack_diff_path_.empty()) 279 base::DeleteFile(unpack_diff_path_, true); 280 if (!unpack_path_.empty()) 281 base::DeleteFile(unpack_path_, true); 282 callback_.Run(error_, extended_error_); 283 } 284 285 ComponentUnpacker::~ComponentUnpacker() { 286 } 287 288 } // namespace component_updater 289