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. 4 5 #include "chrome/browser/component_updater/component_unpacker.h" 6 7 #include <string> 8 #include <vector> 9 10 #include "base/file_util.h" 11 #include "base/json/json_file_value_serializer.h" 12 #include "base/memory/scoped_handle.h" 13 #include "base/strings/string_number_conversions.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" 17 #include "chrome/common/extensions/extension_constants.h" 18 #include "crypto/secure_hash.h" 19 #include "crypto/signature_verifier.h" 20 #include "extensions/common/crx_file.h" 21 #include "third_party/zlib/google/zip.h" 22 23 using crypto::SecureHash; 24 25 namespace { 26 27 // This class makes sure that the CRX digital signature is valid 28 // and well formed. 29 class CRXValidator { 30 public: 31 explicit CRXValidator(FILE* crx_file) : valid_(false), delta_(false) { 32 extensions::CrxFile::Header header; 33 size_t len = fread(&header, 1, sizeof(header), crx_file); 34 if (len < sizeof(header)) 35 return; 36 37 extensions::CrxFile::Error error; 38 scoped_ptr<extensions::CrxFile> crx( 39 extensions::CrxFile::Parse(header, &error)); 40 if (!crx.get()) 41 return; 42 delta_ = extensions::CrxFile::HeaderIsDelta(header); 43 44 std::vector<uint8> key(header.key_size); 45 len = fread(&key[0], sizeof(uint8), header.key_size, crx_file); 46 if (len < header.key_size) 47 return; 48 49 std::vector<uint8> signature(header.signature_size); 50 len = fread(&signature[0], sizeof(uint8), header.signature_size, crx_file); 51 if (len < header.signature_size) 52 return; 53 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). 61 return; 62 } 63 64 const size_t kBufSize = 8 * 1024; 65 scoped_ptr<uint8[]> buf(new uint8[kBufSize]); 66 while ((len = fread(buf.get(), 1, kBufSize, crx_file)) > 0) 67 verifier.VerifyUpdate(buf.get(), len); 68 69 if (!verifier.VerifyFinal()) 70 return; 71 72 public_key_.swap(key); 73 valid_ = true; 74 } 75 76 bool valid() const { return valid_; } 77 78 bool delta() const { return delta_; } 79 80 const std::vector<uint8>& public_key() const { return public_key_; } 81 82 private: 83 bool valid_; 84 bool delta_; 85 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. 92 base::DictionaryValue* ReadManifest(const base::FilePath& unpack_path) { 93 base::FilePath manifest = 94 unpack_path.Append(FILE_PATH_LITERAL("manifest.json")); 95 if (!base::PathExists(manifest)) 96 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 107 } // namespace. 108 109 ComponentUnpacker::ComponentUnpacker(const std::vector<uint8>& pk_hash, 110 const base::FilePath& path, 111 const std::string& fingerprint, 112 ComponentPatcher* patcher, 113 ComponentInstaller* installer) 114 : error_(kNone), 115 extended_error_(0) { 116 if (pk_hash.empty() || path.empty()) { 117 error_ = kInvalidParams; 118 return; 119 } 120 // First, validate the CRX header and signature. As of today 121 // this is SHA1 with RSA 1024. 122 ScopedStdioHandle file(file_util::OpenFile(path, "rb")); 123 if (!file.get()) { 124 error_ = kInvalidFile; 125 return; 126 } 127 CRXValidator validator(file.get()); 128 if (!validator.valid()) { 129 error_ = kInvalidFile; 130 return; 131 } 132 file.Close(); 133 134 // File is valid and the digital signature matches. Now make sure 135 // the public key hash matches the expected hash. If they do we fully 136 // trust this CRX. 137 uint8 hash[32]; 138 scoped_ptr<SecureHash> sha256(SecureHash::Create(SecureHash::SHA256)); 139 sha256->Update(&(validator.public_key()[0]), validator.public_key().size()); 140 sha256->Finish(hash, arraysize(hash)); 141 142 if (!std::equal(pk_hash.begin(), pk_hash.end(), hash)) { 143 error_ = kInvalidId; 144 return; 145 } 146 if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL(""), 147 &unpack_path_)) { 148 error_ = kUnzipPathError; 149 return; 150 } 151 if (validator.delta()) { // Package is a diff package. 152 // We want a different temp directory for the delta files; we'll put the 153 // patch output into unpack_path_. 154 base::FilePath unpack_diff_path; 155 if (!file_util::CreateNewTempDirectory(FILE_PATH_LITERAL(""), 156 &unpack_diff_path)) { 157 error_ = kUnzipPathError; 158 return; 159 } 160 if (!zip::Unzip(path, unpack_diff_path)) { 161 error_ = kUnzipFailed; 162 return; 163 } 164 ComponentUnpacker::Error result = DifferentialUpdatePatch(unpack_diff_path, 165 unpack_path_, 166 patcher, 167 installer, 168 &extended_error_); 169 base::DeleteFile(unpack_diff_path, true); 170 unpack_diff_path.clear(); 171 error_ = result; 172 if (error_ != kNone) { 173 return; 174 } 175 } else { 176 // Package is a normal update/install; unzip it into unpack_path_ directly. 177 if (!zip::Unzip(path, unpack_path_)) { 178 error_ = kUnzipFailed; 179 return; 180 } 181 } 182 scoped_ptr<base::DictionaryValue> manifest(ReadManifest(unpack_path_)); 183 if (!manifest.get()) { 184 error_ = kBadManifest; 185 return; 186 } 187 // Write the fingerprint to disk. 188 if (static_cast<int>(fingerprint.size()) != 189 file_util::WriteFile( 190 unpack_path_.Append(FILE_PATH_LITERAL("manifest.fingerprint")), 191 fingerprint.c_str(), 192 fingerprint.size())) { 193 error_ = kFingerprintWriteFailed; 194 return; 195 } 196 if (!installer->Install(*manifest, unpack_path_)) { 197 error_ = kInstallerError; 198 return; 199 } 200 // Installation successful. The directory is not our concern now. 201 unpack_path_.clear(); 202 } 203 204 ComponentUnpacker::~ComponentUnpacker() { 205 if (!unpack_path_.empty()) 206 base::DeleteFile(unpack_path_, true); 207 } 208