summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorabarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-20 01:37:47 +0000
committerabarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-20 01:37:47 +0000
commite4182160e5cfb36d623ca3f7baef71ea4fd980af (patch)
treec59e127afa23ac826c61c01b6899fb0ac3911c5f /chrome
parent1ccd006ccad33e8d4480435c81d04d0706d63ca7 (diff)
downloadchromium_src-e4182160e5cfb36d623ca3f7baef71ea4fd980af.zip
chromium_src-e4182160e5cfb36d623ca3f7baef71ea4fd980af.tar.gz
chromium_src-e4182160e5cfb36d623ca3f7baef71ea4fd980af.tar.bz2
SSLPolicy fix: Step 9 of 9 (hopefully!).
Change our algorithm for computing the state of our SSL security indicators. Previously, we were computing this state for a single navigation entry. Although this matches other browsers, it fails to take the same-origin policy into account. For example, if one tab is contaminated with insecure content, that insecure content can spread to all the tabs in the same security origin. R=jcampan,wtc BUG=8706 TEST=SSLUITest.TestMixedContentsRandomizeHash,SSLUITest.TestMixedContentsTwoTabs Review URL: http://codereview.chromium.org/42314 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12178 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/renderer_host/resource_request_details.h3
-rwxr-xr-xchrome/browser/ssl/ssl_host_state.cc12
-rwxr-xr-xchrome/browser/ssl/ssl_host_state.h4
-rw-r--r--chrome/browser/ssl/ssl_manager.cc88
-rw-r--r--chrome/browser/ssl/ssl_manager.h20
-rw-r--r--chrome/browser/ssl/ssl_policy.cc207
-rw-r--r--chrome/browser/ssl/ssl_policy.h5
-rw-r--r--chrome/browser/ssl/ssl_uitest.cc102
-rw-r--r--chrome/browser/tab_contents/navigation_controller.cc5
-rw-r--r--chrome/browser/tab_contents/navigation_entry.h8
-rw-r--r--chrome/test/data/ssl/blank_page.html8
-rwxr-xr-xchrome/test/data/ssl/page_with_http_script.html8
-rwxr-xr-xchrome/test/data/ssl/randomize_hash.js2
13 files changed, 270 insertions, 202 deletions
diff --git a/chrome/browser/renderer_host/resource_request_details.h b/chrome/browser/renderer_host/resource_request_details.h
index 8c2b98a..0e0ac17 100644
--- a/chrome/browser/renderer_host/resource_request_details.h
+++ b/chrome/browser/renderer_host/resource_request_details.h
@@ -44,6 +44,7 @@ class ResourceRequestDetails {
resource_type_ = info->resource_type;
frame_origin_ = info->frame_origin;
main_frame_origin_ = info->main_frame_origin;
+ filter_policy_ = info->filter_policy;
}
~ResourceRequestDetails() { }
@@ -61,6 +62,7 @@ class ResourceRequestDetails {
int ssl_cert_id() const { return ssl_cert_id_; }
int ssl_cert_status() const { return ssl_cert_status_; }
ResourceType::Type resource_type() const { return resource_type_; }
+ FilterPolicy::Type filter_policy() const { return filter_policy_; }
private:
GURL url_;
@@ -76,6 +78,7 @@ class ResourceRequestDetails {
int ssl_cert_id_;
int ssl_cert_status_;
ResourceType::Type resource_type_;
+ FilterPolicy::Type filter_policy_;
DISALLOW_COPY_AND_ASSIGN(ResourceRequestDetails);
};
diff --git a/chrome/browser/ssl/ssl_host_state.cc b/chrome/browser/ssl/ssl_host_state.cc
index 5a5b7ae..f8a063b 100755
--- a/chrome/browser/ssl/ssl_host_state.cc
+++ b/chrome/browser/ssl/ssl_host_state.cc
@@ -56,18 +56,6 @@ void SSLHostState::AllowCertForHost(net::X509Certificate* cert,
cert_policy_for_host_[host].Allow(cert);
}
-bool SSLHostState::DidAllowCertForHost(const std::string& host) {
- DCHECK(CalledOnValidThread());
-
- std::map<std::string, net::X509Certificate::Policy>::const_iterator iter =
- cert_policy_for_host_.find(host);
-
- if (iter == cert_policy_for_host_.end())
- return false;
-
- return iter->second.HasAllowedCert();
-}
-
net::X509Certificate::Policy::Judgment SSLHostState::QueryPolicy(
net::X509Certificate* cert, const std::string& host) {
DCHECK(CalledOnValidThread());
diff --git a/chrome/browser/ssl/ssl_host_state.h b/chrome/browser/ssl/ssl_host_state.h
index d8cbeff..f66e9bc 100755
--- a/chrome/browser/ssl/ssl_host_state.h
+++ b/chrome/browser/ssl/ssl_host_state.h
@@ -41,10 +41,6 @@ class SSLHostState : public NonThreadSafe {
// Records that |cert| is not permitted to be used for |host| in the future.
void AllowCertForHost(net::X509Certificate* cert, const std::string& host);
- // Queries whether there is at least one certificate that has been manually
- // allowed for this host.
- bool DidAllowCertForHost(const std::string& host);
-
// Queries whether |cert| is allowed or denied for |host|.
net::X509Certificate::Policy::Judgment QueryPolicy(
net::X509Certificate* cert, const std::string& host);
diff --git a/chrome/browser/ssl/ssl_manager.cc b/chrome/browser/ssl/ssl_manager.cc
index f158104..461979d 100644
--- a/chrome/browser/ssl/ssl_manager.cc
+++ b/chrome/browser/ssl/ssl_manager.cc
@@ -206,14 +206,12 @@ void SSLManager::DenyCertForHost(net::X509Certificate* cert,
const std::string& host) {
// Remember that we don't like this cert for this host.
ssl_host_state_->DenyCertForHost(cert, host);
- DispatchSSLInternalStateChanged();
}
// Delegate API method.
void SSLManager::AllowCertForHost(net::X509Certificate* cert,
const std::string& host) {
ssl_host_state_->AllowCertForHost(cert, host);
- DispatchSSLInternalStateChanged();
}
// Delegate API method.
@@ -225,7 +223,6 @@ net::X509Certificate::Policy::Judgment SSLManager::QueryPolicy(
// Delegate API method.
void SSLManager::AllowMixedContentForHost(const std::string& host) {
ssl_host_state_->AllowMixedContentForHost(host);
- DispatchSSLInternalStateChanged();
}
// Delegate API method.
@@ -506,7 +503,8 @@ bool SSLManager::ShouldStartRequest(ResourceDispatcherHost* rdh,
// to respond synchronously to avoid delaying all network requests...
if (!SSLPolicy::IsMixedContent(request->url(),
info->resource_type,
- info->main_frame_origin))
+ info->filter_policy,
+ info->frame_origin))
return true;
@@ -573,24 +571,18 @@ void SSLManager::DispatchSSLVisibleStateChanged() {
NotificationService::NoDetails());
}
-void SSLManager::InitializeEntryIfNeeded(NavigationEntry* entry) {
- DCHECK(entry);
+void SSLManager::UpdateEntry(NavigationEntry* entry) {
+ // We don't always have a navigation entry to update, for example in the
+ // case of the Web Inspector.
+ if (!entry)
+ return;
- // If the security style of the entry is SECURITY_STYLE_UNKNOWN, then it is a
- // fresh entry and should get the default style.
- if (entry->ssl().security_style() == SECURITY_STYLE_UNKNOWN) {
- entry->ssl().set_security_style(
- delegate()->GetDefaultStyle(entry->url()));
- }
-}
+ NavigationEntry::SSLStatus original_ssl_status = entry->ssl(); // Copy!
-void SSLManager::NavigationStateChanged() {
- NavigationEntry* active_entry = controller_->GetActiveEntry();
- if (!active_entry)
- return; // Nothing showing yet.
+ delegate()->UpdateEntry(this, entry);
- // This might be a new entry we've never seen before.
- InitializeEntryIfNeeded(active_entry);
+ if (!entry->ssl().Equals(original_ssl_status))
+ DispatchSSLVisibleStateChanged();
}
void SSLManager::DidLoadFromMemoryCache(LoadFromMemoryCacheDetails* details) {
@@ -599,12 +591,15 @@ void SSLManager::DidLoadFromMemoryCache(LoadFromMemoryCacheDetails* details) {
// Simulate loading this resource through the usual path.
// Note that we specify SUB_RESOURCE as the resource type as WebCore only
// caches sub-resources.
+ // This resource must have been loaded with FilterPolicy::DONT_FILTER because
+ // filtered resouces aren't cachable.
scoped_refptr<RequestInfo> info = new RequestInfo(
this,
details->url(),
ResourceType::SUB_RESOURCE,
details->frame_origin(),
details->main_frame_origin(),
+ FilterPolicy::DONT_FILTER,
details->ssl_cert_id(),
details->ssl_cert_status());
@@ -622,62 +617,28 @@ void SSLManager::DidCommitProvisionalLoad(
if (details->is_in_page)
return;
- // Decode the security details.
- int ssl_cert_id, ssl_cert_status, ssl_security_bits;
- DeserializeSecurityInfo(details->serialized_security_info,
- &ssl_cert_id, &ssl_cert_status, &ssl_security_bits);
+ NavigationEntry* entry = controller_->GetActiveEntry();
- bool changed = false;
if (details->is_main_frame) {
- // Update the SSL states of the pending entry.
- NavigationEntry* entry = controller_->GetActiveEntry();
if (entry) {
+ // Decode the security details.
+ int ssl_cert_id, ssl_cert_status, ssl_security_bits;
+ DeserializeSecurityInfo(details->serialized_security_info,
+ &ssl_cert_id,
+ &ssl_cert_status,
+ &ssl_security_bits);
+
// We may not have an entry if this is a navigation to an initial blank
// page. Reset the SSL information and add the new data we have.
entry->ssl() = NavigationEntry::SSLStatus();
- InitializeEntryIfNeeded(entry); // For security_style.
entry->ssl().set_cert_id(ssl_cert_id);
entry->ssl().set_cert_status(ssl_cert_status);
entry->ssl().set_security_bits(ssl_security_bits);
- changed = true;
}
-
ShowPendingMessages();
}
- // An HTTPS response may not have a certificate for some reason. When that
- // happens, use the unauthenticated (HTTP) rather than the authentication
- // broken security style so that we can detect this error condition.
- if (net::IsCertStatusError(ssl_cert_status) &&
- !details->is_content_filtered) {
- changed |= SetMaxSecurityStyle(SECURITY_STYLE_AUTHENTICATION_BROKEN);
- if (!details->is_main_frame &&
- !details->entry->ssl().has_unsafe_content()) {
- details->entry->ssl().set_has_unsafe_content();
- changed = true;
- }
- } else if (details->entry->url().SchemeIsSecure() && !ssl_cert_id) {
- if (details->is_main_frame) {
- changed |= SetMaxSecurityStyle(SECURITY_STYLE_UNAUTHENTICATED);
- } else {
- // If the frame has been blocked we keep our security style as
- // authenticated in that case as nothing insecure is actually showing or
- // loaded.
- if (!details->is_content_filtered &&
- !details->entry->ssl().has_mixed_content()) {
- details->entry->ssl().set_has_mixed_content();
- changed = true;
- }
- }
- }
-
- if (changed) {
- // Only send the notification when something actually changed.
- NotificationService::current()->Notify(
- NotificationType::SSL_VISIBLE_STATE_CHANGED,
- Source<NavigationController>(controller_),
- NotificationService::NoDetails());
- }
+ UpdateEntry(entry);
}
void SSLManager::DidFailProvisionalLoadWithError(
@@ -701,6 +662,7 @@ void SSLManager::DidStartResourceResponse(ResourceRequestDetails* details) {
details->resource_type(),
details->frame_origin(),
details->main_frame_origin(),
+ details->filter_policy(),
details->ssl_cert_id(),
details->ssl_cert_status());
@@ -728,7 +690,7 @@ void SSLManager::ShowPendingMessages() {
}
void SSLManager::DidChangeSSLInternalState() {
- // TODO(abarth): We'll need to do something here in the next step.
+ UpdateEntry(controller_->GetActiveEntry());
}
void SSLManager::ClearPendingMessages() {
diff --git a/chrome/browser/ssl/ssl_manager.h b/chrome/browser/ssl/ssl_manager.h
index b15f7e8..b72f1377f 100644
--- a/chrome/browser/ssl/ssl_manager.h
+++ b/chrome/browser/ssl/ssl_manager.h
@@ -270,6 +270,7 @@ class SSLManager : public NotificationObserver {
ResourceType::Type resource_type,
const std::string& frame_origin,
const std::string& main_frame_origin,
+ FilterPolicy::Type filter_policy,
int ssl_cert_id,
int ssl_cert_status)
: manager_(manager),
@@ -277,6 +278,7 @@ class SSLManager : public NotificationObserver {
resource_type_(resource_type),
frame_origin_(frame_origin),
main_frame_origin_(main_frame_origin),
+ filter_policy_(filter_policy),
ssl_cert_id_(ssl_cert_id),
ssl_cert_status_(ssl_cert_status) {
}
@@ -286,6 +288,7 @@ class SSLManager : public NotificationObserver {
ResourceType::Type resource_type() const { return resource_type_; }
const std::string& frame_origin() const { return frame_origin_; }
const std::string& main_frame_origin() const { return main_frame_origin_; }
+ FilterPolicy::Type filter_policy() const { return filter_policy_; }
int ssl_cert_id() const { return ssl_cert_id_; }
int ssl_cert_status() const { return ssl_cert_status_; }
@@ -295,6 +298,7 @@ class SSLManager : public NotificationObserver {
ResourceType::Type resource_type_;
std::string frame_origin_;
std::string main_frame_origin_;
+ FilterPolicy::Type filter_policy_;
int ssl_cert_id_;
int ssl_cert_status_;
@@ -323,8 +327,8 @@ class SSLManager : public NotificationObserver {
// We have started a resource request with the given info.
virtual void OnRequestStarted(RequestInfo* info) = 0;
- // Returns the default security style for a given URL.
- virtual SecurityStyle GetDefaultStyle(const GURL& url) = 0;
+ // Update the SSL information in |entry| to match the current state.
+ virtual void UpdateEntry(SSLManager* manager, NavigationEntry* entry) = 0;
};
static void RegisterUserPrefs(PrefService* prefs);
@@ -441,15 +445,11 @@ class SSLManager : public NotificationObserver {
const NotificationSource& source,
const NotificationDetails& details);
- // Entry point for navigation. This function begins the process of updating
- // the security UI when the main frame navigates.
- //
- // Called on the UI thread.
- void NavigationStateChanged();
-
// Called to determine if there were any processed SSL errors from request.
bool ProcessedSSLErrorFromRequest() const;
+ // The navigation controller associated with this SSLManager. The
+ // NavigationController is guaranteed to outlive the SSLManager.
NavigationController* controller() { return controller_; }
// Convenience methods for serializing/deserializing the security info.
@@ -510,8 +510,8 @@ class SSLManager : public NotificationObserver {
// Dispatch NotificationType::SSL_VISIBLE_STATE_CHANGED notification.
void DispatchSSLVisibleStateChanged();
- // Convenience method for initializing navigation entries.
- void InitializeEntryIfNeeded(NavigationEntry* entry);
+ // Update the NavigationEntry with our current state.
+ void UpdateEntry(NavigationEntry* entry);
// Shows the pending messages (in info-bars) if any.
void ShowPendingMessages();
diff --git a/chrome/browser/ssl/ssl_policy.cc b/chrome/browser/ssl/ssl_policy.cc
index ed9678b..9e796fa 100644
--- a/chrome/browser/ssl/ssl_policy.cc
+++ b/chrome/browser/ssl/ssl_policy.cc
@@ -38,6 +38,44 @@
// Wrap all these helper classes in an anonymous namespace.
namespace {
+static void MarkOriginAsBroken(SSLManager* manager, const std::string& origin) {
+ GURL parsed_origin(origin);
+ if (!parsed_origin.SchemeIsSecure())
+ return;
+
+ manager->MarkHostAsBroken(parsed_origin.host());
+}
+
+static void AllowMixedContentForOrigin(SSLManager* manager,
+ const std::string& origin) {
+ GURL parsed_origin(origin);
+ if (!parsed_origin.SchemeIsSecure())
+ return;
+
+ manager->AllowMixedContentForHost(parsed_origin.host());
+}
+
+static void UpdateStateForMixedContent(SSLManager::RequestInfo* info) {
+ if (info->resource_type() != ResourceType::MAIN_FRAME ||
+ info->resource_type() != ResourceType::SUB_FRAME) {
+ // The frame's origin now contains mixed content and therefore is broken.
+ MarkOriginAsBroken(info->manager(), info->frame_origin());
+ }
+
+ if (info->resource_type() != ResourceType::MAIN_FRAME) {
+ // The main frame now contains a frame with mixed content. Therefore, we
+ // mark the main frame's origin as broken too.
+ MarkOriginAsBroken(info->manager(), info->main_frame_origin());
+ }
+}
+
+static void UpdateStateForUnsafeContent(SSLManager::RequestInfo* info) {
+ // This request as a broken cert, which means its host is broken.
+ info->manager()->MarkHostAsBroken(info->url().host());
+
+ UpdateStateForMixedContent(info);
+}
+
class ShowMixedContentTask : public Task {
public:
ShowMixedContentTask(SSLManager::MixedContentHandler* handler);
@@ -60,10 +98,9 @@ ShowMixedContentTask::~ShowMixedContentTask() {
}
void ShowMixedContentTask::Run() {
- handler_->manager()->AllowMixedContentForHost(
- GURL(handler_->main_frame_origin()).host());
-
- // Reload the page.
+ AllowMixedContentForOrigin(handler_->manager(), handler_->frame_origin());
+ AllowMixedContentForOrigin(handler_->manager(),
+ handler_->main_frame_origin());
handler_->manager()->controller()->Reload(true);
}
@@ -112,6 +149,23 @@ static void ShowBlockingPage(SSLPolicy* policy, SSLManager::CertError* error) {
blocking_page->Show();
}
+static void InitializeEntryIfNeeded(NavigationEntry* entry) {
+ if (entry->ssl().security_style() != SECURITY_STYLE_UNKNOWN)
+ return;
+
+ entry->ssl().set_security_style(entry->url().SchemeIsSecure() ?
+ SECURITY_STYLE_AUTHENTICATED : SECURITY_STYLE_UNAUTHENTICATED);
+}
+
+static void AddMixedContentWarningToConsole(
+ SSLManager::MixedContentHandler* handler) {
+ const std::wstring& msg = l10n_util::GetStringF(
+ IDS_MIXED_CONTENT_LOG_MESSAGE,
+ UTF8ToWide(handler->frame_origin()),
+ UTF8ToWide(handler->request_url().spec()));
+ handler->manager()->AddMessageToConsole(msg, MESSAGE_LEVEL_WARNING);
+}
+
} // namespace
SSLPolicy::SSLPolicy() {
@@ -128,15 +182,6 @@ void SSLPolicy::OnCertError(SSLManager::CertError* error) {
error->request_url().host());
if (judgment == net::X509Certificate::Policy::ALLOWED) {
- // We've been told to allow this certificate.
- if (error->manager()->SetMaxSecurityStyle(
- SECURITY_STYLE_AUTHENTICATION_BROKEN)) {
- NotificationService::current()->Notify(
- NotificationType::SSL_VISIBLE_STATE_CHANGED,
- Source<NavigationController>(error->manager()->controller()),
- Details<NavigationEntry>(
- error->manager()->controller()->GetActiveEntry()));
- }
error->ContinueRequest();
return;
}
@@ -179,9 +224,10 @@ void SSLPolicy::OnMixedContent(SSLManager::MixedContentHandler* handler) {
FilterPolicy::Type filter_policy =
FilterPolicy::FromInt(prefs->GetInteger(prefs::kMixedContentFiltering));
- // If the user have added an exception, doctor the |filter_policy|.
- if (handler->manager()->DidAllowMixedContentForHost(
- GURL(handler->main_frame_origin()).host()))
+ // If the user has added an exception, doctor the |filter_policy|.
+ std::string host = GURL(handler->main_frame_origin()).host();
+ if (handler->manager()->DidAllowMixedContentForHost(host) ||
+ handler->manager()->DidMarkHostAsBroken(host))
filter_policy = FilterPolicy::DONT_FILTER;
if (filter_policy != FilterPolicy::DONT_FILTER) {
@@ -190,108 +236,52 @@ void SSLPolicy::OnMixedContent(SSLManager::MixedContentHandler* handler) {
l10n_util::GetString(IDS_SSL_INFO_BAR_SHOW_CONTENT),
new ShowMixedContentTask(handler));
}
- handler->StartRequest(filter_policy);
- NavigationEntry* entry =
- handler->manager()->controller()->GetLastCommittedEntry();
- // We might not have a navigation entry in some cases (e.g. when a
- // HTTPS page opens a popup with no URL and then populate it with
- // document.write()). See bug http://crbug.com/3845.
- if (!entry)
- return;
+ handler->StartRequest(filter_policy);
+ AddMixedContentWarningToConsole(handler);
+}
- // Even though we are loading the mixed-content resource, it will not be
- // included in the page when we set the policy to FILTER_ALL or
- // FILTER_ALL_EXCEPT_IMAGES (only images and they are stamped with warning
- // icons), so we don't set the mixed-content mode in these cases.
- if (filter_policy == FilterPolicy::DONT_FILTER)
- entry->ssl().set_has_mixed_content();
+void SSLPolicy::OnRequestStarted(SSLManager::RequestInfo* info) {
+ if (net::IsCertStatusError(info->ssl_cert_status()))
+ UpdateStateForUnsafeContent(info);
+
+ if (IsMixedContent(info->url(),
+ info->resource_type(),
+ info->filter_policy(),
+ info->frame_origin()))
+ UpdateStateForMixedContent(info);
+}
- // Print a message indicating the mixed-contents resource in the console.
- const std::wstring& msg = l10n_util::GetStringF(
- IDS_MIXED_CONTENT_LOG_MESSAGE,
- UTF8ToWide(entry->url().spec()),
- UTF8ToWide(handler->request_url().spec()));
- handler->manager()->AddMessageToConsole(msg, MESSAGE_LEVEL_WARNING);
+void SSLPolicy::UpdateEntry(SSLManager* manager, NavigationEntry* entry) {
+ DCHECK(entry);
- NotificationService::current()->Notify(
- NotificationType::SSL_VISIBLE_STATE_CHANGED,
- Source<NavigationController>(handler->manager()->controller()),
- Details<NavigationEntry>(entry));
-}
+ InitializeEntryIfNeeded(entry);
-void SSLPolicy::OnRequestStarted(SSLManager::RequestInfo* info) {
- // These schemes never leave the browser and don't require a warning.
- if (info->url().SchemeIs(chrome::kDataScheme) ||
- info->url().SchemeIs(chrome::kJavaScriptScheme) ||
- info->url().SchemeIs(chrome::kAboutScheme))
+ if (!entry->url().SchemeIsSecure())
return;
- NavigationEntry* entry = info->manager()->controller()->GetActiveEntry();
- if (!entry) {
- // We may not have an entry for cases such as the inspector.
+ // An HTTPS response may not have a certificate for some reason. When that
+ // happens, use the unauthenticated (HTTP) rather than the authentication
+ // broken security style so that we can detect this error condition.
+ if (!entry->ssl().cert_id()) {
+ entry->ssl().set_security_style(SECURITY_STYLE_UNAUTHENTICATED);
return;
}
- NavigationEntry::SSLStatus& ssl = entry->ssl();
- bool changed = false;
- if (!entry->url().SchemeIsSecure() || // Current page is not secure.
- info->resource_type() == ResourceType::MAIN_FRAME || // Main frame load.
- net::IsCertStatusError(ssl.cert_status())) { // There is already
- // an error for the main page, don't report sub-resources as unsafe
- // content.
- // No mixed/unsafe content check necessary.
+ if (net::IsCertStatusError(entry->ssl().cert_status())) {
+ entry->ssl().set_security_style(SECURITY_STYLE_AUTHENTICATION_BROKEN);
return;
}
- if (info->url().SchemeIsSecure()) {
- // Check for insecure content (anything served over intranet is considered
- // insecure).
-
- // TODO(jcampan): bug #1178228 Disabling the broken style for intranet
- // hosts for beta as it is missing error strings (and cert status).
- // if (IsIntranetHost(url.host()) ||
- // net::IsCertStatusError(info->ssl_cert_status())) {
- if (net::IsCertStatusError(info->ssl_cert_status())) {
- // The resource is unsafe.
- if (!ssl.has_unsafe_content()) {
- changed = true;
- ssl.set_has_unsafe_content();
- info->manager()->SetMaxSecurityStyle(
- SECURITY_STYLE_AUTHENTICATION_BROKEN);
- }
- }
- }
-
- if (changed) {
- // Only send the notification when something actually changed.
- NotificationService::current()->Notify(
- NotificationType::SSL_VISIBLE_STATE_CHANGED,
- Source<NavigationController>(info->manager()->controller()),
- NotificationService::NoDetails());
- }
-}
-
-SecurityStyle SSLPolicy::GetDefaultStyle(const GURL& url) {
- // Show the secure style for HTTPS.
- if (url.SchemeIsSecure()) {
- // TODO(jcampan): bug #1178228 Disabling the broken style for intranet
- // hosts for beta as it is missing error strings (and cert status).
- // CAs issue certs for intranet hosts to anyone.
- // if (IsIntranetHost(url.host()))
- // return SECURITY_STYLE_AUTHENTICATION_BROKEN;
-
- return SECURITY_STYLE_AUTHENTICATED;
- }
-
- // Otherwise, show the unauthenticated style.
- return SECURITY_STYLE_UNAUTHENTICATED;
+ if (manager->DidMarkHostAsBroken(entry->url().host()))
+ entry->ssl().set_has_mixed_content();
}
// static
bool SSLPolicy::IsMixedContent(const GURL& url,
ResourceType::Type resource_type,
- const std::string& main_frame_origin) {
+ FilterPolicy::Type filter_policy,
+ const std::string& frame_origin) {
////////////////////////////////////////////////////////////////////////////
// WARNING: This function is called from both the IO and UI threads. Do //
// not touch any non-thread-safe objects! You have been warned. //
@@ -301,9 +291,20 @@ bool SSLPolicy::IsMixedContent(const GURL& url,
if (resource_type == ResourceType::MAIN_FRAME)
return false;
- // TODO(abarth): This is wrong, but it matches our current behavior.
- // I'll fix this in a subsequent step.
- return GURL(main_frame_origin).SchemeIsSecure() && !url.SchemeIsSecure();
+ // If we've filtered the resource, then it's no longer dangerous.
+ if (filter_policy != FilterPolicy::DONT_FILTER)
+ return false;
+
+ // If the frame doing the loading is already insecure, then we must have
+ // already dealt with whatever mixed content might be going on.
+ if (!GURL(frame_origin).SchemeIsSecure())
+ return false;
+
+ // We aren't worried about mixed content if we're loading an HTTPS URL.
+ if (url.SchemeIsSecure())
+ return false;
+
+ return true;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ssl/ssl_policy.h b/chrome/browser/ssl/ssl_policy.h
index 0a017eb..51a3a3a 100644
--- a/chrome/browser/ssl/ssl_policy.h
+++ b/chrome/browser/ssl/ssl_policy.h
@@ -25,13 +25,14 @@ class SSLPolicy : public SSLManager::Delegate,
virtual void OnCertError(SSLManager::CertError* error);
virtual void OnMixedContent(SSLManager::MixedContentHandler* handler);
virtual void OnRequestStarted(SSLManager::RequestInfo* info);
- virtual SecurityStyle GetDefaultStyle(const GURL& url);
+ virtual void UpdateEntry(SSLManager* manager, NavigationEntry* entry);
// This method is static because it is called from both the UI and the IO
// threads.
static bool IsMixedContent(const GURL& url,
ResourceType::Type resource_type,
- const std::string& main_frame_origin);
+ FilterPolicy::Type filter_policy,
+ const std::string& frame_origin);
// SSLBlockingPage::Delegate methods.
virtual SSLErrorInfo GetSSLErrorInfo(SSLManager::CertError* error);
diff --git a/chrome/browser/ssl/ssl_uitest.cc b/chrome/browser/ssl/ssl_uitest.cc
index 7ba3b61..5275b92 100644
--- a/chrome/browser/ssl/ssl_uitest.cc
+++ b/chrome/browser/ssl/ssl_uitest.cc
@@ -242,13 +242,29 @@ TEST_F(SSLUITest, TestMixedContents) {
EXPECT_EQ(0,
cert_status & net::CERT_STATUS_ALL_ERRORS); // No errors expected.
EXPECT_EQ(NavigationEntry::SSLStatus::MIXED_CONTENT, mixed_content_state);
+}
+
+// Visits a page with mixed content.
+TEST_F(SSLUITest, TestMixedContentsFilterAll) {
+ scoped_refptr<HTTPSTestServer> https_server = GoodCertServer();
+ scoped_refptr<HTTPTestServer> http_server = PlainServer();
// Now select the block mixed-content pref and reload the page.
scoped_ptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0));
EXPECT_TRUE(browser_proxy.get());
EXPECT_TRUE(browser_proxy->SetIntPreference(prefs::kMixedContentFiltering,
FilterPolicy::FILTER_ALL));
- EXPECT_TRUE(tab->Reload());
+
+ // Load a page with mixed-content, we've overridden our filtering policy so
+ // we won't load the mixed content by default.
+ scoped_ptr<TabProxy> tab(GetActiveTabProxy());
+ NavigateTab(
+ tab.get(),
+ https_server->TestServerPageW(
+ L"files/ssl/page_with_mixed_contents.html"));
+ NavigationEntry::PageType page_type;
+ EXPECT_TRUE(tab->GetPageType(&page_type));
+ EXPECT_EQ(NavigationEntry::NORMAL_PAGE, page_type);
// The image should be filtered.
int img_width;
@@ -260,6 +276,9 @@ TEST_F(SSLUITest, TestMixedContents) {
// image is less than 100.
EXPECT_GT(100, img_width);
+ SecurityStyle security_style;
+ int cert_status;
+ int mixed_content_state;
// The state should be OK since we are not showing the resource.
EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status,
&mixed_content_state));
@@ -289,6 +308,32 @@ TEST_F(SSLUITest, TestMixedContents) {
EXPECT_EQ(NavigationEntry::SSLStatus::MIXED_CONTENT, mixed_content_state);
}
+// Visits a page with an http script that tries to suppress our mixed content
+// warnings by randomize location.hash.
+// Based on http://crbug.com/8706
+TEST_F(SSLUITest, TestMixedContentsRandomizeHash) {
+ scoped_refptr<HTTPSTestServer> https_server = GoodCertServer();
+ scoped_refptr<HTTPTestServer> http_server = PlainServer();
+
+ scoped_ptr<TabProxy> tab(GetActiveTabProxy());
+ NavigateTab(
+ tab.get(),
+ https_server->TestServerPageW(
+ L"files/ssl/page_with_http_script.html"));
+ NavigationEntry::PageType page_type;
+ EXPECT_TRUE(tab->GetPageType(&page_type));
+ EXPECT_EQ(NavigationEntry::NORMAL_PAGE, page_type);
+
+ SecurityStyle security_style;
+ int cert_status;
+ int mixed_content_state;
+ EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status,
+ &mixed_content_state));
+ EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, security_style);
+ EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS);
+ EXPECT_EQ(NavigationEntry::SSLStatus::MIXED_CONTENT, mixed_content_state);
+}
+
// Visits a page with unsafe content and make sure that:
// - frames content is replaced with warning
// - images and scripts are filtered out entirely
@@ -378,6 +423,57 @@ TEST_F(SSLUITest, TestMixedContentsLoadedFromJS) {
EXPECT_EQ(NavigationEntry::SSLStatus::MIXED_CONTENT, mixed_content_state);
}
+// Visits two pages from the same origin: one with mixed content and one
+// without. The test checks that we propagate the mixed content state from one
+// to the other.
+TEST_F(SSLUITest, TestMixedContentsTwoTabs) {
+ scoped_refptr<HTTPSTestServer> https_server = GoodCertServer();
+ scoped_refptr<HTTPTestServer> http_server = PlainServer();
+
+ scoped_ptr<TabProxy> tab1(GetActiveTabProxy());
+ NavigateTab(
+ tab1.get(),
+ https_server->TestServerPageW(
+ L"files/ssl/blank_page.html"));
+ NavigationEntry::PageType page_type;
+ EXPECT_TRUE(tab1->GetPageType(&page_type));
+ EXPECT_EQ(NavigationEntry::NORMAL_PAGE, page_type);
+
+ // This tab should be fine.
+ SecurityStyle security_style;
+ int cert_status;
+ int mixed_content_state;
+ EXPECT_TRUE(tab1->GetSecurityState(&security_style, &cert_status,
+ &mixed_content_state));
+ EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, security_style);
+ EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS);
+ EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state);
+
+ scoped_ptr<BrowserProxy> browser_proxy(automation()->GetBrowserWindow(0));
+ EXPECT_TRUE(browser_proxy.get());
+ EXPECT_TRUE(browser_proxy->AppendTab(
+ https_server->TestServerPageW(L"files/ssl/page_with_http_script.html")));
+
+ scoped_ptr<TabProxy> tab2(GetActiveTabProxy());
+ EXPECT_TRUE(tab2->GetPageType(&page_type));
+ EXPECT_EQ(NavigationEntry::NORMAL_PAGE, page_type);
+
+ // The new tab has mixed content.
+ EXPECT_TRUE(tab2->GetSecurityState(&security_style, &cert_status,
+ &mixed_content_state));
+ EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, security_style);
+ EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS);
+ EXPECT_EQ(NavigationEntry::SSLStatus::MIXED_CONTENT, mixed_content_state);
+
+ // Which means the origin for the first tab has also been contaminated with
+ // mixed content.
+ EXPECT_TRUE(tab1->GetSecurityState(&security_style, &cert_status,
+ &mixed_content_state));
+ EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, security_style);
+ EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS);
+ EXPECT_EQ(NavigationEntry::SSLStatus::MIXED_CONTENT, mixed_content_state);
+}
+
// Visits a page with an image over http. Visits another page over https
// referencing that same image over http (hoping it is coming from the webcore
// memory cache).
@@ -803,13 +899,13 @@ TEST_F(SSLUITest, TestGoodFrameNavigation) {
EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS);
EXPECT_EQ(NavigationEntry::SSLStatus::MIXED_CONTENT, mixed_content_state);
- // Go back, our state should be back to OK.
+ // Go back, our state should be unchanged.
EXPECT_TRUE(tab->GoBack());
EXPECT_TRUE(tab->GetSecurityState(&security_style, &cert_status,
&mixed_content_state));
EXPECT_EQ(SECURITY_STYLE_AUTHENTICATED, security_style);
EXPECT_EQ(0, cert_status & net::CERT_STATUS_ALL_ERRORS);
- EXPECT_EQ(NavigationEntry::SSLStatus::NORMAL_CONTENT, mixed_content_state);
+ EXPECT_EQ(NavigationEntry::SSLStatus::MIXED_CONTENT, mixed_content_state);
}
// From a bad HTTPS top frame:
diff --git a/chrome/browser/tab_contents/navigation_controller.cc b/chrome/browser/tab_contents/navigation_controller.cc
index 38dafb6d..3dbdef8 100644
--- a/chrome/browser/tab_contents/navigation_controller.cc
+++ b/chrome/browser/tab_contents/navigation_controller.cc
@@ -1011,10 +1011,6 @@ void NavigationController::NavigateToPendingEntry(bool reload) {
pending_entry_ = entries_[pending_entry_index_].get();
}
- // Reset the security states as any SSL error may have been resolved since we
- // last visited that page.
- pending_entry_->ssl() = NavigationEntry::SSLStatus();
-
if (from_contents && from_contents->type() != pending_entry_->tab_type())
from_contents->set_is_active(false);
@@ -1036,7 +1032,6 @@ void NavigationController::NotifyNavigationEntryCommitted(
// TODO(pkasting): http://b/1113079 Probably these explicit notification paths
// should be removed, and interested parties should just listen for the
// notification below instead.
- ssl_manager_.NavigationStateChanged();
active_contents_->NotifyNavigationStateChanged(
TabContents::INVALIDATE_EVERYTHING);
diff --git a/chrome/browser/tab_contents/navigation_entry.h b/chrome/browser/tab_contents/navigation_entry.h
index 48e1750..16801b3 100644
--- a/chrome/browser/tab_contents/navigation_entry.h
+++ b/chrome/browser/tab_contents/navigation_entry.h
@@ -45,6 +45,14 @@ class NavigationEntry {
SSLStatus();
+ bool Equals(const SSLStatus& status) const {
+ return security_style_ == status.security_style_ &&
+ cert_id_ == status.cert_id_ &&
+ cert_status_ == status.cert_status_ &&
+ security_bits_ == status.security_bits_ &&
+ content_status_ == status.content_status_;
+ }
+
void set_security_style(SecurityStyle security_style) {
security_style_ = security_style;
}
diff --git a/chrome/test/data/ssl/blank_page.html b/chrome/test/data/ssl/blank_page.html
new file mode 100644
index 0000000..68b761a
--- /dev/null
+++ b/chrome/test/data/ssl/blank_page.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>I am a blank page.</title>
+</head>
+<body>
+Nothing to see here.
+</body>
+</html>
diff --git a/chrome/test/data/ssl/page_with_http_script.html b/chrome/test/data/ssl/page_with_http_script.html
new file mode 100755
index 0000000..d0719c4
--- /dev/null
+++ b/chrome/test/data/ssl/page_with_http_script.html
@@ -0,0 +1,8 @@
+<html>
+<head><title>Page with http script</title></head>
+<body>
+This page contains an script which is served over an http connection,
+causing mixed contents (when this page is loaded over https).<br>
+<script src="http://localhost:1337/files/ssl/randomize_hash.js"></script>
+</body>
+</html>
diff --git a/chrome/test/data/ssl/randomize_hash.js b/chrome/test/data/ssl/randomize_hash.js
new file mode 100755
index 0000000..46c2082
--- /dev/null
+++ b/chrome/test/data/ssl/randomize_hash.js
@@ -0,0 +1,2 @@
+document.body.innerHTML = "I'm content from an HTTP script."
+location.hash = Math.random();