OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/component_updater/component_unpacker.h" | 5 #include "chrome/browser/component_updater/component_unpacker.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
11 #include "base/json/json_file_value_serializer.h" | 11 #include "base/json/json_file_value_serializer.h" |
12 #include "base/memory/scoped_handle.h" | 12 #include "base/memory/scoped_handle.h" |
13 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
14 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
15 #include "chrome/browser/component_updater/component_patcher.h" | |
16 #include "chrome/browser/component_updater/component_updater_service.h" | 15 #include "chrome/browser/component_updater/component_updater_service.h" |
17 #include "chrome/common/extensions/extension_constants.h" | 16 #include "chrome/common/extensions/extension_constants.h" |
18 #include "crypto/secure_hash.h" | 17 #include "crypto/secure_hash.h" |
19 #include "crypto/signature_verifier.h" | 18 #include "crypto/signature_verifier.h" |
20 #include "extensions/common/crx_file.h" | 19 #include "extensions/common/crx_file.h" |
21 #include "third_party/zlib/google/zip.h" | 20 #include "third_party/zlib/google/zip.h" |
22 | 21 |
23 using crypto::SecureHash; | 22 using crypto::SecureHash; |
24 | 23 |
25 namespace { | 24 namespace { |
26 | |
27 // This class makes sure that the CRX digital signature is valid | 25 // This class makes sure that the CRX digital signature is valid |
28 // and well formed. | 26 // and well formed. |
29 class CRXValidator { | 27 class CRXValidator { |
30 public: | 28 public: |
31 explicit CRXValidator(FILE* crx_file) : valid_(false), delta_(false) { | 29 explicit CRXValidator(FILE* crx_file) : valid_(false) { |
32 extensions::CrxFile::Header header; | 30 extensions::CrxFile::Header header; |
33 size_t len = fread(&header, 1, sizeof(header), crx_file); | 31 size_t len = fread(&header, 1, sizeof(header), crx_file); |
34 if (len < sizeof(header)) | 32 if (len < sizeof(header)) |
35 return; | 33 return; |
36 | 34 |
37 extensions::CrxFile::Error error; | 35 extensions::CrxFile::Error error; |
38 scoped_ptr<extensions::CrxFile> crx( | 36 scoped_ptr<extensions::CrxFile> crx( |
39 extensions::CrxFile::Parse(header, &error)); | 37 extensions::CrxFile::Parse(header, &error)); |
40 if (!crx.get()) | 38 if (!crx.get()) |
41 return; | 39 return; |
42 delta_ = extensions::CrxFile::HeaderIsDelta(header); | |
43 | 40 |
44 std::vector<uint8> key(header.key_size); | 41 std::vector<uint8> key(header.key_size); |
45 len = fread(&key[0], sizeof(uint8), header.key_size, crx_file); | 42 len = fread(&key[0], sizeof(uint8), header.key_size, crx_file); |
46 if (len < header.key_size) | 43 if (len < header.key_size) |
47 return; | 44 return; |
48 | 45 |
49 std::vector<uint8> signature(header.signature_size); | 46 std::vector<uint8> signature(header.signature_size); |
50 len = fread(&signature[0], sizeof(uint8), header.signature_size, crx_file); | 47 len = fread(&signature[0], sizeof(uint8), header.signature_size, crx_file); |
51 if (len < header.signature_size) | 48 if (len < header.signature_size) |
52 return; | 49 return; |
(...skipping 15 matching lines...) Expand all Loading... |
68 | 65 |
69 if (!verifier.VerifyFinal()) | 66 if (!verifier.VerifyFinal()) |
70 return; | 67 return; |
71 | 68 |
72 public_key_.swap(key); | 69 public_key_.swap(key); |
73 valid_ = true; | 70 valid_ = true; |
74 } | 71 } |
75 | 72 |
76 bool valid() const { return valid_; } | 73 bool valid() const { return valid_; } |
77 | 74 |
78 bool delta() const { return delta_; } | |
79 | |
80 const std::vector<uint8>& public_key() const { return public_key_; } | 75 const std::vector<uint8>& public_key() const { return public_key_; } |
81 | 76 |
82 private: | 77 private: |
83 bool valid_; | 78 bool valid_; |
84 bool delta_; | |
85 std::vector<uint8> public_key_; | 79 std::vector<uint8> public_key_; |
86 }; | 80 }; |
87 | 81 |
88 // Deserialize the CRX manifest. The top level must be a dictionary. | 82 // 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 | 83 // 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 | 84 // extension unpacker will reject, so that a component cannot be installed |
91 // as an extension. | 85 // as an extension. |
92 base::DictionaryValue* ReadManifest(const base::FilePath& unpack_path) { | 86 base::DictionaryValue* ReadManifest(const base::FilePath& unpack_path) { |
93 base::FilePath manifest = | 87 base::FilePath manifest = |
94 unpack_path.Append(FILE_PATH_LITERAL("manifest.json")); | 88 unpack_path.Append(FILE_PATH_LITERAL("manifest.json")); |
95 if (!file_util::PathExists(manifest)) | 89 if (!file_util::PathExists(manifest)) |
96 return NULL; | 90 return NULL; |
97 JSONFileValueSerializer serializer(manifest); | 91 JSONFileValueSerializer serializer(manifest); |
98 std::string error; | 92 std::string error; |
99 scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error)); | 93 scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error)); |
100 if (!root.get()) | 94 if (!root.get()) |
101 return NULL; | 95 return NULL; |
102 if (!root->IsType(base::Value::TYPE_DICTIONARY)) | 96 if (!root->IsType(base::Value::TYPE_DICTIONARY)) |
103 return NULL; | 97 return NULL; |
104 return static_cast<base::DictionaryValue*>(root.release()); | 98 return static_cast<base::DictionaryValue*>(root.release()); |
105 } | 99 } |
106 | 100 |
107 // 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. | |
111 bool MakeEmptyDirectory(const base::FilePath& path) { | |
112 if (file_util::PathExists(path)) { | |
113 if (!file_util::Delete(path, true)) | |
114 return false; | |
115 } | |
116 if (!file_util::CreateDirectory(path)) | |
117 return false; | |
118 return true; | |
119 } | |
120 | |
121 } // namespace. | 101 } // namespace. |
122 | 102 |
123 ComponentUnpacker::ComponentUnpacker(const std::vector<uint8>& pk_hash, | 103 ComponentUnpacker::ComponentUnpacker(const std::vector<uint8>& pk_hash, |
124 const base::FilePath& path, | 104 const base::FilePath& path, |
125 const std::string& fingerprint, | |
126 ComponentPatcher* patcher, | |
127 ComponentInstaller* installer) | 105 ComponentInstaller* installer) |
128 : error_(kNone), | 106 : error_(kNone) { |
129 extended_error_(0) { | |
130 if (pk_hash.empty() || path.empty()) { | 107 if (pk_hash.empty() || path.empty()) { |
131 error_ = kInvalidParams; | 108 error_ = kInvalidParams; |
132 return; | 109 return; |
133 } | 110 } |
134 // First, validate the CRX header and signature. As of today | 111 // First, validate the CRX header and signature. As of today |
135 // this is SHA1 with RSA 1024. | 112 // this is SHA1 with RSA 1024. |
136 ScopedStdioHandle file(file_util::OpenFile(path, "rb")); | 113 ScopedStdioHandle file(file_util::OpenFile(path, "rb")); |
137 if (!file.get()) { | 114 if (!file.get()) { |
138 error_ = kInvalidFile; | 115 error_ = kInvalidFile; |
139 return; | 116 return; |
(...skipping 11 matching lines...) Expand all Loading... |
151 uint8 hash[32]; | 128 uint8 hash[32]; |
152 scoped_ptr<SecureHash> sha256(SecureHash::Create(SecureHash::SHA256)); | 129 scoped_ptr<SecureHash> sha256(SecureHash::Create(SecureHash::SHA256)); |
153 sha256->Update(&(validator.public_key()[0]), validator.public_key().size()); | 130 sha256->Update(&(validator.public_key()[0]), validator.public_key().size()); |
154 sha256->Finish(hash, arraysize(hash)); | 131 sha256->Finish(hash, arraysize(hash)); |
155 | 132 |
156 if (!std::equal(pk_hash.begin(), pk_hash.end(), hash)) { | 133 if (!std::equal(pk_hash.begin(), pk_hash.end(), hash)) { |
157 error_ = kInvalidId; | 134 error_ = kInvalidId; |
158 return; | 135 return; |
159 } | 136 } |
160 // We want the temporary directory to be unique and yet predictable, so | 137 // We want the temporary directory to be unique and yet predictable, so |
161 // we can easily find the package in an end user machine. | 138 // we can easily find the package in a end user machine. |
162 const std::string dir( | 139 std::string dir( |
163 base::StringPrintf("CRX_%s", base::HexEncode(hash, 6).c_str())); | 140 base::StringPrintf("CRX_%s", base::HexEncode(hash, 6).c_str())); |
164 unpack_path_ = path.DirName().AppendASCII(dir.c_str()); | 141 unpack_path_ = path.DirName().AppendASCII(dir.c_str()); |
165 if (!MakeEmptyDirectory(unpack_path_)) { | 142 if (file_util::DirectoryExists(unpack_path_)) { |
| 143 if (!file_util::Delete(unpack_path_, true)) { |
| 144 unpack_path_.clear(); |
| 145 error_ = kUzipPathError; |
| 146 return; |
| 147 } |
| 148 } |
| 149 if (!file_util::CreateDirectory(unpack_path_)) { |
166 unpack_path_.clear(); | 150 unpack_path_.clear(); |
167 error_ = kUnzipPathError; | 151 error_ = kUzipPathError; |
168 return; | 152 return; |
169 } | 153 } |
170 if (validator.delta()) { // Package is a diff package. | 154 if (!zip::Unzip(path, unpack_path_)) { |
171 // We want a different temp directory for the delta files; we'll put the | 155 error_ = kUnzipFailed; |
172 // patch output into unpack_path_. | 156 return; |
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; | |
178 return; | |
179 } | |
180 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_); | |
189 file_util::Delete(unpack_diff_path, true); | |
190 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 } | |
201 } | 157 } |
202 scoped_ptr<base::DictionaryValue> manifest(ReadManifest(unpack_path_)); | 158 scoped_ptr<base::DictionaryValue> manifest(ReadManifest(unpack_path_)); |
203 if (!manifest.get()) { | 159 if (!manifest.get()) { |
204 error_ = kBadManifest; | 160 error_ = kBadManifest; |
205 return; | 161 return; |
206 } | 162 } |
207 // 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 } | |
216 if (!installer->Install(*manifest, unpack_path_)) { | 163 if (!installer->Install(*manifest, unpack_path_)) { |
217 error_ = kInstallerError; | 164 error_ = kInstallerError; |
218 return; | 165 return; |
219 } | 166 } |
220 // Installation successful. The directory is not our concern now. | 167 // Installation successful. The directory is not our concern now. |
221 unpack_path_.clear(); | 168 unpack_path_.clear(); |
222 } | 169 } |
223 | 170 |
224 ComponentUnpacker::~ComponentUnpacker() { | 171 ComponentUnpacker::~ComponentUnpacker() { |
225 if (!unpack_path_.empty()) | 172 if (!unpack_path_.empty()) { |
226 file_util::Delete(unpack_path_, true); | 173 file_util::Delete(unpack_path_, true); |
| 174 } |
227 } | 175 } |
OLD | NEW |