1 // Copyright (c) 2012 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.
5 #include "chrome/browser/component_updater/component_unpacker.h"
10 #include "base/file_util.h"
11 #include "base/json/json_file_value_serializer.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_handle.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/values.h"
17 #include "chrome/browser/component_updater/component_patcher.h"
18 #include "chrome/browser/component_updater/component_updater_service.h"
19 #include "chrome/common/extensions/extension_constants.h"
20 #include "crypto/secure_hash.h"
21 #include "crypto/signature_verifier.h"
22 #include "extensions/common/crx_file.h"
23 #include "third_party/zlib/google/zip.h"
25 using crypto::SecureHash;
29 // This class makes sure that the CRX digital signature is valid
33 explicit CRXValidator(FILE* crx_file) : valid_(false), delta_(false) {
34 extensions::CrxFile::Header header;
35 size_t len = fread(&header, 1, sizeof(header), crx_file);
36 if (len < sizeof(header))
39 extensions::CrxFile::Error error;
40 scoped_ptr<extensions::CrxFile> crx(
41 extensions::CrxFile::Parse(header, &error));
44 delta_ = extensions::CrxFile::HeaderIsDelta(header);
46 std::vector<uint8> key(header.key_size);
47 len = fread(&key[0], sizeof(uint8), header.key_size, crx_file);
48 if (len < header.key_size)
51 std::vector<uint8> signature(header.signature_size);
52 len = fread(&signature[0], sizeof(uint8), header.signature_size, crx_file);
53 if (len < header.signature_size)
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).
66 const size_t kBufSize = 8 * 1024;
67 scoped_ptr<uint8[]> buf(new uint8[kBufSize]);
68 while ((len = fread(buf.get(), 1, kBufSize, crx_file)) > 0)
69 verifier.VerifyUpdate(buf.get(), len);
71 if (!verifier.VerifyFinal())
74 public_key_.swap(key);
78 bool valid() const { return valid_; }
80 bool delta() const { return delta_; }
82 const std::vector<uint8>& public_key() const { return public_key_; }
87 std::vector<uint8> public_key_;
92 // 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
95 scoped_ptr<base::DictionaryValue> ReadManifest(
96 const base::FilePath& unpack_path) {
97 base::FilePath manifest =
98 unpack_path.Append(FILE_PATH_LITERAL("manifest.json"));
99 if (!base::PathExists(manifest))
100 return scoped_ptr<base::DictionaryValue>();
101 JSONFileValueSerializer serializer(manifest);
103 scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error));
105 return scoped_ptr<base::DictionaryValue>();
106 if (!root->IsType(base::Value::TYPE_DICTIONARY))
107 return scoped_ptr<base::DictionaryValue>();
108 return scoped_ptr<base::DictionaryValue>(
109 static_cast<base::DictionaryValue*>(root.release())).Pass();
112 ComponentUnpacker::ComponentUnpacker(const std::vector<uint8>& pk_hash,
113 const base::FilePath& path,
114 const std::string& fingerprint,
115 ComponentPatcher* patcher,
116 ComponentInstaller* installer)
119 if (pk_hash.empty() || path.empty()) {
120 error_ = kInvalidParams;
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"));
127 error_ = kInvalidFile;
130 CRXValidator validator(file.get());
131 if (!validator.valid()) {
132 error_ = kInvalidFile;
137 // File is valid and the digital signature matches. Now make sure
138 // the public key hash matches the expected hash. If they do we fully
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));
145 if (!std::equal(pk_hash.begin(), pk_hash.end(), hash)) {
149 if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL(""),
151 error_ = kUnzipPathError;
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_.
157 base::FilePath unpack_diff_path;
158 if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL(""),
159 &unpack_diff_path)) {
160 error_ = kUnzipPathError;
163 if (!zip::Unzip(path, unpack_diff_path)) {
164 error_ = kUnzipFailed;
167 ComponentUnpacker::Error result = DifferentialUpdatePatch(unpack_diff_path,
172 base::DeleteFile(unpack_diff_path, true);
173 unpack_diff_path.clear();
175 if (error_ != kNone) {
179 // Package is a normal update/install; unzip it into unpack_path_ directly.
180 if (!zip::Unzip(path, unpack_path_)) {
181 error_ = kUnzipFailed;
185 scoped_ptr<base::DictionaryValue> manifest(ReadManifest(unpack_path_));
186 if (!manifest.get()) {
187 error_ = kBadManifest;
190 // 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")),
195 fingerprint.size())) {
196 error_ = kFingerprintWriteFailed;
199 if (!installer->Install(*manifest, unpack_path_)) {
200 error_ = kInstallerError;
203 // Installation successful. The directory is not our concern now.
204 unpack_path_.clear();
207 ComponentUnpacker::~ComponentUnpacker() {
208 if (!unpack_path_.empty())
209 base::DeleteFile(unpack_path_, true);