Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(48)

Unified Diff: extensions/browser/sandboxed_unpacker.cc

Issue 829583002: Validate hash_sha256 checksum on .crx update. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix histogram value. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: extensions/browser/sandboxed_unpacker.cc
diff --git a/extensions/browser/sandboxed_unpacker.cc b/extensions/browser/sandboxed_unpacker.cc
index cd535a83dbed0c2e9397e188d8300973d417f084..cc40e45677711036170549c9ff481e7c0050c1c2 100644
--- a/extensions/browser/sandboxed_unpacker.cc
+++ b/extensions/browser/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 "components/crx_file/constants.h"
@@ -26,6 +27,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"
@@ -35,6 +38,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 "grit/extensions_strings.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/l10n/l10n_util.h"
@@ -59,6 +63,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) \
Ilya Sherman 2015/02/03 21:40:29 Why do you need a wrapper macro?
+ UMA_HISTOGRAM_BOOLEAN(name, success)
+
namespace extensions {
namespace {
@@ -209,19 +217,25 @@ bool ReadMessageCatalogsFromFile(const base::FilePath& extension_path,
} // namespace
SandboxedUnpacker::SandboxedUnpacker(
- const base::FilePath& crx_path,
+ const CRXFileInfo& file,
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),
+ : crx_path_(file.path),
+ package_hash_(file.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() {
@@ -402,9 +416,52 @@ void SandboxedUnpacker::OnUnpackExtensionFailed(const base::string16& error) {
l10n_util::GetStringFUTF16(IDS_EXTENSION_PACKAGE_ERROR_MESSAGE, error));
}
+static size_t ReadAndHash(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::FinalizeHash(scoped_ptr<crypto::SecureHash>& hash) {
+ if (hash) {
+ uint8 output[crypto::kSHA256Length];
+ hash->Finish(output, sizeof(output));
+ if (base::StringToLowerASCII(base::HexEncode(output, sizeof(output))) !=
+ package_hash_) {
+ // Package hash verification failed
+ CRX_HASH_CHECK_HISTOGRAM("Extensions.SandboxUnpackHashCheck", false);
+ if (check_crx_hash_) {
+ std::string name = crx_path_.BaseName().AsUTF8Unsafe();
+ LOG(ERROR) << "Hash check failed for extension: " << name;
+ 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);
Ilya Sherman 2015/02/03 21:40:29 I'd recommend having a single code path per histog
+ }
+ }
+
+ return true;
+}
+
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)
@@ -437,7 +494,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 = ReadAndHash(&header, 1, sizeof(header), file.get(), hash);
if (len < sizeof(header)) {
// Invalid crx header
ReportFailure(CRX_HEADER_INVALID, l10n_util::GetStringFUTF16(
@@ -492,7 +549,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 = ReadAndHash(&key.front(), sizeof(uint8), header.key_size, file.get(),
+ hash);
if (len < header.key_size) {
// Invalid public key
ReportFailure(
@@ -504,8 +562,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 = ReadAndHash(&signature.front(), sizeof(uint8), header.signature_size,
+ file.get(), hash);
if (len < header.signature_size) {
// Invalid signature
ReportFailure(
@@ -530,7 +588,7 @@ bool SandboxedUnpacker::ValidateSignature() {
}
unsigned char buf[1 << 12];
- while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0)
+ while ((len = ReadAndHash(buf, 1, sizeof(buf), file.get(), hash)) > 0)
verifier.VerifyUpdate(buf, len);
if (!verifier.VerifyFinal()) {
@@ -542,6 +600,10 @@ bool SandboxedUnpacker::ValidateSignature() {
return false;
}
+ if (!FinalizeHash(hash)) {
+ return false;
+ }
+
std::string public_key =
std::string(reinterpret_cast<char*>(&key.front()), key.size());
base::Base64Encode(public_key, &public_key_);

Powered by Google App Engine
This is Rietveld 408576698