blob: 5541a9b5d269281f871dbd99743aa75d7fe5de60 [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
10#include "base/file_util.h"
[email protected]ffbec692012-02-26 20:26:4211#include "base/json/json_file_value_serializer.h"
[email protected]871bdf12013-10-26 10:52:0612#include "base/logging.h"
[email protected]2e114e732011-07-22 02:55:0413#include "base/memory/scoped_handle.h"
[email protected]3ea1b182013-02-08 22:38:4114#include "base/strings/string_number_conversions.h"
[email protected]e7463412013-06-10 22:53:4615#include "base/strings/stringprintf.h"
[email protected]871bdf12013-10-26 10:52:0616#include "base/values.h"
[email protected]e3e696d32013-06-21 20:41:3617#include "chrome/browser/component_updater/component_patcher.h"
[email protected]2e114e732011-07-22 02:55:0418#include "chrome/browser/component_updater/component_updater_service.h"
19#include "chrome/common/extensions/extension_constants.h"
[email protected]2e114e732011-07-22 02:55:0420#include "crypto/secure_hash.h"
21#include "crypto/signature_verifier.h"
[email protected]993da5e2013-03-23 21:25:1622#include "extensions/common/crx_file.h"
[email protected]4170d3a2013-05-03 23:02:5723#include "third_party/zlib/google/zip.h"
[email protected]2e114e732011-07-22 02:55:0424
25using crypto::SecureHash;
26
[email protected]2e114e732011-07-22 02:55:0427namespace {
[email protected]e3e696d32013-06-21 20:41:3628
[email protected]2e114e732011-07-22 02:55:0429// This class makes sure that the CRX digital signature is valid
30// and well formed.
31class CRXValidator {
32 public:
[email protected]e3e696d32013-06-21 20:41:3633 explicit CRXValidator(FILE* crx_file) : valid_(false), delta_(false) {
[email protected]bf3d9df2012-07-24 23:20:2734 extensions::CrxFile::Header header;
[email protected]2e114e732011-07-22 02:55:0435 size_t len = fread(&header, 1, sizeof(header), crx_file);
[email protected]802a30e2012-06-26 10:19:4136 if (len < sizeof(header))
[email protected]2e114e732011-07-22 02:55:0437 return;
[email protected]802a30e2012-06-26 10:19:4138
[email protected]bf3d9df2012-07-24 23:20:2739 extensions::CrxFile::Error error;
40 scoped_ptr<extensions::CrxFile> crx(
41 extensions::CrxFile::Parse(header, &error));
[email protected]802a30e2012-06-26 10:19:4142 if (!crx.get())
[email protected]2e114e732011-07-22 02:55:0443 return;
[email protected]e3e696d32013-06-21 20:41:3644 delta_ = extensions::CrxFile::HeaderIsDelta(header);
[email protected]2e114e732011-07-22 02:55:0445
46 std::vector<uint8> key(header.key_size);
47 len = fread(&key[0], sizeof(uint8), header.key_size, crx_file);
[email protected]802a30e2012-06-26 10:19:4148 if (len < header.key_size)
[email protected]2e114e732011-07-22 02:55:0449 return;
[email protected]2e114e732011-07-22 02:55:0450
51 std::vector<uint8> signature(header.signature_size);
52 len = fread(&signature[0], sizeof(uint8), header.signature_size, crx_file);
[email protected]802a30e2012-06-26 10:19:4153 if (len < header.signature_size)
[email protected]2e114e732011-07-22 02:55:0454 return;
[email protected]2e114e732011-07-22 02:55:0455
56 crypto::SignatureVerifier verifier;
57 if (!verifier.VerifyInit(extension_misc::kSignatureAlgorithm,
58 sizeof(extension_misc::kSignatureAlgorithm),
59 &signature[0], signature.size(),
60 &key[0], key.size())) {
61 // Signature verification initialization failed. This is most likely
62 // caused by a public key in the wrong format (should encode algorithm).
[email protected]2e114e732011-07-22 02:55:0463 return;
64 }
65
66 const size_t kBufSize = 8 * 1024;
[email protected]d06bece2013-04-06 06:48:0667 scoped_ptr<uint8[]> buf(new uint8[kBufSize]);
[email protected]2e114e732011-07-22 02:55:0468 while ((len = fread(buf.get(), 1, kBufSize, crx_file)) > 0)
69 verifier.VerifyUpdate(buf.get(), len);
70
[email protected]802a30e2012-06-26 10:19:4171 if (!verifier.VerifyFinal())
[email protected]2e114e732011-07-22 02:55:0472 return;
[email protected]2e114e732011-07-22 02:55:0473
74 public_key_.swap(key);
[email protected]802a30e2012-06-26 10:19:4175 valid_ = true;
[email protected]2e114e732011-07-22 02:55:0476 }
77
[email protected]802a30e2012-06-26 10:19:4178 bool valid() const { return valid_; }
[email protected]2e114e732011-07-22 02:55:0479
[email protected]e3e696d32013-06-21 20:41:3680 bool delta() const { return delta_; }
81
[email protected]2e114e732011-07-22 02:55:0482 const std::vector<uint8>& public_key() const { return public_key_; }
83
84 private:
[email protected]802a30e2012-06-26 10:19:4185 bool valid_;
[email protected]e3e696d32013-06-21 20:41:3686 bool delta_;
[email protected]2e114e732011-07-22 02:55:0487 std::vector<uint8> public_key_;
88};
89
[email protected]871bdf12013-10-26 10:52:0690} // namespace.
91
[email protected]2e114e732011-07-22 02:55:0492// TODO(cpu): add a specific attribute check to a component json that the
93// extension unpacker will reject, so that a component cannot be installed
94// as an extension.
[email protected]871bdf12013-10-26 10:52:0695scoped_ptr<base::DictionaryValue> ReadManifest(
96 const base::FilePath& unpack_path) {
[email protected]650b2d52013-02-10 03:41:4597 base::FilePath manifest =
98 unpack_path.Append(FILE_PATH_LITERAL("manifest.json"));
[email protected]7567484142013-07-11 17:36:0799 if (!base::PathExists(manifest))
[email protected]871bdf12013-10-26 10:52:06100 return scoped_ptr<base::DictionaryValue>();
[email protected]2e114e732011-07-22 02:55:04101 JSONFileValueSerializer serializer(manifest);
102 std::string error;
103 scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error));
104 if (!root.get())
[email protected]871bdf12013-10-26 10:52:06105 return scoped_ptr<base::DictionaryValue>();
[email protected]2e114e732011-07-22 02:55:04106 if (!root->IsType(base::Value::TYPE_DICTIONARY))
[email protected]871bdf12013-10-26 10:52:06107 return scoped_ptr<base::DictionaryValue>();
108 return scoped_ptr<base::DictionaryValue>(
109 static_cast<base::DictionaryValue*>(root.release())).Pass();
[email protected]2e114e732011-07-22 02:55:04110}
111
[email protected]2e114e732011-07-22 02:55:04112ComponentUnpacker::ComponentUnpacker(const std::vector<uint8>& pk_hash,
[email protected]650b2d52013-02-10 03:41:45113 const base::FilePath& path,
[email protected]e3e696d32013-06-21 20:41:36114 const std::string& fingerprint,
115 ComponentPatcher* patcher,
[email protected]2e114e732011-07-22 02:55:04116 ComponentInstaller* installer)
[email protected]e3e696d32013-06-21 20:41:36117 : error_(kNone),
118 extended_error_(0) {
[email protected]2e114e732011-07-22 02:55:04119 if (pk_hash.empty() || path.empty()) {
120 error_ = kInvalidParams;
121 return;
122 }
123 // First, validate the CRX header and signature. As of today
124 // this is SHA1 with RSA 1024.
125 ScopedStdioHandle file(file_util::OpenFile(path, "rb"));
126 if (!file.get()) {
127 error_ = kInvalidFile;
128 return;
129 }
130 CRXValidator validator(file.get());
[email protected]802a30e2012-06-26 10:19:41131 if (!validator.valid()) {
[email protected]2e114e732011-07-22 02:55:04132 error_ = kInvalidFile;
133 return;
134 }
135 file.Close();
136
[email protected]f1050432012-02-15 01:35:46137 // File is valid and the digital signature matches. Now make sure
[email protected]2e114e732011-07-22 02:55:04138 // the public key hash matches the expected hash. If they do we fully
139 // trust this CRX.
140 uint8 hash[32];
141 scoped_ptr<SecureHash> sha256(SecureHash::Create(SecureHash::SHA256));
142 sha256->Update(&(validator.public_key()[0]), validator.public_key().size());
143 sha256->Finish(hash, arraysize(hash));
144
145 if (!std::equal(pk_hash.begin(), pk_hash.end(), hash)) {
146 error_ = kInvalidId;
147 return;
148 }
[email protected]02b090bf2013-08-02 00:56:36149 if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL(""),
150 &unpack_path_)) {
[email protected]e3e696d32013-06-21 20:41:36151 error_ = kUnzipPathError;
152 return;
153 }
154 if (validator.delta()) { // Package is a diff package.
155 // We want a different temp directory for the delta files; we'll put the
156 // patch output into unpack_path_.
[email protected]02b090bf2013-08-02 00:56:36157 base::FilePath unpack_diff_path;
158 if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL(""),
159 &unpack_diff_path)) {
[email protected]e3e696d32013-06-21 20:41:36160 error_ = kUnzipPathError;
[email protected]86550a42013-06-21 15:20:49161 return;
162 }
[email protected]e3e696d32013-06-21 20:41:36163 if (!zip::Unzip(path, unpack_diff_path)) {
164 error_ = kUnzipFailed;
165 return;
166 }
167 ComponentUnpacker::Error result = DifferentialUpdatePatch(unpack_diff_path,
168 unpack_path_,
169 patcher,
170 installer,
171 &extended_error_);
[email protected]dd3aa792013-07-16 19:10:23172 base::DeleteFile(unpack_diff_path, true);
[email protected]e3e696d32013-06-21 20:41:36173 unpack_diff_path.clear();
174 error_ = result;
175 if (error_ != kNone) {
176 return;
177 }
178 } else {
179 // Package is a normal update/install; unzip it into unpack_path_ directly.
180 if (!zip::Unzip(path, unpack_path_)) {
181 error_ = kUnzipFailed;
182 return;
183 }
[email protected]2e114e732011-07-22 02:55:04184 }
185 scoped_ptr<base::DictionaryValue> manifest(ReadManifest(unpack_path_));
186 if (!manifest.get()) {
187 error_ = kBadManifest;
188 return;
189 }
[email protected]e3e696d32013-06-21 20:41:36190 // Write the fingerprint to disk.
191 if (static_cast<int>(fingerprint.size()) !=
192 file_util::WriteFile(
193 unpack_path_.Append(FILE_PATH_LITERAL("manifest.fingerprint")),
194 fingerprint.c_str(),
195 fingerprint.size())) {
196 error_ = kFingerprintWriteFailed;
197 return;
198 }
[email protected]14ca8872013-05-02 01:51:06199 if (!installer->Install(*manifest, unpack_path_)) {
[email protected]2e114e732011-07-22 02:55:04200 error_ = kInstallerError;
201 return;
202 }
[email protected]f1050432012-02-15 01:35:46203 // Installation successful. The directory is not our concern now.
[email protected]2e114e732011-07-22 02:55:04204 unpack_path_.clear();
205}
206
207ComponentUnpacker::~ComponentUnpacker() {
[email protected]e3e696d32013-06-21 20:41:36208 if (!unpack_path_.empty())
[email protected]dd3aa792013-07-16 19:10:23209 base::DeleteFile(unpack_path_, true);
[email protected]2e114e732011-07-22 02:55:04210}