diff options
-rw-r--r-- | chrome/browser/browser_process_impl.cc | 14 | ||||
-rw-r--r-- | chrome/browser/download/base_file.cc | 39 | ||||
-rw-r--r-- | chrome/browser/download/base_file.h | 20 | ||||
-rw-r--r-- | chrome/browser/download/base_file_unittest.cc | 48 | ||||
-rw-r--r-- | chrome/browser/download/download_file_manager.cc | 17 | ||||
-rw-r--r-- | chrome/browser/download/download_file_manager.h | 3 | ||||
-rw-r--r-- | chrome/browser/download/save_file_manager.cc | 2 | ||||
-rw-r--r-- | chrome/browser/safe_browsing/safe_browsing_service.cc | 15 | ||||
-rw-r--r-- | chrome/browser/safe_browsing/safe_browsing_service.h | 8 |
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 |