blob: 1e3e558ab071d20372ff69a819110f4deeed1b7f [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]2e114e732011-07-22 02:55:0412#include "base/memory/scoped_handle.h"
[email protected]3ea1b182013-02-08 22:38:4113#include "base/strings/string_number_conversions.h"
[email protected]e7463412013-06-10 22:53:4614#include "base/strings/stringprintf.h"
[email protected]e3e696d32013-06-21 20:41:3615#include "chrome/browser/component_updater/component_patcher.h"
[email protected]2e114e732011-07-22 02:55:0416#include "chrome/browser/component_updater/component_updater_service.h"
17#include "chrome/common/extensions/extension_constants.h"
[email protected]2e114e732011-07-22 02:55:0418#include "crypto/secure_hash.h"
19#include "crypto/signature_verifier.h"
[email protected]993da5e2013-03-23 21:25:1620#include "extensions/common/crx_file.h"
[email protected]4170d3a2013-05-03 23:02:5721#include "third_party/zlib/google/zip.h"
[email protected]2e114e732011-07-22 02:55:0422
23using crypto::SecureHash;
24
[email protected]2e114e732011-07-22 02:55:0425namespace {
[email protected]e3e696d32013-06-21 20:41:3626
[email protected]2e114e732011-07-22 02:55:0427// This class makes sure that the CRX digital signature is valid
28// and well formed.
29class CRXValidator {
30 public:
[email protected]e3e696d32013-06-21 20:41:3631 explicit CRXValidator(FILE* crx_file) : valid_(false), delta_(false) {
[email protected]bf3d9df2012-07-24 23:20:2732 extensions::CrxFile::Header header;
[email protected]2e114e732011-07-22 02:55:0433 size_t len = fread(&header, 1, sizeof(header), crx_file);
[email protected]802a30e2012-06-26 10:19:4134 if (len < sizeof(header))
[email protected]2e114e732011-07-22 02:55:0435 return;
[email protected]802a30e2012-06-26 10:19:4136
[email protected]bf3d9df2012-07-24 23:20:2737 extensions::CrxFile::Error error;
38 scoped_ptr<extensions::CrxFile> crx(
39 extensions::CrxFile::Parse(header, &error));
[email protected]802a30e2012-06-26 10:19:4140 if (!crx.get())
[email protected]2e114e732011-07-22 02:55:0441 return;
[email protected]e3e696d32013-06-21 20:41:3642 delta_ = extensions::CrxFile::HeaderIsDelta(header);
[email protected]2e114e732011-07-22 02:55:0443
44 std::vector<uint8> key(header.key_size);
45 len = fread(&key[0], sizeof(uint8), header.key_size, crx_file);
[email protected]802a30e2012-06-26 10:19:4146 if (len < header.key_size)
[email protected]2e114e732011-07-22 02:55:0447 return;
[email protected]2e114e732011-07-22 02:55:0448
49 std::vector<uint8> signature(header.signature_size);
50 len = fread(&signature[0], sizeof(uint8), header.signature_size, crx_file);
[email protected]802a30e2012-06-26 10:19:4151 if (len < header.signature_size)
[email protected]2e114e732011-07-22 02:55:0452 return;
[email protected]2e114e732011-07-22 02:55:0453
54 crypto::SignatureVerifier verifier;
55 if (!verifier.VerifyInit(extension_misc::kSignatureAlgorithm,
56 sizeof(extension_misc::kSignatureAlgorithm),
57 &signature[0], signature.size(),
58 &key[0], key.size())) {
59 // Signature verification initialization failed. This is most likely
60 // caused by a public key in the wrong format (should encode algorithm).
[email protected]2e114e732011-07-22 02:55:0461 return;
62 }
63
64 const size_t kBufSize = 8 * 1024;
[email protected]d06bece2013-04-06 06:48:0665 scoped_ptr<uint8[]> buf(new uint8[kBufSize]);
[email protected]2e114e732011-07-22 02:55:0466 while ((len = fread(buf.get(), 1, kBufSize, crx_file)) > 0)
67 verifier.VerifyUpdate(buf.get(), len);
68
[email protected]802a30e2012-06-26 10:19:4169 if (!verifier.VerifyFinal())
[email protected]2e114e732011-07-22 02:55:0470 return;
[email protected]2e114e732011-07-22 02:55:0471
72 public_key_.swap(key);
[email protected]802a30e2012-06-26 10:19:4173 valid_ = true;
[email protected]2e114e732011-07-22 02:55:0474 }
75
[email protected]802a30e2012-06-26 10:19:4176 bool valid() const { return valid_; }
[email protected]2e114e732011-07-22 02:55:0477
[email protected]e3e696d32013-06-21 20:41:3678 bool delta() const { return delta_; }
79
[email protected]2e114e732011-07-22 02:55:0480 const std::vector<uint8>& public_key() const { return public_key_; }
81
82 private:
[email protected]802a30e2012-06-26 10:19:4183 bool valid_;
[email protected]e3e696d32013-06-21 20:41:3684 bool delta_;
[email protected]2e114e732011-07-22 02:55:0485 std::vector<uint8> public_key_;
86};
87
88// Deserialize the CRX manifest. The top level must be a dictionary.
89// TODO(cpu): add a specific attribute check to a component json that the
90// extension unpacker will reject, so that a component cannot be installed
91// as an extension.
[email protected]650b2d52013-02-10 03:41:4592base::DictionaryValue* ReadManifest(const base::FilePath& unpack_path) {
93 base::FilePath manifest =
94 unpack_path.Append(FILE_PATH_LITERAL("manifest.json"));
[email protected]7567484142013-07-11 17:36:0795 if (!base::PathExists(manifest))
[email protected]2e114e732011-07-22 02:55:0496 return NULL;
97 JSONFileValueSerializer serializer(manifest);
98 std::string error;
99 scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error));
100 if (!root.get())
101 return NULL;
102 if (!root->IsType(base::Value::TYPE_DICTIONARY))
103 return NULL;
104 return static_cast<base::DictionaryValue*>(root.release());
105}
106
[email protected]e3e696d32013-06-21 20:41:36107// Deletes a path if it exists, and then creates a directory there.
108// Returns true if and only if these operations were successful.
109// This method doesn't take any special steps to prevent files from
110// being inserted into the target directory by another process or thread.
111bool MakeEmptyDirectory(const base::FilePath& path) {
[email protected]7567484142013-07-11 17:36:07112 if (base::PathExists(path)) {
[email protected]918efbf2013-07-01 19:41:02113 if (!base::Delete(path, true))
[email protected]e3e696d32013-06-21 20:41:36114 return false;
115 }
116 if (!file_util::CreateDirectory(path))
117 return false;
118 return true;
119}
120
[email protected]2e114e732011-07-22 02:55:04121} // namespace.
122
123ComponentUnpacker::ComponentUnpacker(const std::vector<uint8>& pk_hash,
[email protected]650b2d52013-02-10 03:41:45124 const base::FilePath& path,
[email protected]e3e696d32013-06-21 20:41:36125 const std::string& fingerprint,
126 ComponentPatcher* patcher,
[email protected]2e114e732011-07-22 02:55:04127 ComponentInstaller* installer)
[email protected]e3e696d32013-06-21 20:41:36128 : error_(kNone),
129 extended_error_(0) {
[email protected]2e114e732011-07-22 02:55:04130 if (pk_hash.empty() || path.empty()) {
131 error_ = kInvalidParams;
132 return;
133 }
134 // First, validate the CRX header and signature. As of today
135 // this is SHA1 with RSA 1024.
136 ScopedStdioHandle file(file_util::OpenFile(path, "rb"));
137 if (!file.get()) {
138 error_ = kInvalidFile;
139 return;
140 }
141 CRXValidator validator(file.get());
[email protected]802a30e2012-06-26 10:19:41142 if (!validator.valid()) {
[email protected]2e114e732011-07-22 02:55:04143 error_ = kInvalidFile;
144 return;
145 }
146 file.Close();
147
[email protected]f1050432012-02-15 01:35:46148 // File is valid and the digital signature matches. Now make sure
[email protected]2e114e732011-07-22 02:55:04149 // the public key hash matches the expected hash. If they do we fully
150 // trust this CRX.
151 uint8 hash[32];
152 scoped_ptr<SecureHash> sha256(SecureHash::Create(SecureHash::SHA256));
153 sha256->Update(&(validator.public_key()[0]), validator.public_key().size());
154 sha256->Finish(hash, arraysize(hash));
155
156 if (!std::equal(pk_hash.begin(), pk_hash.end(), hash)) {
157 error_ = kInvalidId;
158 return;
159 }
160 // We want the temporary directory to be unique and yet predictable, so
[email protected]e3e696d32013-06-21 20:41:36161 // we can easily find the package in an end user machine.
162 const std::string dir(
[email protected]7d3cbc92013-03-18 22:33:04163 base::StringPrintf("CRX_%s", base::HexEncode(hash, 6).c_str()));
[email protected]2e114e732011-07-22 02:55:04164 unpack_path_ = path.DirName().AppendASCII(dir.c_str());
[email protected]e3e696d32013-06-21 20:41:36165 if (!MakeEmptyDirectory(unpack_path_)) {
166 unpack_path_.clear();
167 error_ = kUnzipPathError;
168 return;
169 }
170 if (validator.delta()) { // Package is a diff package.
171 // We want a different temp directory for the delta files; we'll put the
172 // patch output into unpack_path_.
173 std::string dir(
174 base::StringPrintf("CRX_%s_diff", base::HexEncode(hash, 6).c_str()));
175 base::FilePath unpack_diff_path = path.DirName().AppendASCII(dir.c_str());
176 if (!MakeEmptyDirectory(unpack_diff_path)) {
177 error_ = kUnzipPathError;
[email protected]86550a42013-06-21 15:20:49178 return;
179 }
[email protected]e3e696d32013-06-21 20:41:36180 if (!zip::Unzip(path, unpack_diff_path)) {
181 error_ = kUnzipFailed;
182 return;
183 }
184 ComponentUnpacker::Error result = DifferentialUpdatePatch(unpack_diff_path,
185 unpack_path_,
186 patcher,
187 installer,
188 &extended_error_);
[email protected]918efbf2013-07-01 19:41:02189 base::Delete(unpack_diff_path, true);
[email protected]e3e696d32013-06-21 20:41:36190 unpack_diff_path.clear();
191 error_ = result;
192 if (error_ != kNone) {
193 return;
194 }
195 } else {
196 // Package is a normal update/install; unzip it into unpack_path_ directly.
197 if (!zip::Unzip(path, unpack_path_)) {
198 error_ = kUnzipFailed;
199 return;
200 }
[email protected]2e114e732011-07-22 02:55:04201 }
202 scoped_ptr<base::DictionaryValue> manifest(ReadManifest(unpack_path_));
203 if (!manifest.get()) {
204 error_ = kBadManifest;
205 return;
206 }
[email protected]e3e696d32013-06-21 20:41:36207 // Write the fingerprint to disk.
208 if (static_cast<int>(fingerprint.size()) !=
209 file_util::WriteFile(
210 unpack_path_.Append(FILE_PATH_LITERAL("manifest.fingerprint")),
211 fingerprint.c_str(),
212 fingerprint.size())) {
213 error_ = kFingerprintWriteFailed;
214 return;
215 }
[email protected]14ca8872013-05-02 01:51:06216 if (!installer->Install(*manifest, unpack_path_)) {
[email protected]2e114e732011-07-22 02:55:04217 error_ = kInstallerError;
218 return;
219 }
[email protected]f1050432012-02-15 01:35:46220 // Installation successful. The directory is not our concern now.
[email protected]2e114e732011-07-22 02:55:04221 unpack_path_.clear();
222}
223
224ComponentUnpacker::~ComponentUnpacker() {
[email protected]e3e696d32013-06-21 20:41:36225 if (!unpack_path_.empty())
[email protected]918efbf2013-07-01 19:41:02226 base::Delete(unpack_path_, true);
[email protected]2e114e732011-07-22 02:55:04227}