Commit 3413ce67 authored by bryner@chromium.org's avatar bryner@chromium.org

Implement a whitelist for code-signing certificates.

With this change, only downloads that match a whitelisted URL or certificate will be exempt from the download protection pingback.  The certificate whitelist format allows matching on the certificate issuer along with the CN, O, or OU attributes of the certificate.

BUG=102540
TEST=DownloadProtectionServiceTest


Review URL: http://codereview.chromium.org/8762007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112604 0039d316-1c4b-4281-b951-d872f2087c98
parent f104ec58
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
#include "content/public/common/url_fetcher.h" #include "content/public/common/url_fetcher.h"
#include "content/public/common/url_fetcher_delegate.h" #include "content/public/common/url_fetcher_delegate.h"
#include "net/base/load_flags.h" #include "net/base/load_flags.h"
#include "net/base/x509_cert_types.h"
#include "net/base/x509_certificate.h"
#include "net/url_request/url_request_context_getter.h" #include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_status.h" #include "net/url_request/url_request_status.h"
...@@ -503,12 +505,15 @@ class DownloadProtectionService::CheckClientDownloadRequest ...@@ -503,12 +505,15 @@ class DownloadProtectionService::CheckClientDownloadRequest
for (size_t i = 0; i < info_.download_url_chain.size(); ++i) { for (size_t i = 0; i < info_.download_url_chain.size(); ++i) {
const GURL& url = info_.download_url_chain[i]; const GURL& url = info_.download_url_chain[i];
if (url.is_valid() && sb_service_->MatchDownloadWhitelistUrl(url)) { if (url.is_valid() && sb_service_->MatchDownloadWhitelistUrl(url)) {
VLOG(2) << url << " is on the download whitelist.";
reason = REASON_WHITELISTED_URL; reason = REASON_WHITELISTED_URL;
break; break;
} }
} }
if (info_.referrer_url.is_valid() && reason == REASON_MAX && if (info_.referrer_url.is_valid() && reason == REASON_MAX &&
sb_service_->MatchDownloadWhitelistUrl(info_.referrer_url)) { sb_service_->MatchDownloadWhitelistUrl(info_.referrer_url)) {
VLOG(2) << "Referrer url " << info_.referrer_url
<< " is on the download whitelist.";
reason = REASON_WHITELISTED_REFERRER; reason = REASON_WHITELISTED_REFERRER;
} }
if (reason != REASON_MAX || signature_info_.trusted()) { if (reason != REASON_MAX || signature_info_.trusted()) {
...@@ -516,9 +521,13 @@ class DownloadProtectionService::CheckClientDownloadRequest ...@@ -516,9 +521,13 @@ class DownloadProtectionService::CheckClientDownloadRequest
} }
} }
if (reason == REASON_MAX && signature_info_.trusted()) { if (reason == REASON_MAX && signature_info_.trusted()) {
// TODO(noelutz): implement a certificate whitelist and only whitelist for (int i = 0; i < signature_info_.certificate_chain_size(); ++i) {
// binaries whose certificate match the whitelist. if (CertificateChainIsWhitelisted(
signature_info_.certificate_chain(i))) {
reason = REASON_TRUSTED_EXECUTABLE; reason = REASON_TRUSTED_EXECUTABLE;
break;
}
}
} }
if (reason != REASON_MAX) { if (reason != REASON_MAX) {
RecordImprovedProtectionStats(reason); RecordImprovedProtectionStats(reason);
...@@ -622,6 +631,46 @@ class DownloadProtectionService::CheckClientDownloadRequest ...@@ -622,6 +631,46 @@ class DownloadProtectionService::CheckClientDownloadRequest
REASON_MAX); REASON_MAX);
} }
bool CertificateChainIsWhitelisted(
const ClientDownloadRequest_CertificateChain& chain) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (chain.element_size() < 2) {
// We need to have both a signing certificate and its issuer certificate
// present to construct a whitelist entry.
return false;
}
scoped_refptr<net::X509Certificate> cert =
net::X509Certificate::CreateFromBytes(
chain.element(0).certificate().data(),
chain.element(0).certificate().size());
if (!cert.get()) {
return false;
}
for (int i = 1; i < chain.element_size(); ++i) {
scoped_refptr<net::X509Certificate> issuer =
net::X509Certificate::CreateFromBytes(
chain.element(i).certificate().data(),
chain.element(i).certificate().size());
if (!issuer.get()) {
return false;
}
std::vector<std::string> whitelist_strings;
DownloadProtectionService::GetCertificateWhitelistStrings(
*cert, *issuer, &whitelist_strings);
for (size_t j = 0; j < whitelist_strings.size(); ++j) {
if (sb_service_->MatchDownloadWhitelistString(whitelist_strings[j])) {
VLOG(2) << "Certificate matched whitelist, cert="
<< cert->subject().GetDisplayName()
<< " issuer=" << issuer->subject().GetDisplayName();
return true;
}
}
cert = issuer;
}
return false;
}
DownloadInfo info_; DownloadInfo info_;
ClientDownloadRequest_SignatureInfo signature_info_; ClientDownloadRequest_SignatureInfo signature_info_;
CheckDownloadCallback callback_; CheckDownloadCallback callback_;
...@@ -712,4 +761,80 @@ void DownloadProtectionService::RequestFinished( ...@@ -712,4 +761,80 @@ void DownloadProtectionService::RequestFinished(
DCHECK(it != download_requests_.end()); DCHECK(it != download_requests_.end());
download_requests_.erase(*it); download_requests_.erase(*it);
} }
namespace {
// Escapes a certificate attribute so that it can be used in a whitelist
// entry. Currently, we only escape slashes, since they are used as a
// separator between attributes.
std::string EscapeCertAttribute(const std::string& attribute) {
std::string escaped;
for (size_t i = 0; i < attribute.size(); ++i) {
if (attribute[i] == '%') {
escaped.append("%25");
} else if (attribute[i] == '/') {
escaped.append("%2F");
} else {
escaped.push_back(attribute[i]);
}
}
return escaped;
}
} // namespace
// static
void DownloadProtectionService::GetCertificateWhitelistStrings(
const net::X509Certificate& certificate,
const net::X509Certificate& issuer,
std::vector<std::string>* whitelist_strings) {
// The whitelist paths are in the format:
// cert/<ascii issuer fingerprint>[/CN=common_name][/O=org][/OU=unit]
//
// Any of CN, O, or OU may be omitted from the whitelist entry, in which
// case they match anything. However, the attributes that do appear will
// always be in the order shown above. At least one attribute will always
// be present.
const net::CertPrincipal& subject = certificate.subject();
std::vector<std::string> ou_tokens;
for (size_t i = 0; i < subject.organization_unit_names.size(); ++i) {
ou_tokens.push_back(
"/OU=" + EscapeCertAttribute(subject.organization_unit_names[i]));
}
std::vector<std::string> o_tokens;
for (size_t i = 0; i < subject.organization_names.size(); ++i) {
o_tokens.push_back(
"/O=" + EscapeCertAttribute(subject.organization_names[i]));
}
std::string cn_token;
if (!subject.common_name.empty()) {
cn_token = "/CN=" + EscapeCertAttribute(subject.common_name);
}
std::set<std::string> paths_to_check;
if (!cn_token.empty()) {
paths_to_check.insert(cn_token);
}
for (size_t i = 0; i < o_tokens.size(); ++i) {
paths_to_check.insert(cn_token + o_tokens[i]);
paths_to_check.insert(o_tokens[i]);
for (size_t j = 0; j < ou_tokens.size(); ++j) {
paths_to_check.insert(cn_token + o_tokens[i] + ou_tokens[j]);
paths_to_check.insert(o_tokens[i] + ou_tokens[j]);
}
}
for (size_t i = 0; i < ou_tokens.size(); ++i) {
paths_to_check.insert(cn_token + ou_tokens[i]);
paths_to_check.insert(ou_tokens[i]);
}
std::string issuer_fp = base::HexEncode(issuer.fingerprint().data,
sizeof(issuer.fingerprint().data));
for (std::set<std::string>::iterator it = paths_to_check.begin();
it != paths_to_check.end(); ++it) {
whitelist_strings->push_back("cert/" + issuer_fp + *it);
}
}
} // namespace safe_browsing } // namespace safe_browsing
...@@ -25,6 +25,7 @@ class SafeBrowsingService; ...@@ -25,6 +25,7 @@ class SafeBrowsingService;
namespace net { namespace net {
class URLRequestContextGetter; class URLRequestContextGetter;
class X509Certificate;
} // namespace net } // namespace net
namespace safe_browsing { namespace safe_browsing {
...@@ -140,7 +141,6 @@ class DownloadProtectionService { ...@@ -140,7 +141,6 @@ class DownloadProtectionService {
CheckClientDownloadFetchFailed); CheckClientDownloadFetchFailed);
FRIEND_TEST_ALL_PREFIXES(DownloadProtectionServiceTest, FRIEND_TEST_ALL_PREFIXES(DownloadProtectionServiceTest,
TestDownloadRequestTimeout); TestDownloadRequestTimeout);
static const char kDownloadRequestUrl[]; static const char kDownloadRequestUrl[];
// Cancels all requests in |download_requests_|, and empties it, releasing // Cancels all requests in |download_requests_|, and empties it, releasing
...@@ -154,6 +154,14 @@ class DownloadProtectionService { ...@@ -154,6 +154,14 @@ class DownloadProtectionService {
static void FillDownloadInfo(const DownloadItem& item, static void FillDownloadInfo(const DownloadItem& item,
DownloadInfo* download_info); DownloadInfo* download_info);
// Given a certificate and its immediate issuer certificate, generates the
// list of strings that need to be checked against the download whitelist to
// determine whether the certificate is whitelisted.
static void GetCertificateWhitelistStrings(
const net::X509Certificate& certificate,
const net::X509Certificate& issuer,
std::vector<std::string>* whitelist_strings);
// This pointer may be NULL if SafeBrowsing is disabled. The // This pointer may be NULL if SafeBrowsing is disabled. The
// SafeBrowsingService owns us, so we don't need to hold a reference to it. // SafeBrowsingService owns us, so we don't need to hold a reference to it.
SafeBrowsingService* sb_service_; SafeBrowsingService* sb_service_;
......
...@@ -7,12 +7,16 @@ ...@@ -7,12 +7,16 @@
#include <map> #include <map>
#include <string> #include <string>
#include "base/base_paths.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/file_path.h" #include "base/file_path.h"
#include "base/file_util.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/message_loop.h" #include "base/message_loop.h"
#include "base/path_service.h"
#include "base/string_number_conversions.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/safe_browsing/signature_util.h" #include "chrome/browser/safe_browsing/signature_util.h"
#include "chrome/common/safe_browsing/csd.pb.h" #include "chrome/common/safe_browsing/csd.pb.h"
...@@ -20,12 +24,15 @@ ...@@ -20,12 +24,15 @@
#include "content/public/common/url_fetcher_delegate.h" #include "content/public/common/url_fetcher_delegate.h"
#include "content/test/test_browser_thread.h" #include "content/test/test_browser_thread.h"
#include "content/test/test_url_fetcher_factory.h" #include "content/test/test_url_fetcher_factory.h"
#include "crypto/rsa_private_key.h"
#include "googleurl/src/gurl.h" #include "googleurl/src/gurl.h"
#include "net/base/x509_certificate.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
using ::testing::ContainerEq; using ::testing::ContainerEq;
using ::testing::DoAll; using ::testing::DoAll;
using ::testing::ElementsAre;
using ::testing::Mock; using ::testing::Mock;
using ::testing::NotNull; using ::testing::NotNull;
using ::testing::Return; using ::testing::Return;
...@@ -42,6 +49,7 @@ class MockSafeBrowsingService : public SafeBrowsingService { ...@@ -42,6 +49,7 @@ class MockSafeBrowsingService : public SafeBrowsingService {
virtual ~MockSafeBrowsingService() {} virtual ~MockSafeBrowsingService() {}
MOCK_METHOD1(MatchDownloadWhitelistUrl, bool(const GURL&)); MOCK_METHOD1(MatchDownloadWhitelistUrl, bool(const GURL&));
MOCK_METHOD1(MatchDownloadWhitelistString, bool(const std::string&));
MOCK_METHOD2(CheckDownloadUrl, bool(const std::vector<GURL>& url_chain, MOCK_METHOD2(CheckDownloadUrl, bool(const std::vector<GURL>& url_chain,
Client* client)); Client* client));
MOCK_METHOD2(CheckDownloadHash, bool(const std::string&, Client* client)); MOCK_METHOD2(CheckDownloadHash, bool(const std::string&, Client* client));
...@@ -66,8 +74,16 @@ ACTION_P(SetCertificateContents, contents) { ...@@ -66,8 +74,16 @@ ACTION_P(SetCertificateContents, contents) {
arg1->add_certificate_chain()->add_element()->set_certificate(contents); arg1->add_certificate_chain()->add_element()->set_certificate(contents);
} }
ACTION(TrustSignature) { ACTION_P(TrustSignature, certificate_file) {
arg1->set_trusted(true); arg1->set_trusted(true);
// Add a certificate chain. Note that we add the certificate twice so that
// it appears as its own issuer.
std::string cert_data;
ASSERT_TRUE(file_util::ReadFileToString(certificate_file, &cert_data));
ClientDownloadRequest_CertificateChain* chain =
arg1->add_certificate_chain();
chain->add_element()->set_certificate(cert_data);
chain->add_element()->set_certificate(cert_data);
} }
// We can't call OnSafeBrowsingResult directly because SafeBrowsingCheck does // We can't call OnSafeBrowsingResult directly because SafeBrowsingCheck does
...@@ -122,6 +138,15 @@ class DownloadProtectionServiceTest : public testing::Test { ...@@ -122,6 +138,15 @@ class DownloadProtectionServiceTest : public testing::Test {
download_service_->signature_util_ = signature_util_; download_service_->signature_util_ = signature_util_;
download_service_->SetEnabled(true); download_service_->SetEnabled(true);
msg_loop_.RunAllPending(); msg_loop_.RunAllPending();
FilePath source_path;
ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &source_path));
testdata_path_ = source_path
.AppendASCII("chrome")
.AppendASCII("test")
.AppendASCII("data")
.AppendASCII("safe_browsing")
.AppendASCII("download_protection");
} }
virtual void TearDown() { virtual void TearDown() {
...@@ -155,6 +180,15 @@ class DownloadProtectionServiceTest : public testing::Test { ...@@ -155,6 +180,15 @@ class DownloadProtectionServiceTest : public testing::Test {
msg_loop_.RunAllPending(); msg_loop_.RunAllPending();
} }
// Proxy for private method.
static void GetCertificateWhitelistStrings(
const net::X509Certificate& certificate,
const net::X509Certificate& issuer,
std::vector<std::string>* whitelist_strings) {
DownloadProtectionService::GetCertificateWhitelistStrings(
certificate, issuer, whitelist_strings);
}
private: private:
// Helper functions for FlushThreadMessageLoops. // Helper functions for FlushThreadMessageLoops.
void RunAllPendingAndQuitUI() { void RunAllPendingAndQuitUI() {
...@@ -212,6 +246,7 @@ class DownloadProtectionServiceTest : public testing::Test { ...@@ -212,6 +246,7 @@ class DownloadProtectionServiceTest : public testing::Test {
scoped_ptr<content::TestBrowserThread> io_thread_; scoped_ptr<content::TestBrowserThread> io_thread_;
scoped_ptr<content::TestBrowserThread> file_thread_; scoped_ptr<content::TestBrowserThread> file_thread_;
scoped_ptr<content::TestBrowserThread> ui_thread_; scoped_ptr<content::TestBrowserThread> ui_thread_;
FilePath testdata_path_;
}; };
TEST_F(DownloadProtectionServiceTest, CheckClientDownloadInvalidUrl) { TEST_F(DownloadProtectionServiceTest, CheckClientDownloadInvalidUrl) {
...@@ -602,7 +637,13 @@ TEST_F(DownloadProtectionServiceTest, CheckClientDownloadDigestList) { ...@@ -602,7 +637,13 @@ TEST_F(DownloadProtectionServiceTest, CheckClientDownloadDigestList) {
EXPECT_CALL(*sb_service_, MatchDownloadWhitelistUrl(_)) EXPECT_CALL(*sb_service_, MatchDownloadWhitelistUrl(_))
.WillRepeatedly(Return(false)); .WillRepeatedly(Return(false));
EXPECT_CALL(*signature_util_, CheckSignature(info.local_file, _)) EXPECT_CALL(*signature_util_, CheckSignature(info.local_file, _))
.WillOnce(TrustSignature()); .WillOnce(TrustSignature(
testdata_path_.AppendASCII("signature_util_test.cer")));
EXPECT_CALL(*sb_service_,
MatchDownloadWhitelistString(
"cert/58AFF702772EB67BDD412571BA40AAC07F0D936C/"
"CN=Joe's-Software-Emporium"))
.WillOnce(Return(true));
EXPECT_CALL(*sb_service_, EXPECT_CALL(*sb_service_,
CheckDownloadHash(info.sha256_hash, NotNull())) CheckDownloadHash(info.sha256_hash, NotNull()))
.WillOnce(DoAll(CheckDownloadHashDone(SafeBrowsingService::SAFE), .WillOnce(DoAll(CheckDownloadHashDone(SafeBrowsingService::SAFE),
...@@ -701,4 +742,119 @@ TEST_F(DownloadProtectionServiceTest, TestDownloadRequestTimeout) { ...@@ -701,4 +742,119 @@ TEST_F(DownloadProtectionServiceTest, TestDownloadRequestTimeout) {
msg_loop_.Run(); msg_loop_.Run();
ExpectResult(DownloadProtectionService::SAFE); ExpectResult(DownloadProtectionService::SAFE);
} }
TEST_F(DownloadProtectionServiceTest,
GetCertificateWhitelistStrings_TestCert) {
std::string cert_data;
ASSERT_TRUE(file_util::ReadFileToString(testdata_path_.AppendASCII(
"signature_util_test.cer"), &cert_data));
scoped_refptr<net::X509Certificate> cert(
net::X509Certificate::CreateFromBytes(cert_data.data(),
cert_data.size()));
ASSERT_TRUE(cert.get());
std::vector<std::string> whitelist_strings;
GetCertificateWhitelistStrings(*cert, *cert, &whitelist_strings);
EXPECT_THAT(whitelist_strings, ElementsAre(
"cert/58AFF702772EB67BDD412571BA40AAC07F0D936C"
"/CN=Joe's-Software-Emporium"));
}
// Only some implementations have the ability to generate self-signed certs.
#if defined(USE_NSS) || defined(OS_WIN) || defined(OS_MACOSX)
TEST_F(DownloadProtectionServiceTest,
GetCertificateWhitelistStrings_SelfSigned) {
scoped_ptr<crypto::RSAPrivateKey> private_key(
crypto::RSAPrivateKey::Create(1024));
// We'll pass this cert in as the "issuer", even though it isn't really
// used to sign the certs below. GetCertificateWhitelistStirngs doesn't care
// about this.
scoped_refptr<net::X509Certificate> issuer_cert =
net::X509Certificate::CreateSelfSigned(
private_key.get(), "CN=issuer", 1, base::TimeDelta::FromDays(1));
ASSERT_TRUE(issuer_cert.get());
std::string cert_base = "cert/" + base::HexEncode(
issuer_cert->fingerprint().data,
sizeof(issuer_cert->fingerprint().data));
scoped_refptr<net::X509Certificate> cert =
net::X509Certificate::CreateSelfSigned(
private_key.get(), "CN=subject/%1", 1, base::TimeDelta::FromDays(1));
ASSERT_TRUE(cert.get());
std::vector<std::string> whitelist_strings;
GetCertificateWhitelistStrings(*cert, *issuer_cert, &whitelist_strings);
// This also tests escaping of characters in the certificate attributes.
EXPECT_THAT(whitelist_strings, ElementsAre(
cert_base + "/CN=subject%2F%251"));
cert = net::X509Certificate::CreateSelfSigned(
private_key.get(), "CN=subject,O=org", 1, base::TimeDelta::FromDays(1));
ASSERT_TRUE(cert.get());
whitelist_strings.clear();
GetCertificateWhitelistStrings(*cert, *issuer_cert, &whitelist_strings);
EXPECT_THAT(whitelist_strings, ElementsAre(
cert_base + "/CN=subject",
cert_base + "/CN=subject/O=org",
cert_base + "/O=org"));
cert = net::X509Certificate::CreateSelfSigned(
private_key.get(), "CN=subject,O=org,OU=unit", 1,
base::TimeDelta::FromDays(1));
ASSERT_TRUE(cert.get());
whitelist_strings.clear();
GetCertificateWhitelistStrings(*cert, *issuer_cert, &whitelist_strings);
EXPECT_THAT(whitelist_strings, ElementsAre(
cert_base + "/CN=subject",
cert_base + "/CN=subject/O=org",
cert_base + "/CN=subject/O=org/OU=unit",
cert_base + "/CN=subject/OU=unit",
cert_base + "/O=org",
cert_base + "/O=org/OU=unit",
cert_base + "/OU=unit"));
cert = net::X509Certificate::CreateSelfSigned(
private_key.get(), "CN=subject,OU=unit", 1,
base::TimeDelta::FromDays(1));
ASSERT_TRUE(cert.get());
whitelist_strings.clear();
GetCertificateWhitelistStrings(*cert, *issuer_cert, &whitelist_strings);
EXPECT_THAT(whitelist_strings, ElementsAre(
cert_base + "/CN=subject",
cert_base + "/CN=subject/OU=unit",
cert_base + "/OU=unit"));
cert = net::X509Certificate::CreateSelfSigned(
private_key.get(), "O=org,", 1, base::TimeDelta::FromDays(1));
ASSERT_TRUE(cert.get());
whitelist_strings.clear();
GetCertificateWhitelistStrings(*cert, *issuer_cert, &whitelist_strings);
EXPECT_THAT(whitelist_strings, ElementsAre(cert_base + "/O=org"));
cert = net::X509Certificate::CreateSelfSigned(
private_key.get(), "O=org,OU=unit", 1, base::TimeDelta::FromDays(1));
ASSERT_TRUE(cert.get());
whitelist_strings.clear();
GetCertificateWhitelistStrings(*cert, *issuer_cert, &whitelist_strings);
EXPECT_THAT(whitelist_strings, ElementsAre(
cert_base + "/O=org",
cert_base + "/O=org/OU=unit",
cert_base + "/OU=unit"));
cert = net::X509Certificate::CreateSelfSigned(
private_key.get(), "OU=unit", 1, base::TimeDelta::FromDays(1));
ASSERT_TRUE(cert.get());
whitelist_strings.clear();
GetCertificateWhitelistStrings(*cert, *issuer_cert, &whitelist_strings);
EXPECT_THAT(whitelist_strings, ElementsAre(cert_base + "/OU=unit"));
cert = net::X509Certificate::CreateSelfSigned(
private_key.get(), "C=US", 1, base::TimeDelta::FromDays(1));
ASSERT_TRUE(cert.get());
whitelist_strings.clear();
GetCertificateWhitelistStrings(*cert, *issuer_cert, &whitelist_strings);
EXPECT_THAT(whitelist_strings, ElementsAre());
}
#endif
} // namespace safe_browsing } // namespace safe_browsing
...@@ -304,6 +304,15 @@ bool SafeBrowsingService::MatchDownloadWhitelistUrl(const GURL& url) { ...@@ -304,6 +304,15 @@ bool SafeBrowsingService::MatchDownloadWhitelistUrl(const GURL& url) {
return database_->ContainsDownloadWhitelistedUrl(url); return database_->ContainsDownloadWhitelistedUrl(url);
} }
bool SafeBrowsingService::MatchDownloadWhitelistString(
const std::string& str) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
return true;
}
return database_->ContainsDownloadWhitelistedString(str);
}
bool SafeBrowsingService::CheckBrowseUrl(const GURL& url, bool SafeBrowsingService::CheckBrowseUrl(const GURL& url,
Client* client) { Client* client) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
......
...@@ -208,6 +208,12 @@ class SafeBrowsingService ...@@ -208,6 +208,12 @@ class SafeBrowsingService
// This method is expected to be called on the IO thread. // This method is expected to be called on the IO thread.
virtual bool MatchDownloadWhitelistUrl(const GURL& url); virtual bool MatchDownloadWhitelistUrl(const GURL& url);
// Check if |str| matches any of the full-length hashes from the download
// whitelist. Returns true if there was a match and false otherwise.
// To make sure we are conservative we will return true if an error occurs.
// This method is expected to be called on the IO thread.
virtual bool MatchDownloadWhitelistString(const std::string& str);
// Called on the IO thread to cancel a pending check if the result is no // Called on the IO thread to cancel a pending check if the result is no
// longer needed. // longer needed.
void CancelCheck(Client* client); void CancelCheck(Client* client);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment