blob: 74b17853bacf6890421a15b6ae0302ac5ea9d0b0 [file] [log] [blame]
[email protected]f1050432012-02-15 01:35:461// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]2e114e732011-07-22 02:55:042// 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/component_unpacker.h"
6
7#include <string>
8#include <vector>
9
[email protected]f5d27e32014-01-31 06:48:5310#include "base/bind.h"
[email protected]2e114e732011-07-22 02:55:0411#include "base/file_util.h"
[email protected]f5d27e32014-01-31 06:48:5312#include "base/files/file_path.h"
[email protected]0910bae2014-06-10 17:53:2113#include "base/files/scoped_file.h"
[email protected]ffbec692012-02-26 20:26:4214#include "base/json/json_file_value_serializer.h"
[email protected]9e1685a2014-02-13 15:08:3415#include "base/location.h"
[email protected]871bdf12013-10-26 10:52:0616#include "base/logging.h"
[email protected]3ea1b182013-02-08 22:38:4117#include "base/strings/string_number_conversions.h"
[email protected]e7463412013-06-10 22:53:4618#include "base/strings/stringprintf.h"
[email protected]871bdf12013-10-26 10:52:0619#include "base/values.h"
[email protected]e3e696d32013-06-21 20:41:3620#include "chrome/browser/component_updater/component_patcher.h"
[email protected]2e114e732011-07-22 02:55:0421#include "chrome/browser/component_updater/component_updater_service.h"
[email protected]2e114e732011-07-22 02:55:0422#include "crypto/secure_hash.h"
23#include "crypto/signature_verifier.h"
[email protected]cda103d2014-04-04 16:22:3924#include "extensions/common/constants.h"
[email protected]993da5e2013-03-23 21:25:1625#include "extensions/common/crx_file.h"
[email protected]4170d3a2013-05-03 23:02:5726#include "third_party/zlib/google/zip.h"
[email protected]2e114e732011-07-22 02:55:0427
28using crypto::SecureHash;
29
[email protected]055981f2014-01-17 20:22:3230namespace component_updater {
31
[email protected]2e114e732011-07-22 02:55:0432namespace {
[email protected]e3e696d32013-06-21 20:41:3633
[email protected]2e114e732011-07-22 02:55:0434// This class makes sure that the CRX digital signature is valid
35// and well formed.
36class CRXValidator {
37 public:
[email protected]f5d27e32014-01-31 06:48:5338 explicit CRXValidator(FILE* crx_file) : valid_(false), is_delta_(false) {
[email protected]bf3d9df2012-07-24 23:20:2739 extensions::CrxFile::Header header;
[email protected]2e114e732011-07-22 02:55:0440 size_t len = fread(&header, 1, sizeof(header), crx_file);
[email protected]802a30e2012-06-26 10:19:4141 if (len < sizeof(header))
[email protected]2e114e732011-07-22 02:55:0442 return;
[email protected]802a30e2012-06-26 10:19:4143
[email protected]bf3d9df2012-07-24 23:20:2744 extensions::CrxFile::Error error;
45 scoped_ptr<extensions::CrxFile> crx(
46 extensions::CrxFile::Parse(header, &error));
[email protected]802a30e2012-06-26 10:19:4147 if (!crx.get())
[email protected]2e114e732011-07-22 02:55:0448 return;
[email protected]f5d27e32014-01-31 06:48:5349 is_delta_ = extensions::CrxFile::HeaderIsDelta(header);
[email protected]2e114e732011-07-22 02:55:0450
51 std::vector<uint8> key(header.key_size);
52 len = fread(&key[0], sizeof(uint8), header.key_size, crx_file);
[email protected]802a30e2012-06-26 10:19:4153 if (len < header.key_size)
[email protected]2e114e732011-07-22 02:55:0454 return;
[email protected]2e114e732011-07-22 02:55:0455
56 std::vector<uint8> signature(header.signature_size);
57 len = fread(&signature[0], sizeof(uint8), header.signature_size, crx_file);
[email protected]802a30e2012-06-26 10:19:4158 if (len < header.signature_size)
[email protected]2e114e732011-07-22 02:55:0459 return;
[email protected]2e114e732011-07-22 02:55:0460
61 crypto::SignatureVerifier verifier;
62 if (!verifier.VerifyInit(extension_misc::kSignatureAlgorithm,
63 sizeof(extension_misc::kSignatureAlgorithm),
[email protected]d0c8b8b42014-05-06 05:11:4564 &signature[0],
65 signature.size(),
66 &key[0],
67 key.size())) {
[email protected]2e114e732011-07-22 02:55:0468 // Signature verification initialization failed. This is most likely
69 // caused by a public key in the wrong format (should encode algorithm).
[email protected]2e114e732011-07-22 02:55:0470 return;
71 }
72
73 const size_t kBufSize = 8 * 1024;
[email protected]d06bece2013-04-06 06:48:0674 scoped_ptr<uint8[]> buf(new uint8[kBufSize]);
[email protected]2e114e732011-07-22 02:55:0475 while ((len = fread(buf.get(), 1, kBufSize, crx_file)) > 0)
76 verifier.VerifyUpdate(buf.get(), len);
77
[email protected]802a30e2012-06-26 10:19:4178 if (!verifier.VerifyFinal())
[email protected]2e114e732011-07-22 02:55:0479 return;
[email protected]2e114e732011-07-22 02:55:0480
81 public_key_.swap(key);
[email protected]802a30e2012-06-26 10:19:4182 valid_ = true;
[email protected]2e114e732011-07-22 02:55:0483 }
84
[email protected]802a30e2012-06-26 10:19:4185 bool valid() const { return valid_; }
[email protected]2e114e732011-07-22 02:55:0486
[email protected]f5d27e32014-01-31 06:48:5387 bool is_delta() const { return is_delta_; }
[email protected]e3e696d32013-06-21 20:41:3688
[email protected]2e114e732011-07-22 02:55:0489 const std::vector<uint8>& public_key() const { return public_key_; }
90
91 private:
[email protected]802a30e2012-06-26 10:19:4192 bool valid_;
[email protected]f5d27e32014-01-31 06:48:5393 bool is_delta_;
[email protected]2e114e732011-07-22 02:55:0494 std::vector<uint8> public_key_;
95};
96
[email protected]f5d27e32014-01-31 06:48:5397} // namespace
98
99ComponentUnpacker::ComponentUnpacker(
100 const std::vector<uint8>& pk_hash,
101 const base::FilePath& path,
102 const std::string& fingerprint,
[email protected]f5d27e32014-01-31 06:48:53103 ComponentInstaller* installer,
[email protected]94a481b2014-03-28 19:41:55104 bool in_process,
[email protected]f5d27e32014-01-31 06:48:53105 scoped_refptr<base::SequencedTaskRunner> task_runner)
106 : pk_hash_(pk_hash),
107 path_(path),
108 is_delta_(false),
109 fingerprint_(fingerprint),
[email protected]f5d27e32014-01-31 06:48:53110 installer_(installer),
[email protected]94a481b2014-03-28 19:41:55111 in_process_(in_process),
[email protected]f5d27e32014-01-31 06:48:53112 error_(kNone),
113 extended_error_(0),
[email protected]f5d27e32014-01-31 06:48:53114 task_runner_(task_runner) {
115}
[email protected]871bdf12013-10-26 10:52:06116
[email protected]2e114e732011-07-22 02:55:04117// TODO(cpu): add a specific attribute check to a component json that the
118// extension unpacker will reject, so that a component cannot be installed
119// as an extension.
[email protected]871bdf12013-10-26 10:52:06120scoped_ptr<base::DictionaryValue> ReadManifest(
121 const base::FilePath& unpack_path) {
[email protected]650b2d52013-02-10 03:41:45122 base::FilePath manifest =
123 unpack_path.Append(FILE_PATH_LITERAL("manifest.json"));
[email protected]7567484142013-07-11 17:36:07124 if (!base::PathExists(manifest))
[email protected]871bdf12013-10-26 10:52:06125 return scoped_ptr<base::DictionaryValue>();
[email protected]2e114e732011-07-22 02:55:04126 JSONFileValueSerializer serializer(manifest);
127 std::string error;
128 scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error));
129 if (!root.get())
[email protected]871bdf12013-10-26 10:52:06130 return scoped_ptr<base::DictionaryValue>();
[email protected]2e114e732011-07-22 02:55:04131 if (!root->IsType(base::Value::TYPE_DICTIONARY))
[email protected]871bdf12013-10-26 10:52:06132 return scoped_ptr<base::DictionaryValue>();
133 return scoped_ptr<base::DictionaryValue>(
[email protected]d0c8b8b42014-05-06 05:11:45134 static_cast<base::DictionaryValue*>(root.release())).Pass();
[email protected]2e114e732011-07-22 02:55:04135}
136
[email protected]f5d27e32014-01-31 06:48:53137bool ComponentUnpacker::UnpackInternal() {
138 return Verify() && Unzip() && BeginPatching();
139}
140
[email protected]94a481b2014-03-28 19:41:55141void ComponentUnpacker::Unpack(const Callback& callback) {
[email protected]f5d27e32014-01-31 06:48:53142 callback_ = callback;
143 if (!UnpackInternal())
144 Finish();
145}
146
147bool ComponentUnpacker::Verify() {
[email protected]fb53e652014-04-30 11:27:19148 VLOG(1) << "Verifying component: " << path_.value();
[email protected]f5d27e32014-01-31 06:48:53149 if (pk_hash_.empty() || path_.empty()) {
[email protected]2e114e732011-07-22 02:55:04150 error_ = kInvalidParams;
[email protected]f5d27e32014-01-31 06:48:53151 return false;
[email protected]2e114e732011-07-22 02:55:04152 }
153 // First, validate the CRX header and signature. As of today
154 // this is SHA1 with RSA 1024.
[email protected]0910bae2014-06-10 17:53:21155 base::ScopedFILE file(base::OpenFile(path_, "rb"));
[email protected]2e114e732011-07-22 02:55:04156 if (!file.get()) {
157 error_ = kInvalidFile;
[email protected]f5d27e32014-01-31 06:48:53158 return false;
[email protected]2e114e732011-07-22 02:55:04159 }
160 CRXValidator validator(file.get());
[email protected]0910bae2014-06-10 17:53:21161 file.reset();
[email protected]802a30e2012-06-26 10:19:41162 if (!validator.valid()) {
[email protected]2e114e732011-07-22 02:55:04163 error_ = kInvalidFile;
[email protected]f5d27e32014-01-31 06:48:53164 return false;
[email protected]2e114e732011-07-22 02:55:04165 }
[email protected]f5d27e32014-01-31 06:48:53166 is_delta_ = validator.is_delta();
[email protected]2e114e732011-07-22 02:55:04167
[email protected]f1050432012-02-15 01:35:46168 // File is valid and the digital signature matches. Now make sure
[email protected]2e114e732011-07-22 02:55:04169 // the public key hash matches the expected hash. If they do we fully
170 // trust this CRX.
[email protected]f5d27e32014-01-31 06:48:53171 uint8 hash[32] = {};
[email protected]2e114e732011-07-22 02:55:04172 scoped_ptr<SecureHash> sha256(SecureHash::Create(SecureHash::SHA256));
173 sha256->Update(&(validator.public_key()[0]), validator.public_key().size());
174 sha256->Finish(hash, arraysize(hash));
175
[email protected]f5d27e32014-01-31 06:48:53176 if (!std::equal(pk_hash_.begin(), pk_hash_.end(), hash)) {
[email protected]fb53e652014-04-30 11:27:19177 VLOG(1) << "Hash mismatch: " << path_.value();
[email protected]2e114e732011-07-22 02:55:04178 error_ = kInvalidId;
[email protected]f5d27e32014-01-31 06:48:53179 return false;
[email protected]2e114e732011-07-22 02:55:04180 }
[email protected]fb53e652014-04-30 11:27:19181 VLOG(1) << "Verification successful: " << path_.value();
[email protected]f5d27e32014-01-31 06:48:53182 return true;
183}
184
185bool ComponentUnpacker::Unzip() {
186 base::FilePath& destination = is_delta_ ? unpack_diff_path_ : unpack_path_;
[email protected]fb53e652014-04-30 11:27:19187 VLOG(1) << "Unpacking in: " << destination.value();
[email protected]03d9afc02013-12-03 17:55:52188 if (!base::CreateNewTempDirectory(base::FilePath::StringType(),
[email protected]f5d27e32014-01-31 06:48:53189 &destination)) {
[email protected]fb53e652014-04-30 11:27:19190 VLOG(1) << "Unable to create temporary directory for unpacking.";
[email protected]e3e696d32013-06-21 20:41:36191 error_ = kUnzipPathError;
[email protected]f5d27e32014-01-31 06:48:53192 return false;
193 }
194 if (!zip::Unzip(path_, destination)) {
[email protected]fb53e652014-04-30 11:27:19195 VLOG(1) << "Unzipping failed.";
[email protected]f5d27e32014-01-31 06:48:53196 error_ = kUnzipFailed;
197 return false;
198 }
[email protected]fb53e652014-04-30 11:27:19199 VLOG(1) << "Unpacked successfully";
[email protected]f5d27e32014-01-31 06:48:53200 return true;
201}
202
[email protected]f5d27e32014-01-31 06:48:53203bool ComponentUnpacker::BeginPatching() {
204 if (is_delta_) { // Package is a diff package.
205 // Use a different temp directory for the patch output files.
206 if (!base::CreateNewTempDirectory(base::FilePath::StringType(),
207 &unpack_path_)) {
208 error_ = kUnzipPathError;
209 return false;
210 }
[email protected]94a481b2014-03-28 19:41:55211 patcher_ = new ComponentPatcher(unpack_diff_path_,
212 unpack_path_,
213 installer_,
214 in_process_,
215 task_runner_);
[email protected]f5d27e32014-01-31 06:48:53216 task_runner_->PostTask(
[email protected]94a481b2014-03-28 19:41:55217 FROM_HERE,
218 base::Bind(&ComponentPatcher::Start,
219 patcher_,
220 base::Bind(&ComponentUnpacker::EndPatching,
221 scoped_refptr<ComponentUnpacker>(this))));
[email protected]f5d27e32014-01-31 06:48:53222 } else {
[email protected]94a481b2014-03-28 19:41:55223 task_runner_->PostTask(FROM_HERE,
224 base::Bind(&ComponentUnpacker::EndPatching,
225 scoped_refptr<ComponentUnpacker>(this),
226 kNone,
227 0));
[email protected]f5d27e32014-01-31 06:48:53228 }
229 return true;
230}
231
232void ComponentUnpacker::EndPatching(Error error, int extended_error) {
233 error_ = error;
234 extended_error_ = extended_error;
[email protected]94a481b2014-03-28 19:41:55235 patcher_ = NULL;
[email protected]f5d27e32014-01-31 06:48:53236 if (error_ != kNone) {
237 Finish();
[email protected]e3e696d32013-06-21 20:41:36238 return;
239 }
[email protected]f5d27e32014-01-31 06:48:53240 // Optimization: clean up patch files early, in case disk space is too low to
241 // install otherwise.
242 if (!unpack_diff_path_.empty()) {
243 base::DeleteFile(unpack_diff_path_, true);
244 unpack_diff_path_.clear();
245 }
246 Install();
247 Finish();
248}
249
250void ComponentUnpacker::Install() {
251 // Write the fingerprint to disk.
252 if (static_cast<int>(fingerprint_.size()) !=
[email protected]e5c2a22e2014-03-06 20:42:30253 base::WriteFile(
[email protected]f5d27e32014-01-31 06:48:53254 unpack_path_.Append(FILE_PATH_LITERAL("manifest.fingerprint")),
255 fingerprint_.c_str(),
256 fingerprint_.size())) {
257 error_ = kFingerprintWriteFailed;
258 return;
[email protected]2e114e732011-07-22 02:55:04259 }
260 scoped_ptr<base::DictionaryValue> manifest(ReadManifest(unpack_path_));
261 if (!manifest.get()) {
262 error_ = kBadManifest;
263 return;
264 }
[email protected]f5d27e32014-01-31 06:48:53265 DCHECK(error_ == kNone);
266 if (!installer_->Install(*manifest, unpack_path_)) {
[email protected]2e114e732011-07-22 02:55:04267 error_ = kInstallerError;
268 return;
269 }
[email protected]f5d27e32014-01-31 06:48:53270}
271
272void ComponentUnpacker::Finish() {
273 if (!unpack_diff_path_.empty())
274 base::DeleteFile(unpack_diff_path_, true);
275 if (!unpack_path_.empty())
276 base::DeleteFile(unpack_path_, true);
277 callback_.Run(error_, extended_error_);
278}
279
[email protected]2e114e732011-07-22 02:55:04280ComponentUnpacker::~ComponentUnpacker() {
[email protected]2e114e732011-07-22 02:55:04281}
[email protected]055981f2014-01-17 20:22:32282
283} // namespace component_updater