Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / components / component_updater / component_unpacker.cc
1 // Copyright 2014 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.
4
5 #include "components/component_updater/component_unpacker.h"
6
7 #include <stdint.h>
8 #include <string>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/files/scoped_file.h"
15 #include "base/json/json_file_value_serializer.h"
16 #include "base/location.h"
17 #include "base/logging.h"
18 #include "base/numerics/safe_conversions.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/values.h"
22 #include "components/component_updater/component_patcher.h"
23 #include "components/component_updater/component_patcher_operation.h"
24 #include "components/component_updater/component_updater_service.h"
25 #include "components/crx_file/constants.h"
26 #include "components/crx_file/crx_file.h"
27 #include "crypto/secure_hash.h"
28 #include "crypto/signature_verifier.h"
29 #include "third_party/zlib/google/zip.h"
30
31 using crypto::SecureHash;
32
33 namespace component_updater {
34
35 namespace {
36
37 // This class makes sure that the CRX digital signature is valid
38 // and well formed.
39 class CRXValidator {
40  public:
41   explicit CRXValidator(FILE* crx_file) : valid_(false), is_delta_(false) {
42     crx_file::CrxFile::Header header;
43     size_t len = fread(&header, 1, sizeof(header), crx_file);
44     if (len < sizeof(header))
45       return;
46
47     crx_file::CrxFile::Error error;
48     scoped_ptr<crx_file::CrxFile> crx(
49         crx_file::CrxFile::Parse(header, &error));
50     if (!crx.get())
51       return;
52     is_delta_ = crx_file::CrxFile::HeaderIsDelta(header);
53
54     std::vector<uint8_t> key(header.key_size);
55     len = fread(&key[0], sizeof(uint8_t), header.key_size, crx_file);
56     if (len < header.key_size)
57       return;
58
59     std::vector<uint8_t> signature(header.signature_size);
60     len =
61         fread(&signature[0], sizeof(uint8_t), header.signature_size, crx_file);
62     if (len < header.signature_size)
63       return;
64
65     crypto::SignatureVerifier verifier;
66     if (!verifier.VerifyInit(crx_file::kSignatureAlgorithm,
67                              base::checked_cast<int>(
68                                  sizeof(crx_file::kSignatureAlgorithm)),
69                              &signature[0],
70                              base::checked_cast<int>(signature.size()),
71                              &key[0],
72                              base::checked_cast<int>(key.size()))) {
73       // Signature verification initialization failed. This is most likely
74       // caused by a public key in the wrong format (should encode algorithm).
75       return;
76     }
77
78     const size_t kBufSize = 8 * 1024;
79     scoped_ptr<uint8_t[]> buf(new uint8_t[kBufSize]);
80     while ((len = fread(buf.get(), 1, kBufSize, crx_file)) > 0)
81       verifier.VerifyUpdate(buf.get(), base::checked_cast<int>(len));
82
83     if (!verifier.VerifyFinal())
84       return;
85
86     public_key_.swap(key);
87     valid_ = true;
88   }
89
90   bool valid() const { return valid_; }
91
92   bool is_delta() const { return is_delta_; }
93
94   const std::vector<uint8_t>& public_key() const { return public_key_; }
95
96  private:
97   bool valid_;
98   bool is_delta_;
99   std::vector<uint8_t> public_key_;
100 };
101
102 }  // namespace
103
104 ComponentUnpacker::ComponentUnpacker(
105     const std::vector<uint8_t>& pk_hash,
106     const base::FilePath& path,
107     const std::string& fingerprint,
108     ComponentInstaller* installer,
109     scoped_refptr<OutOfProcessPatcher> out_of_process_patcher,
110     scoped_refptr<base::SequencedTaskRunner> task_runner)
111     : pk_hash_(pk_hash),
112       path_(path),
113       is_delta_(false),
114       fingerprint_(fingerprint),
115       installer_(installer),
116       out_of_process_patcher_(out_of_process_patcher),
117       error_(kNone),
118       extended_error_(0),
119       task_runner_(task_runner) {
120 }
121
122 // TODO(cpu): add a specific attribute check to a component json that the
123 // extension unpacker will reject, so that a component cannot be installed
124 // as an extension.
125 scoped_ptr<base::DictionaryValue> ReadManifest(
126     const base::FilePath& unpack_path) {
127   base::FilePath manifest =
128       unpack_path.Append(FILE_PATH_LITERAL("manifest.json"));
129   if (!base::PathExists(manifest))
130     return scoped_ptr<base::DictionaryValue>();
131   JSONFileValueSerializer serializer(manifest);
132   std::string error;
133   scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error));
134   if (!root.get())
135     return scoped_ptr<base::DictionaryValue>();
136   if (!root->IsType(base::Value::TYPE_DICTIONARY))
137     return scoped_ptr<base::DictionaryValue>();
138   return scoped_ptr<base::DictionaryValue>(
139              static_cast<base::DictionaryValue*>(root.release())).Pass();
140 }
141
142 bool ComponentUnpacker::UnpackInternal() {
143   return Verify() && Unzip() && BeginPatching();
144 }
145
146 void ComponentUnpacker::Unpack(const Callback& callback) {
147   callback_ = callback;
148   if (!UnpackInternal())
149     Finish();
150 }
151
152 bool ComponentUnpacker::Verify() {
153   VLOG(1) << "Verifying component: " << path_.value();
154   if (pk_hash_.empty() || path_.empty()) {
155     error_ = kInvalidParams;
156     return false;
157   }
158   // First, validate the CRX header and signature. As of today
159   // this is SHA1 with RSA 1024.
160   base::ScopedFILE file(base::OpenFile(path_, "rb"));
161   if (!file.get()) {
162     error_ = kInvalidFile;
163     return false;
164   }
165   CRXValidator validator(file.get());
166   file.reset();
167   if (!validator.valid()) {
168     error_ = kInvalidFile;
169     return false;
170   }
171   is_delta_ = validator.is_delta();
172
173   // File is valid and the digital signature matches. Now make sure
174   // the public key hash matches the expected hash. If they do we fully
175   // trust this CRX.
176   uint8_t hash[32] = {};
177   scoped_ptr<SecureHash> sha256(SecureHash::Create(SecureHash::SHA256));
178   sha256->Update(&(validator.public_key()[0]), validator.public_key().size());
179   sha256->Finish(hash, arraysize(hash));
180
181   if (!std::equal(pk_hash_.begin(), pk_hash_.end(), hash)) {
182     VLOG(1) << "Hash mismatch: " << path_.value();
183     error_ = kInvalidId;
184     return false;
185   }
186   VLOG(1) << "Verification successful: " << path_.value();
187   return true;
188 }
189
190 bool ComponentUnpacker::Unzip() {
191   base::FilePath& destination = is_delta_ ? unpack_diff_path_ : unpack_path_;
192   VLOG(1) << "Unpacking in: " << destination.value();
193   if (!base::CreateNewTempDirectory(base::FilePath::StringType(),
194                                     &destination)) {
195     VLOG(1) << "Unable to create temporary directory for unpacking.";
196     error_ = kUnzipPathError;
197     return false;
198   }
199   if (!zip::Unzip(path_, destination)) {
200     VLOG(1) << "Unzipping failed.";
201     error_ = kUnzipFailed;
202     return false;
203   }
204   VLOG(1) << "Unpacked successfully";
205   return true;
206 }
207
208 bool ComponentUnpacker::BeginPatching() {
209   if (is_delta_) {  // Package is a diff package.
210     // Use a different temp directory for the patch output files.
211     if (!base::CreateNewTempDirectory(base::FilePath::StringType(),
212                                       &unpack_path_)) {
213       error_ = kUnzipPathError;
214       return false;
215     }
216     patcher_ = new ComponentPatcher(unpack_diff_path_,
217                                     unpack_path_,
218                                     installer_,
219                                     out_of_process_patcher_,
220                                     task_runner_);
221     task_runner_->PostTask(
222         FROM_HERE,
223         base::Bind(&ComponentPatcher::Start,
224                    patcher_,
225                    base::Bind(&ComponentUnpacker::EndPatching,
226                               scoped_refptr<ComponentUnpacker>(this))));
227   } else {
228     task_runner_->PostTask(FROM_HERE,
229                            base::Bind(&ComponentUnpacker::EndPatching,
230                                       scoped_refptr<ComponentUnpacker>(this),
231                                       kNone,
232                                       0));
233   }
234   return true;
235 }
236
237 void ComponentUnpacker::EndPatching(Error error, int extended_error) {
238   error_ = error;
239   extended_error_ = extended_error;
240   patcher_ = NULL;
241   if (error_ != kNone) {
242     Finish();
243     return;
244   }
245   // Optimization: clean up patch files early, in case disk space is too low to
246   // install otherwise.
247   if (!unpack_diff_path_.empty()) {
248     base::DeleteFile(unpack_diff_path_, true);
249     unpack_diff_path_.clear();
250   }
251   Install();
252   Finish();
253 }
254
255 void ComponentUnpacker::Install() {
256   // Write the fingerprint to disk.
257   if (static_cast<int>(fingerprint_.size()) !=
258       base::WriteFile(
259           unpack_path_.Append(FILE_PATH_LITERAL("manifest.fingerprint")),
260           fingerprint_.c_str(),
261           base::checked_cast<int>(fingerprint_.size()))) {
262     error_ = kFingerprintWriteFailed;
263     return;
264   }
265   scoped_ptr<base::DictionaryValue> manifest(ReadManifest(unpack_path_));
266   if (!manifest.get()) {
267     error_ = kBadManifest;
268     return;
269   }
270   DCHECK(error_ == kNone);
271   if (!installer_->Install(*manifest, unpack_path_)) {
272     error_ = kInstallerError;
273     return;
274   }
275 }
276
277 void ComponentUnpacker::Finish() {
278   if (!unpack_diff_path_.empty())
279     base::DeleteFile(unpack_diff_path_, true);
280   if (!unpack_path_.empty())
281     base::DeleteFile(unpack_path_, true);
282   callback_.Run(error_, extended_error_);
283 }
284
285 ComponentUnpacker::~ComponentUnpacker() {
286 }
287
288 }  // namespace component_updater