blob: 48c584cd42f7572f096d581acf706bc083979553 [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]ffbec692012-02-26 20:26:4213#include "base/json/json_file_value_serializer.h"
[email protected]9e1685a2014-02-13 15:08:3414#include "base/location.h"
[email protected]871bdf12013-10-26 10:52:0615#include "base/logging.h"
[email protected]2e114e732011-07-22 02:55:0416#include "base/memory/scoped_handle.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),
64 &signature[0], signature.size(),
65 &key[0], key.size())) {
66 // Signature verification initialization failed. This is most likely
67 // caused by a public key in the wrong format (should encode algorithm).
[email protected]2e114e732011-07-22 02:55:0468 return;
69 }
70
71 const size_t kBufSize = 8 * 1024;
[email protected]d06bece2013-04-06 06:48:0672 scoped_ptr<uint8[]> buf(new uint8[kBufSize]);
[email protected]2e114e732011-07-22 02:55:0473 while ((len = fread(buf.get(), 1, kBufSize, crx_file)) > 0)
74 verifier.VerifyUpdate(buf.get(), len);
75
[email protected]802a30e2012-06-26 10:19:4176 if (!verifier.VerifyFinal())
[email protected]2e114e732011-07-22 02:55:0477 return;
[email protected]2e114e732011-07-22 02:55:0478
79 public_key_.swap(key);
[email protected]802a30e2012-06-26 10:19:4180 valid_ = true;
[email protected]2e114e732011-07-22 02:55:0481 }
82
[email protected]802a30e2012-06-26 10:19:4183 bool valid() const { return valid_; }
[email protected]2e114e732011-07-22 02:55:0484
[email protected]f5d27e32014-01-31 06:48:5385 bool is_delta() const { return is_delta_; }
[email protected]e3e696d32013-06-21 20:41:3686
[email protected]2e114e732011-07-22 02:55:0487 const std::vector<uint8>& public_key() const { return public_key_; }
88
89 private:
[email protected]802a30e2012-06-26 10:19:4190 bool valid_;
[email protected]f5d27e32014-01-31 06:48:5391 bool is_delta_;
[email protected]2e114e732011-07-22 02:55:0492 std::vector<uint8> public_key_;
93};
94
[email protected]f5d27e32014-01-31 06:48:5395} // namespace
96
97ComponentUnpacker::ComponentUnpacker(
98 const std::vector<uint8>& pk_hash,
99 const base::FilePath& path,
100 const std::string& fingerprint,
[email protected]f5d27e32014-01-31 06:48:53101 ComponentInstaller* installer,
[email protected]94a481b2014-03-28 19:41:55102 bool in_process,
[email protected]f5d27e32014-01-31 06:48:53103 scoped_refptr<base::SequencedTaskRunner> task_runner)
104 : pk_hash_(pk_hash),
105 path_(path),
106 is_delta_(false),
107 fingerprint_(fingerprint),
[email protected]f5d27e32014-01-31 06:48:53108 installer_(installer),
[email protected]94a481b2014-03-28 19:41:55109 in_process_(in_process),
[email protected]f5d27e32014-01-31 06:48:53110 error_(kNone),
111 extended_error_(0),
[email protected]f5d27e32014-01-31 06:48:53112 task_runner_(task_runner) {
113}
[email protected]871bdf12013-10-26 10:52:06114
[email protected]2e114e732011-07-22 02:55:04115// TODO(cpu): add a specific attribute check to a component json that the
116// extension unpacker will reject, so that a component cannot be installed
117// as an extension.
[email protected]871bdf12013-10-26 10:52:06118scoped_ptr<base::DictionaryValue> ReadManifest(
119 const base::FilePath& unpack_path) {
[email protected]650b2d52013-02-10 03:41:45120 base::FilePath manifest =
121 unpack_path.Append(FILE_PATH_LITERAL("manifest.json"));
[email protected]7567484142013-07-11 17:36:07122 if (!base::PathExists(manifest))
[email protected]871bdf12013-10-26 10:52:06123 return scoped_ptr<base::DictionaryValue>();
[email protected]2e114e732011-07-22 02:55:04124 JSONFileValueSerializer serializer(manifest);
125 std::string error;
126 scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error));
127 if (!root.get())
[email protected]871bdf12013-10-26 10:52:06128 return scoped_ptr<base::DictionaryValue>();
[email protected]2e114e732011-07-22 02:55:04129 if (!root->IsType(base::Value::TYPE_DICTIONARY))
[email protected]871bdf12013-10-26 10:52:06130 return scoped_ptr<base::DictionaryValue>();
131 return scoped_ptr<base::DictionaryValue>(
132 static_cast<base::DictionaryValue*>(root.release())).Pass();
[email protected]2e114e732011-07-22 02:55:04133}
134
[email protected]f5d27e32014-01-31 06:48:53135bool ComponentUnpacker::UnpackInternal() {
136 return Verify() && Unzip() && BeginPatching();
137}
138
[email protected]94a481b2014-03-28 19:41:55139void ComponentUnpacker::Unpack(const Callback& callback) {
[email protected]f5d27e32014-01-31 06:48:53140 callback_ = callback;
141 if (!UnpackInternal())
142 Finish();
143}
144
145bool ComponentUnpacker::Verify() {
[email protected]fb53e652014-04-30 11:27:19146 VLOG(1) << "Verifying component: " << path_.value();
[email protected]f5d27e32014-01-31 06:48:53147 if (pk_hash_.empty() || path_.empty()) {
[email protected]2e114e732011-07-22 02:55:04148 error_ = kInvalidParams;
[email protected]f5d27e32014-01-31 06:48:53149 return false;
[email protected]2e114e732011-07-22 02:55:04150 }
151 // First, validate the CRX header and signature. As of today
152 // this is SHA1 with RSA 1024.
[email protected]f5d27e32014-01-31 06:48:53153 ScopedStdioHandle file(base::OpenFile(path_, "rb"));
[email protected]2e114e732011-07-22 02:55:04154 if (!file.get()) {
155 error_ = kInvalidFile;
[email protected]f5d27e32014-01-31 06:48:53156 return false;
[email protected]2e114e732011-07-22 02:55:04157 }
158 CRXValidator validator(file.get());
[email protected]f5d27e32014-01-31 06:48:53159 file.Close();
[email protected]802a30e2012-06-26 10:19:41160 if (!validator.valid()) {
[email protected]2e114e732011-07-22 02:55:04161 error_ = kInvalidFile;
[email protected]f5d27e32014-01-31 06:48:53162 return false;
[email protected]2e114e732011-07-22 02:55:04163 }
[email protected]f5d27e32014-01-31 06:48:53164 is_delta_ = validator.is_delta();
[email protected]2e114e732011-07-22 02:55:04165
[email protected]f1050432012-02-15 01:35:46166 // File is valid and the digital signature matches. Now make sure
[email protected]2e114e732011-07-22 02:55:04167 // the public key hash matches the expected hash. If they do we fully
168 // trust this CRX.
[email protected]f5d27e32014-01-31 06:48:53169 uint8 hash[32] = {};
[email protected]2e114e732011-07-22 02:55:04170 scoped_ptr<SecureHash> sha256(SecureHash::Create(SecureHash::SHA256));
171 sha256->Update(&(validator.public_key()[0]), validator.public_key().size());
172 sha256->Finish(hash, arraysize(hash));
173
[email protected]f5d27e32014-01-31 06:48:53174 if (!std::equal(pk_hash_.begin(), pk_hash_.end(), hash)) {
[email protected]fb53e652014-04-30 11:27:19175 VLOG(1) << "Hash mismatch: " << path_.value();
[email protected]2e114e732011-07-22 02:55:04176 error_ = kInvalidId;
[email protected]f5d27e32014-01-31 06:48:53177 return false;
[email protected]2e114e732011-07-22 02:55:04178 }
[email protected]fb53e652014-04-30 11:27:19179 VLOG(1) << "Verification successful: " << path_.value();
[email protected]f5d27e32014-01-31 06:48:53180 return true;
181}
182
183bool ComponentUnpacker::Unzip() {
184 base::FilePath& destination = is_delta_ ? unpack_diff_path_ : unpack_path_;
[email protected]fb53e652014-04-30 11:27:19185 VLOG(1) << "Unpacking in: " << destination.value();
[email protected]03d9afc02013-12-03 17:55:52186 if (!base::CreateNewTempDirectory(base::FilePath::StringType(),
[email protected]f5d27e32014-01-31 06:48:53187 &destination)) {
[email protected]fb53e652014-04-30 11:27:19188 VLOG(1) << "Unable to create temporary directory for unpacking.";
[email protected]e3e696d32013-06-21 20:41:36189 error_ = kUnzipPathError;
[email protected]f5d27e32014-01-31 06:48:53190 return false;
191 }
192 if (!zip::Unzip(path_, destination)) {
[email protected]fb53e652014-04-30 11:27:19193 VLOG(1) << "Unzipping failed.";
[email protected]f5d27e32014-01-31 06:48:53194 error_ = kUnzipFailed;
195 return false;
196 }
[email protected]fb53e652014-04-30 11:27:19197 VLOG(1) << "Unpacked successfully";
[email protected]f5d27e32014-01-31 06:48:53198 return true;
199}
200
201
202bool ComponentUnpacker::BeginPatching() {
203 if (is_delta_) { // Package is a diff package.
204 // Use a different temp directory for the patch output files.
205 if (!base::CreateNewTempDirectory(base::FilePath::StringType(),
206 &unpack_path_)) {
207 error_ = kUnzipPathError;
208 return false;
209 }
[email protected]94a481b2014-03-28 19:41:55210 patcher_ = new ComponentPatcher(unpack_diff_path_,
211 unpack_path_,
212 installer_,
213 in_process_,
214 task_runner_);
[email protected]f5d27e32014-01-31 06:48:53215 task_runner_->PostTask(
[email protected]94a481b2014-03-28 19:41:55216 FROM_HERE,
217 base::Bind(&ComponentPatcher::Start,
218 patcher_,
219 base::Bind(&ComponentUnpacker::EndPatching,
220 scoped_refptr<ComponentUnpacker>(this))));
[email protected]f5d27e32014-01-31 06:48:53221 } else {
[email protected]94a481b2014-03-28 19:41:55222 task_runner_->PostTask(FROM_HERE,
223 base::Bind(&ComponentUnpacker::EndPatching,
224 scoped_refptr<ComponentUnpacker>(this),
225 kNone,
226 0));
[email protected]f5d27e32014-01-31 06:48:53227 }
228 return true;
229}
230
231void ComponentUnpacker::EndPatching(Error error, int extended_error) {
232 error_ = error;
233 extended_error_ = extended_error;
[email protected]94a481b2014-03-28 19:41:55234 patcher_ = NULL;
[email protected]f5d27e32014-01-31 06:48:53235 if (error_ != kNone) {
236 Finish();
[email protected]e3e696d32013-06-21 20:41:36237 return;
238 }
[email protected]f5d27e32014-01-31 06:48:53239 // Optimization: clean up patch files early, in case disk space is too low to
240 // install otherwise.
241 if (!unpack_diff_path_.empty()) {
242 base::DeleteFile(unpack_diff_path_, true);
243 unpack_diff_path_.clear();
244 }
245 Install();
246 Finish();
247}
248
249void ComponentUnpacker::Install() {
250 // Write the fingerprint to disk.
251 if (static_cast<int>(fingerprint_.size()) !=
[email protected]e5c2a22e2014-03-06 20:42:30252 base::WriteFile(
[email protected]f5d27e32014-01-31 06:48:53253 unpack_path_.Append(FILE_PATH_LITERAL("manifest.fingerprint")),
254 fingerprint_.c_str(),
255 fingerprint_.size())) {
256 error_ = kFingerprintWriteFailed;
257 return;
[email protected]2e114e732011-07-22 02:55:04258 }
259 scoped_ptr<base::DictionaryValue> manifest(ReadManifest(unpack_path_));
260 if (!manifest.get()) {
261 error_ = kBadManifest;
262 return;
263 }
[email protected]f5d27e32014-01-31 06:48:53264 DCHECK(error_ == kNone);
265 if (!installer_->Install(*manifest, unpack_path_)) {
[email protected]2e114e732011-07-22 02:55:04266 error_ = kInstallerError;
267 return;
268 }
[email protected]f5d27e32014-01-31 06:48:53269}
270
271void ComponentUnpacker::Finish() {
272 if (!unpack_diff_path_.empty())
273 base::DeleteFile(unpack_diff_path_, true);
274 if (!unpack_path_.empty())
275 base::DeleteFile(unpack_path_, true);
276 callback_.Run(error_, extended_error_);
277}
278
[email protected]2e114e732011-07-22 02:55:04279ComponentUnpacker::~ComponentUnpacker() {
[email protected]2e114e732011-07-22 02:55:04280}
[email protected]055981f2014-01-17 20:22:32281
282} // namespace component_updater