Chromium Code Reviews| Index: chrome/browser/extensions/sandboxed_unpacker.cc |
| diff --git a/chrome/browser/extensions/sandboxed_unpacker.cc b/chrome/browser/extensions/sandboxed_unpacker.cc |
| index b2c6a3b3a53e3aeae8465af79f609cb002d1385a..a4a079c8d57f64ca835dc1242594a65275c44381 100644 |
| --- a/chrome/browser/extensions/sandboxed_unpacker.cc |
| +++ b/chrome/browser/extensions/sandboxed_unpacker.cc |
| @@ -18,6 +18,7 @@ |
| #include "base/numerics/safe_conversions.h" |
| #include "base/path_service.h" |
| #include "base/sequenced_task_runner.h" |
| +#include "base/strings/string_number_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/threading/sequenced_worker_pool.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| @@ -32,6 +33,8 @@ |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/utility_process_host.h" |
| #include "content/public/common/common_param_traits.h" |
| +#include "crypto/secure_hash.h" |
| +#include "crypto/sha2.h" |
| #include "crypto/signature_verifier.h" |
| #include "extensions/common/constants.h" |
| #include "extensions/common/extension.h" |
| @@ -40,6 +43,7 @@ |
| #include "extensions/common/file_util.h" |
| #include "extensions/common/manifest_constants.h" |
| #include "extensions/common/manifest_handlers/icons_handler.h" |
| +#include "extensions/common/switches.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/gfx/codec/png_codec.h" |
| @@ -63,6 +67,10 @@ using crx_file::CrxFile; |
| #define UNPACK_RATE_HISTOGRAM(name, rate) \ |
| UMA_HISTOGRAM_CUSTOM_COUNTS(name, rate, 1, 100000, 100); |
| +// Record if the .crx hash sum is the same as in the updater manifest. |
| +#define CRX_HASH_CHECK_HISTOGRAM(name, success) \ |
| + UMA_HISTOGRAM_BOOLEAN(name, success) |
| + |
| namespace extensions { |
| namespace { |
| @@ -216,18 +224,25 @@ bool ReadMessageCatalogsFromFile(const base::FilePath& extension_path, |
| SandboxedUnpacker::SandboxedUnpacker( |
| const base::FilePath& crx_path, |
| + const std::string& package_hash, |
| Manifest::Location location, |
| int creation_flags, |
| const base::FilePath& extensions_dir, |
| const scoped_refptr<base::SequencedTaskRunner>& unpacker_io_task_runner, |
| SandboxedUnpackerClient* client) |
| : crx_path_(crx_path), |
| + package_hash_(package_hash), |
| + check_crx_hash_(false), |
| client_(client), |
| extensions_dir_(extensions_dir), |
| got_response_(false), |
| location_(location), |
| creation_flags_(creation_flags), |
| unpacker_io_task_runner_(unpacker_io_task_runner) { |
| + if (!package_hash_.empty()) { |
| + check_crx_hash_ = base::CommandLine::ForCurrentProcess()->HasSwitch( |
| + extensions::switches::kEnableCrxHashCheck); |
| + } |
| } |
| bool SandboxedUnpacker::CreateTempDirectory() { |
| @@ -422,9 +437,27 @@ void SandboxedUnpacker::OnUnpackExtensionFailed(const base::string16& error) { |
| error)); |
| } |
| +static size_t fread_sha256(void* ptr, |
| + size_t size, |
| + size_t nmemb, |
| + FILE* stream, |
| + scoped_ptr<crypto::SecureHash>& hash) { |
| + size_t len = fread(ptr, size, nmemb, stream); |
| + if (len > 0 && hash) { |
| + hash->Update(ptr, len * size); |
| + } |
| + return len; |
| +} |
| + |
| bool SandboxedUnpacker::ValidateSignature() { |
| base::ScopedFILE file(base::OpenFile(crx_path_, "rb")); |
| + scoped_ptr<crypto::SecureHash> hash; |
| + |
| + if (!package_hash_.empty()) { |
| + hash.reset(crypto::SecureHash::Create(crypto::SecureHash::SHA256)); |
| + } |
| + |
| if (!file.get()) { |
| // Could not open crx file for reading. |
| #if defined (OS_WIN) |
| @@ -458,7 +491,7 @@ bool SandboxedUnpacker::ValidateSignature() { |
| // code in the code base. So for now, this assumes that we're running |
| // on a little endian machine with 4 byte alignment. |
| CrxFile::Header header; |
| - size_t len = fread(&header, 1, sizeof(header), file.get()); |
| + size_t len = fread_sha256(&header, 1, sizeof(header), file.get(), hash); |
| if (len < sizeof(header)) { |
| // Invalid crx header |
| ReportFailure( |
| @@ -519,7 +552,8 @@ bool SandboxedUnpacker::ValidateSignature() { |
| std::vector<uint8> key; |
| key.resize(header.key_size); |
| - len = fread(&key.front(), sizeof(uint8), header.key_size, file.get()); |
| + len = fread_sha256(&key.front(), sizeof(uint8), header.key_size, file.get(), |
| + hash); |
| if (len < header.key_size) { |
| // Invalid public key |
| ReportFailure( |
| @@ -532,8 +566,8 @@ bool SandboxedUnpacker::ValidateSignature() { |
| std::vector<uint8> signature; |
| signature.resize(header.signature_size); |
| - len = fread(&signature.front(), sizeof(uint8), header.signature_size, |
| - file.get()); |
| + len = fread_sha256(&signature.front(), sizeof(uint8), header.signature_size, |
| + file.get(), hash); |
| if (len < header.signature_size) { |
| // Invalid signature |
| ReportFailure( |
| @@ -562,7 +596,7 @@ bool SandboxedUnpacker::ValidateSignature() { |
| } |
| unsigned char buf[1 << 12]; |
| - while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0) |
| + while ((len = fread_sha256(buf, 1, sizeof(buf), file.get(), hash)) > 0) |
| verifier.VerifyUpdate(buf, len); |
| if (!verifier.VerifyFinal()) { |
| @@ -575,6 +609,26 @@ bool SandboxedUnpacker::ValidateSignature() { |
| return false; |
| } |
| + if (hash) { |
| + uint8 output3[crypto::kSHA256Length]; |
|
Dmitry Polukhin
2015/01/15 12:45:13
Why so strange name 'output3'?
|
| + hash->Finish(output3, sizeof(output3)); |
| + if (base::StringToLowerASCII(base::HexEncode(output3, sizeof(output3))) |
| + != package_hash_) { |
| + // Package hash verification failed |
| + CRX_HASH_CHECK_HISTOGRAM("Extensions.SandboxUnpackHashCheck", false); |
| + if (check_crx_hash_) { |
|
Dmitry Polukhin
2015/01/15 12:45:13
I would also print error message to log.
|
| + ReportFailure( |
| + CRX_HASH_VERIFICATION_FAILED, |
| + l10n_util::GetStringFUTF16( |
| + IDS_EXTENSION_PACKAGE_ERROR_CODE, |
| + ASCIIToUTF16("CRX_HASH_VERIFICATION_FAILED"))); |
| + return false; |
| + } |
| + } else { |
| + CRX_HASH_CHECK_HISTOGRAM("Extensions.SandboxUnpackHashCheck", true); |
| + } |
| + } |
| + |
| std::string public_key = |
| std::string(reinterpret_cast<char*>(&key.front()), key.size()); |
| base::Base64Encode(public_key, &public_key_); |