summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlzheng@chromium.org <lzheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-13 23:26:28 +0000
committerlzheng@chromium.org <lzheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-13 23:26:28 +0000
commit42930de46c386ff5104138d003486bd12a78c45f (patch)
tree2859aeaab1dabfabacb32a2799eed0657b1a5bcf
parent869b5b6f67e9dbf02392ab941ff80f959329ea80 (diff)
downloadchromium_src-42930de46c386ff5104138d003486bd12a78c45f.zip
chromium_src-42930de46c386ff5104138d003486bd12a78c45f.tar.gz
chromium_src-42930de46c386ff5104138d003486bd12a78c45f.tar.bz2
Add support to sha256 hash the downloaded file.
BUG=60822 TEST=base_file_unittest.cc Review URL: http://codereview.chromium.org/6023006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@71379 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/browser_process_impl.cc14
-rw-r--r--chrome/browser/download/base_file.cc39
-rw-r--r--chrome/browser/download/base_file.h20
-rw-r--r--chrome/browser/download/base_file_unittest.cc48
-rw-r--r--chrome/browser/download/download_file_manager.cc17
-rw-r--r--chrome/browser/download/download_file_manager.h3
-rw-r--r--chrome/browser/download/save_file_manager.cc2
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_service.cc15
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_service.h8
9 files changed, 139 insertions, 27 deletions
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 7a14807..db3b343 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -804,15 +804,11 @@ void BrowserProcessImpl::CreateSafeBrowsingDetectionService() {
bool BrowserProcessImpl::IsSafeBrowsingDetectionServiceEnabled() {
// The safe browsing client-side detection is enabled only if the switch is
- // enabled, the user has opted in to UMA usage stats and SafeBrowsing
- // is enabled.
- Profile* profile = profile_manager() ?
- profile_manager()->GetDefaultProfile() : NULL;
- return (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableClientSidePhishingDetection) &&
- metrics_service() && metrics_service()->reporting_active() &&
- profile && profile->GetPrefs() &&
- profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled));
+ // enabled and when safe browsing related stats is allowed to be collected.
+ return CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableClientSidePhishingDetection) &&
+ resource_dispatcher_host()->safe_browsing_service() &&
+ resource_dispatcher_host()->safe_browsing_service()->CanReportStats();
}
// The BrowserProcess object must outlive the file thread so we use traits
diff --git a/chrome/browser/download/base_file.cc b/chrome/browser/download/base_file.cc
index 9d77233..4085f60 100644
--- a/chrome/browser/download/base_file.cc
+++ b/chrome/browser/download/base_file.cc
@@ -7,6 +7,8 @@
#include "base/file_util.h"
#include "base/logging.h"
#include "base/stringprintf.h"
+#include "base/third_party/nss/blapi.h"
+#include "base/third_party/nss/sha256.h"
#include "net/base/file_stream.h"
#include "net/base/net_errors.h"
#include "chrome/browser/browser_thread.h"
@@ -30,7 +32,9 @@ BaseFile::BaseFile(const FilePath& full_path,
referrer_url_(referrer_url),
file_stream_(file_stream),
bytes_so_far_(received_bytes),
- power_save_blocker_(true) {
+ power_save_blocker_(true),
+ calculate_hash_(false),
+ sha_context_(NULL) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
}
@@ -41,8 +45,16 @@ BaseFile::~BaseFile() {
Close();
}
-bool BaseFile::Initialize() {
+bool BaseFile::Initialize(bool calculate_hash) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ calculate_hash_ = calculate_hash;
+
+ if (calculate_hash_) {
+ sha_context_.reset(new SHA256Context);
+ SHA256_Begin(sha_context_.get());
+ }
+
if (!full_path_.empty() ||
download_util::CreateTemporaryFileForDownload(&full_path_))
return Open();
@@ -63,7 +75,16 @@ bool BaseFile::AppendDataToFile(const char* data, size_t data_len) {
// TODO(phajdan.jr): handle errors on file writes. http://crbug.com/58355
size_t written = file_stream_->Write(data, data_len, NULL);
- return (written == data_len);
+ if (written != data_len)
+ return false;
+
+ if (calculate_hash_) {
+ SHA256_Update(sha_context_.get(),
+ reinterpret_cast<const unsigned char*>(data),
+ data_len);
+ }
+
+ return true;
}
bool BaseFile::Rename(const FilePath& new_path, bool is_final_rename) {
@@ -139,9 +160,21 @@ void BaseFile::Cancel() {
void BaseFile::Finish() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ if (calculate_hash_)
+ SHA256_End(sha_context_.get(), sha256_hash_, NULL, kSha256HashLen);
+
Close();
}
+bool BaseFile::GetSha256Hash(std::string* hash) {
+ if (!calculate_hash_ || in_progress())
+ return false;
+ hash->assign(reinterpret_cast<const char*>(sha256_hash_),
+ sizeof(sha256_hash_));
+ return true;
+}
+
void BaseFile::AnnotateWithSourceInformation() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
#if defined(OS_WIN)
diff --git a/chrome/browser/download/base_file.h b/chrome/browser/download/base_file.h
index ffa63cc..3b0782a 100644
--- a/chrome/browser/download/base_file.h
+++ b/chrome/browser/download/base_file.h
@@ -10,6 +10,8 @@
#include "base/file_path.h"
#include "base/linked_ptr.h"
+#include "base/scoped_ptr.h"
+#include "base/third_party/nss/blapi.h"
#include "chrome/browser/power_save_blocker.h"
#include "googleurl/src/gurl.h"
@@ -28,7 +30,8 @@ class BaseFile {
const linked_ptr<net::FileStream>& file_stream);
~BaseFile();
- bool Initialize();
+ // If calculate_hash is true, sha256 hash will be calculated.
+ bool Initialize(bool calculate_hash);
// Write a new chunk of data to the file. Returns true on success (all bytes
// written to the file).
@@ -53,6 +56,10 @@ class BaseFile {
bool in_progress() const { return file_stream_ != NULL; }
int64 bytes_so_far() const { return bytes_so_far_; }
+ // Set |hash| with sha256 digest for the file.
+ // Returns true if digest is successfully calculated.
+ virtual bool GetSha256Hash(std::string* hash);
+
virtual std::string DebugString() const;
protected:
@@ -66,6 +73,8 @@ class BaseFile {
bool path_renamed_;
private:
+ static const size_t kSha256HashLen = 32;
+
// Source URL for the file being downloaded.
GURL source_url_;
@@ -81,6 +90,15 @@ class BaseFile {
// RAII handle to keep the system from sleeping while we're downloading.
PowerSaveBlocker power_save_blocker_;
+ // Indicates if sha256 hash should be calculated for the file.
+ bool calculate_hash_;
+
+ // Used to calculate sha256 hash for the file when calculate_hash_
+ // is set.
+ scoped_ptr<SHA256Context> sha_context_;
+
+ unsigned char sha256_hash_[kSha256HashLen];
+
DISALLOW_COPY_AND_ASSIGN(BaseFile);
};
diff --git a/chrome/browser/download/base_file_unittest.cc b/chrome/browser/download/base_file_unittest.cc
index 88698d2..c005a1c 100644
--- a/chrome/browser/download/base_file_unittest.cc
+++ b/chrome/browser/download/base_file_unittest.cc
@@ -5,6 +5,7 @@
#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/scoped_temp_dir.h"
+#include "base/string_number_conversions.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/download/base_file.h"
#include "net/base/file_stream.h"
@@ -23,7 +24,8 @@ class BaseFileTest : public testing::Test {
virtual void SetUp() {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- base_file_.reset(new BaseFile(FilePath(), GURL(), GURL(), 0, file_stream_));
+ base_file_.reset(
+ new BaseFile(FilePath(), GURL(), GURL(), 0, file_stream_));
}
virtual void TearDown() {
@@ -80,7 +82,7 @@ TEST_F(BaseFileTest, CreateDestroy) {
// Cancel the download explicitly.
TEST_F(BaseFileTest, Cancel) {
- ASSERT_TRUE(base_file_->Initialize());
+ ASSERT_TRUE(base_file_->Initialize(false));
EXPECT_TRUE(file_util::PathExists(base_file_->full_path()));
base_file_->Cancel();
EXPECT_FALSE(file_util::PathExists(base_file_->full_path()));
@@ -90,7 +92,7 @@ TEST_F(BaseFileTest, Cancel) {
// Write data to the file once.
TEST_F(BaseFileTest, SingleWrite) {
- ASSERT_TRUE(base_file_->Initialize());
+ ASSERT_TRUE(base_file_->Initialize(false));
AppendDataToFile(kTestData1);
base_file_->Finish();
@@ -99,18 +101,52 @@ TEST_F(BaseFileTest, SingleWrite) {
// Write data to the file multiple times.
TEST_F(BaseFileTest, MultipleWrites) {
- ASSERT_TRUE(base_file_->Initialize());
+ ASSERT_TRUE(base_file_->Initialize(false));
AppendDataToFile(kTestData1);
AppendDataToFile(kTestData2);
AppendDataToFile(kTestData3);
+ std::string hash;
+ EXPECT_FALSE(base_file_->GetSha256Hash(&hash));
base_file_->Finish();
EXPECT_FALSE(base_file_->path_renamed());
}
+// Write data to the file once and calculate its sha256 hash.
+TEST_F(BaseFileTest, SingleWriteWithHash) {
+ ASSERT_TRUE(base_file_->Initialize(true));
+ AppendDataToFile(kTestData1);
+ base_file_->Finish();
+
+ EXPECT_FALSE(base_file_->path_renamed());
+
+ std::string hash;
+ base_file_->GetSha256Hash(&hash);
+ EXPECT_EQ("0B2D3F3F7943AD64B860DF94D05CB56A8A97C6EC5768B5B70B930C5AA7FA9ADE",
+ base::HexEncode(hash.data(), hash.size()));
+}
+
+// Write data to the file multiple times and calculate its sha256 hash.
+TEST_F(BaseFileTest, MultipleWritesWithHash) {
+ std::string hash;
+
+ ASSERT_TRUE(base_file_->Initialize(true));
+ AppendDataToFile(kTestData1);
+ AppendDataToFile(kTestData2);
+ AppendDataToFile(kTestData3);
+ // no hash before Finish() is called either.
+ EXPECT_FALSE(base_file_->GetSha256Hash(&hash));
+ base_file_->Finish();
+
+ EXPECT_FALSE(base_file_->path_renamed());
+ EXPECT_TRUE(base_file_->GetSha256Hash(&hash));
+ EXPECT_EQ("CBF68BF10F8003DB86B31343AFAC8C7175BD03FB5FC905650F8C80AF087443A8",
+ base::HexEncode(hash.data(), hash.size()));
+}
+
// Rename the file after all writes to it.
TEST_F(BaseFileTest, WriteThenRename) {
- ASSERT_TRUE(base_file_->Initialize());
+ ASSERT_TRUE(base_file_->Initialize(false));
FilePath initial_path(base_file_->full_path());
EXPECT_TRUE(file_util::PathExists(initial_path));
@@ -130,7 +166,7 @@ TEST_F(BaseFileTest, WriteThenRename) {
// Rename the file while the download is still in progress.
TEST_F(BaseFileTest, RenameWhileInProgress) {
- ASSERT_TRUE(base_file_->Initialize());
+ ASSERT_TRUE(base_file_->Initialize(false));
FilePath initial_path(base_file_->full_path());
EXPECT_TRUE(file_util::PathExists(initial_path));
diff --git a/chrome/browser/download/download_file_manager.cc b/chrome/browser/download/download_file_manager.cc
index 07eb72d..b897464 100644
--- a/chrome/browser/download/download_file_manager.cc
+++ b/chrome/browser/download/download_file_manager.cc
@@ -18,6 +18,7 @@
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "googleurl/src/gurl.h"
@@ -74,14 +75,15 @@ void DownloadFileManager::OnShutdown() {
STLDeleteValues(&downloads_);
}
-void DownloadFileManager::CreateDownloadFile(
- DownloadCreateInfo* info, DownloadManager* download_manager) {
+void DownloadFileManager::CreateDownloadFile(DownloadCreateInfo* info,
+ DownloadManager* download_manager,
+ bool get_hash) {
VLOG(20) << __FUNCTION__ << "()" << " info = " << info->DebugString();
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- scoped_ptr<DownloadFile> download_file(
- new DownloadFile(info, download_manager));
- if (!download_file->Initialize()) {
+ scoped_ptr<DownloadFile>
+ download_file(new DownloadFile(info, download_manager));
+ if (!download_file->Initialize(get_hash)) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
NewRunnableFunction(&download_util::CancelDownloadRequest,
@@ -177,9 +179,12 @@ void DownloadFileManager::StartDownload(DownloadCreateInfo* info) {
manager->CreateDownloadItem(info);
+ bool hash_needed = resource_dispatcher_host_->safe_browsing_service()->
+ DownloadBinHashNeeded();
+
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(this, &DownloadFileManager::CreateDownloadFile,
- info, make_scoped_refptr(manager)));
+ info, make_scoped_refptr(manager), hash_needed));
}
// We don't forward an update to the UI thread here, since we want to throttle
diff --git a/chrome/browser/download/download_file_manager.h b/chrome/browser/download/download_file_manager.h
index 5ccf533..22d9c2c 100644
--- a/chrome/browser/download/download_file_manager.h
+++ b/chrome/browser/download/download_file_manager.h
@@ -115,7 +115,8 @@ class DownloadFileManager
// Creates DownloadFile on FILE thread and continues starting the download
// process.
void CreateDownloadFile(DownloadCreateInfo* info,
- DownloadManager* download_manager);
+ DownloadManager* download_manager,
+ bool hash_needed);
// Tells the ResourceDispatcherHost to resume a download request
// that was paused to wait for the on-disk file to be created.
diff --git a/chrome/browser/download/save_file_manager.cc b/chrome/browser/download/save_file_manager.cc
index 5b25ea6..b74be65 100644
--- a/chrome/browser/download/save_file_manager.cc
+++ b/chrome/browser/download/save_file_manager.cc
@@ -222,7 +222,7 @@ void SaveFileManager::StartSave(SaveFileCreateInfo* info) {
SaveFile* save_file = new SaveFile(info);
// TODO(phajdan.jr): We should check the return value and handle errors here.
- save_file->Initialize();
+ save_file->Initialize(false); // No need to calculate hash.
DCHECK(!LookupSaveFile(info->save_id));
save_file_map_[info->save_id] = save_file;
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index c4e8eff..a0f8384 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -47,6 +47,7 @@ const char* const kSbDefaultInfoURLPrefix =
const char* const kSbDefaultMacKeyURLPrefix =
"https://sb-ssl.google.com/safebrowsing";
+// TODO(lzheng): Replace this with Profile* ProfileManager::GetDefaultProfile().
Profile* GetDefaultProfile() {
FilePath user_data_dir;
PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
@@ -154,6 +155,20 @@ bool SafeBrowsingService::CanCheckUrl(const GURL& url) const {
url.SchemeIs(chrome::kHttpsScheme);
}
+// Only report SafeBrowsing related stats when UMA is enabled and
+// safe browsing is enabled.
+bool SafeBrowsingService::CanReportStats() const {
+ const MetricsService* metrics = g_browser_process->metrics_service();
+ const PrefService* pref_service = GetDefaultProfile()->GetPrefs();
+ return metrics && metrics->reporting_active() &&
+ pref_service && pref_service->GetBoolean(prefs::kSafeBrowsingEnabled);
+}
+
+// Binhash verification is only enabled for UMA users for now.
+bool SafeBrowsingService::DownloadBinHashNeeded() const {
+ return enable_download_protection_ && CanReportStats();
+}
+
void SafeBrowsingService::CheckDownloadUrlDone(
SafeBrowsingCheck* check, UrlCheckResult result) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.h b/chrome/browser/safe_browsing/safe_browsing_service.h
index 73eb201..28f74de 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.h
+++ b/chrome/browser/safe_browsing/safe_browsing_service.h
@@ -117,6 +117,10 @@ class SafeBrowsingService
// Create an instance of the safe browsing service.
static SafeBrowsingService* CreateSafeBrowsingService();
+ // Called on UI thread to decide if safe browsing related stats
+ // could be reported.
+ bool CanReportStats() const;
+
// Called on the UI thread to initialize the service.
void Initialize();
@@ -126,6 +130,10 @@ class SafeBrowsingService
// Returns true if the url's scheme can be checked.
bool CanCheckUrl(const GURL& url) const;
+ // Called on UI thread to decide if the download file's sha256 hash
+ // should be calculated for safebrowsing.
+ bool DownloadBinHashNeeded() const;
+
// Called on the IO thread to check if the given url is safe or not. If we
// can synchronously determine that the url is safe, CheckUrl returns true.
// Otherwise it returns false, and "client" is called asynchronously with the